• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/desktop_capture/mac/full_screen_mac_application_handler.h"
12 #include <libproc.h>
13 #include <algorithm>
14 #include <functional>
15 #include <string>
16 #include "absl/strings/match.h"
17 #include "modules/desktop_capture/mac/window_list_utils.h"
18 
19 namespace webrtc {
20 namespace {
21 
22 static constexpr const char* kPowerPointSlideShowTitles[] = {
23     u8"PowerPoint-Bildschirmpräsentation",
24     u8"Προβολή παρουσίασης PowerPoint",
25     u8"PowerPoint スライド ショー",
26     u8"PowerPoint Slide Show",
27     u8"PowerPoint 幻灯片放映",
28     u8"Presentación de PowerPoint",
29     u8"PowerPoint-slideshow",
30     u8"Presentazione di PowerPoint",
31     u8"Prezentácia programu PowerPoint",
32     u8"Apresentação do PowerPoint",
33     u8"PowerPoint-bildspel",
34     u8"Prezentace v aplikaci PowerPoint",
35     u8"PowerPoint 슬라이드 쇼",
36     u8"PowerPoint-lysbildefremvisning",
37     u8"PowerPoint-vetítés",
38     u8"PowerPoint Slayt Gösterisi",
39     u8"Pokaz slajdów programu PowerPoint",
40     u8"PowerPoint 投影片放映",
41     u8"Демонстрация PowerPoint",
42     u8"Diaporama PowerPoint",
43     u8"PowerPoint-diaesitys",
44     u8"Peragaan Slide PowerPoint",
45     u8"PowerPoint-diavoorstelling",
46     u8"การนำเสนอสไลด์ PowerPoint",
47     u8"Apresentação de slides do PowerPoint",
48     u8"הצגת שקופיות של PowerPoint",
49     u8"عرض شرائح في PowerPoint"};
50 
51 class FullScreenMacApplicationHandler : public FullScreenApplicationHandler {
52  public:
53   using TitlePredicate =
54       std::function<bool(const std::string&, const std::string&)>;
55 
FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId,TitlePredicate title_predicate)56   FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId,
57                                   TitlePredicate title_predicate)
58       : FullScreenApplicationHandler(sourceId),
59         title_predicate_(title_predicate),
60         owner_pid_(GetWindowOwnerPid(sourceId)) {}
61 
InvalidateCacheIfNeeded(const DesktopCapturer::SourceList & source_list,int64_t timestamp) const62   void InvalidateCacheIfNeeded(const DesktopCapturer::SourceList& source_list,
63                                int64_t timestamp) const {
64     // Copy only sources with the same pid
65     if (timestamp != cache_timestamp_) {
66       cache_sources_.clear();
67       std::copy_if(source_list.begin(), source_list.end(),
68                    std::back_inserter(cache_sources_),
69                    [&](const DesktopCapturer::Source& src) {
70                      return src.id != GetSourceId() &&
71                             GetWindowOwnerPid(src.id) == owner_pid_;
72                    });
73       cache_timestamp_ = timestamp;
74     }
75   }
76 
FindFullScreenWindowWithSamePid(const DesktopCapturer::SourceList & source_list,int64_t timestamp) const77   WindowId FindFullScreenWindowWithSamePid(
78       const DesktopCapturer::SourceList& source_list,
79       int64_t timestamp) const {
80     InvalidateCacheIfNeeded(source_list, timestamp);
81     if (cache_sources_.empty())
82       return kCGNullWindowID;
83 
84     const auto original_window = GetSourceId();
85     const std::string title = GetWindowTitle(original_window);
86 
87     // We can ignore any windows with empty titles cause regardless type of
88     // application it's impossible to verify that full screen window and
89     // original window are related to the same document.
90     if (title.empty())
91       return kCGNullWindowID;
92 
93     MacDesktopConfiguration desktop_config =
94         MacDesktopConfiguration::GetCurrent(
95             MacDesktopConfiguration::TopLeftOrigin);
96 
97     const auto it = std::find_if(
98         cache_sources_.begin(), cache_sources_.end(),
99         [&](const DesktopCapturer::Source& src) {
100           const std::string window_title = GetWindowTitle(src.id);
101 
102           if (window_title.empty())
103             return false;
104 
105           if (title_predicate_ && !title_predicate_(title, window_title))
106             return false;
107 
108           return IsWindowFullScreen(desktop_config, src.id);
109         });
110 
111     return it != cache_sources_.end() ? it->id : 0;
112   }
113 
FindFullScreenWindow(const DesktopCapturer::SourceList & source_list,int64_t timestamp) const114   DesktopCapturer::SourceId FindFullScreenWindow(
115       const DesktopCapturer::SourceList& source_list,
116       int64_t timestamp) const override {
117     return IsWindowOnScreen(GetSourceId())
118                ? 0
119                : FindFullScreenWindowWithSamePid(source_list, timestamp);
120   }
121 
122  private:
123   const TitlePredicate title_predicate_;
124   const int owner_pid_;
125   mutable int64_t cache_timestamp_ = 0;
126   mutable DesktopCapturer::SourceList cache_sources_;
127 };
128 
equal_title_predicate(const std::string & original_title,const std::string & title)129 bool equal_title_predicate(const std::string& original_title,
130                            const std::string& title) {
131   return original_title == title;
132 }
133 
slide_show_title_predicate(const std::string & original_title,const std::string & title)134 bool slide_show_title_predicate(const std::string& original_title,
135                                 const std::string& title) {
136   if (title.find(original_title) == std::string::npos)
137     return false;
138 
139   for (const char* pp_slide_title : kPowerPointSlideShowTitles) {
140     if (absl::StartsWith(title, pp_slide_title))
141       return true;
142   }
143   return false;
144 }
145 
146 }  // namespace
147 
148 std::unique_ptr<FullScreenApplicationHandler>
CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId)149 CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId) {
150   std::unique_ptr<FullScreenApplicationHandler> result;
151   int pid = GetWindowOwnerPid(sourceId);
152   char buffer[PROC_PIDPATHINFO_MAXSIZE];
153   int path_length = proc_pidpath(pid, buffer, sizeof(buffer));
154   if (path_length > 0) {
155     const char* last_slash = strrchr(buffer, '/');
156     const std::string name{last_slash ? last_slash + 1 : buffer};
157     FullScreenMacApplicationHandler::TitlePredicate predicate = nullptr;
158     if (name.find("Google Chrome") == 0 || name == "Chromium") {
159       predicate = equal_title_predicate;
160     } else if (name == "Microsoft PowerPoint") {
161       predicate = slide_show_title_predicate;
162     } else if (name == "Keynote") {
163       predicate = equal_title_predicate;
164     }
165 
166     if (predicate) {
167       result.reset(new FullScreenMacApplicationHandler(sourceId, predicate));
168     }
169   }
170 
171   return result;
172 }
173 
174 }  // namespace webrtc
175