Improve application window picker on Mac that was not listing all apps.
All application with empty title were not listed, for example Photos. Fallback to owner name in that case while making sure to keep ignoring the ghost window. Most of the ghost windows can be filtered with IsWindowOnScreen or IsWindowFullScreen except a few. For the remaining ghost we check if there is no other window with the same pid. Bug: chromium:516230 Test: Hangouts or Rumpus Change-Id: Ibb9f98887e5aedf822fc0611836b1938b5056d43 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/130360 Commit-Queue: Julien Isorce <julien.isorce@chromium.org> Reviewed-by: Brave Yao <braveyao@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27401}
This commit is contained in:

committed by
Commit Bot

parent
32a5781fa9
commit
98e9f29ff0
@ -24,55 +24,13 @@ namespace {
|
||||
|
||||
const int64_t kUpdateIntervalMs = 500;
|
||||
|
||||
std::string GetWindowTitle(CGWindowID id) {
|
||||
CFArrayRef window_id_array =
|
||||
CFArrayCreate(NULL, reinterpret_cast<const void**>(&id), 1, NULL);
|
||||
CFArrayRef window_array =
|
||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||
std::string title;
|
||||
|
||||
if (window_array && CFArrayGetCount(window_array)) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
|
||||
CFArrayGetValueAtIndex(window_array, 0));
|
||||
CFStringRef title_ref = reinterpret_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowName));
|
||||
|
||||
if (title_ref)
|
||||
rtc::ToUtf8(title_ref, &title);
|
||||
}
|
||||
CFRelease(window_id_array);
|
||||
CFRelease(window_array);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
int GetWindowOwnerPid(CGWindowID id) {
|
||||
CFArrayRef window_id_array =
|
||||
CFArrayCreate(NULL, reinterpret_cast<const void**>(&id), 1, NULL);
|
||||
CFArrayRef window_array =
|
||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||
int pid = 0;
|
||||
|
||||
if (window_array && CFArrayGetCount(window_array)) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
|
||||
CFArrayGetValueAtIndex(window_array, 0));
|
||||
CFNumberRef pid_ref = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowOwnerPID));
|
||||
|
||||
if (pid_ref)
|
||||
CFNumberGetValue(pid_ref, kCFNumberIntType, &pid);
|
||||
}
|
||||
CFRelease(window_id_array);
|
||||
CFRelease(window_array);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Returns the window that is full-screen and has the same title and owner pid
|
||||
// as the input window.
|
||||
CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) {
|
||||
int pid = GetWindowOwnerPid(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(
|
||||
@ -92,29 +50,18 @@ CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) {
|
||||
for (CFIndex i = 0; i < count; ++i) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
|
||||
CFArrayGetValueAtIndex(window_array, i));
|
||||
CFStringRef window_title_ref = reinterpret_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowName));
|
||||
CFNumberRef window_id_ref = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowNumber));
|
||||
CFNumberRef window_pid_ref = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowOwnerPID));
|
||||
|
||||
if (!window_title_ref || !window_id_ref || !window_pid_ref)
|
||||
CGWindowID window_id = GetWindowId(window);
|
||||
if (window_id == kNullWindowId)
|
||||
continue;
|
||||
|
||||
int window_pid = 0;
|
||||
CFNumberGetValue(window_pid_ref, kCFNumberIntType, &window_pid);
|
||||
if (window_pid != pid)
|
||||
if (GetWindowOwnerPid(window) != pid)
|
||||
continue;
|
||||
|
||||
std::string window_title;
|
||||
if (!rtc::ToUtf8(window_title_ref, &window_title) ||
|
||||
window_title != title) {
|
||||
std::string window_title = GetWindowTitle(window);
|
||||
if (window_title != title)
|
||||
continue;
|
||||
}
|
||||
|
||||
CGWindowID window_id;
|
||||
CFNumberGetValue(window_id_ref, kCFNumberIntType, &window_id);
|
||||
if (IsWindowFullScreen(desktop_config, window)) {
|
||||
full_screen_window = window_id;
|
||||
break;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "modules/desktop_capture/mac/screen_capturer_mac.h"
|
||||
|
||||
#include "modules/desktop_capture/mac/desktop_frame_provider.h"
|
||||
#include "modules/desktop_capture/mac/window_list_utils.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/logging.h"
|
||||
@ -75,11 +76,7 @@ CFArrayRef CreateWindowListWithExclusion(CGWindowID window_to_exclude) {
|
||||
CFDictionaryRef window =
|
||||
reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(all_windows, i));
|
||||
|
||||
CFNumberRef id_ref =
|
||||
reinterpret_cast<CFNumberRef>(CFDictionaryGetValue(window, kCGWindowNumber));
|
||||
|
||||
CGWindowID id;
|
||||
CFNumberGetValue(id_ref, kCFNumberIntType, &id);
|
||||
CGWindowID id = GetWindowId(window);
|
||||
if (id == window_to_exclude) {
|
||||
found = true;
|
||||
continue;
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/mac_utils.h"
|
||||
@ -78,11 +80,8 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
|
||||
if (!window_array)
|
||||
return false;
|
||||
|
||||
MacDesktopConfiguration desktop_config;
|
||||
if (ignore_minimized) {
|
||||
desktop_config = MacDesktopConfiguration::GetCurrent(
|
||||
MacDesktopConfiguration::TopLeftOrigin);
|
||||
}
|
||||
MacDesktopConfiguration desktop_config = MacDesktopConfiguration::GetCurrent(
|
||||
MacDesktopConfiguration::TopLeftOrigin);
|
||||
|
||||
// Check windows to make sure they have an id, title, and use window layer
|
||||
// other than 0.
|
||||
@ -94,12 +93,6 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
|
||||
continue;
|
||||
}
|
||||
|
||||
CFStringRef window_title = reinterpret_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowName));
|
||||
if (!window_title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CFNumberRef window_id = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowNumber));
|
||||
if (!window_id) {
|
||||
@ -127,6 +120,15 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
|
||||
continue;
|
||||
}
|
||||
|
||||
// If window title is empty, only consider it if it is either on screen or
|
||||
// fullscreen.
|
||||
CFStringRef window_title = reinterpret_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowName));
|
||||
if (!window_title && !IsWindowOnScreen(window) &&
|
||||
!IsWindowFullScreen(desktop_config, window)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!on_window(window)) {
|
||||
break;
|
||||
}
|
||||
@ -138,16 +140,66 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
|
||||
|
||||
bool GetWindowList(DesktopCapturer::SourceList* windows,
|
||||
bool ignore_minimized) {
|
||||
return GetWindowList(
|
||||
[windows](CFDictionaryRef window) {
|
||||
WindowId id = GetWindowId(window);
|
||||
std::string title = GetWindowTitle(window);
|
||||
if (id != kNullWindowId && !title.empty()) {
|
||||
windows->push_back(DesktopCapturer::Source{id, title});
|
||||
// Use a std::list so that iterators are preversed upon insertion and
|
||||
// deletion.
|
||||
std::list<DesktopCapturer::Source> sources;
|
||||
std::map<int, std::list<DesktopCapturer::Source>::const_iterator> pid_itr_map;
|
||||
const bool ret = GetWindowList(
|
||||
[&sources, &pid_itr_map](CFDictionaryRef window) {
|
||||
WindowId window_id = GetWindowId(window);
|
||||
if (window_id != kNullWindowId) {
|
||||
const std::string title = GetWindowTitle(window);
|
||||
const int pid = GetWindowOwnerPid(window);
|
||||
// Check if window for the same pid have been already inserted.
|
||||
std::map<int,
|
||||
std::list<DesktopCapturer::Source>::const_iterator>::iterator
|
||||
itr = pid_itr_map.find(pid);
|
||||
|
||||
// Only consider empty titles if the app has no other window with a
|
||||
// proper title.
|
||||
if (title.empty()) {
|
||||
std::string owner_name = GetWindowOwnerName(window);
|
||||
|
||||
// At this time we do not know if there will be other windows
|
||||
// for the same pid unless they have been already inserted, hence
|
||||
// the check in the map. Also skip the window if owner name is
|
||||
// empty too.
|
||||
if (!owner_name.empty() && (itr == pid_itr_map.end())) {
|
||||
sources.push_back(DesktopCapturer::Source{window_id, owner_name});
|
||||
RTC_DCHECK(!sources.empty());
|
||||
// Get an iterator on the last valid element in the source list.
|
||||
std::list<DesktopCapturer::Source>::const_iterator last_source =
|
||||
--sources.end();
|
||||
pid_itr_map.insert(
|
||||
std::pair<int,
|
||||
std::list<DesktopCapturer::Source>::const_iterator>(
|
||||
pid, last_source));
|
||||
}
|
||||
} else {
|
||||
sources.push_back(DesktopCapturer::Source{window_id, title});
|
||||
// Once the window with empty title has been removed no other empty
|
||||
// windows are allowed for the same pid.
|
||||
if (itr != pid_itr_map.end() && (itr->second != sources.end())) {
|
||||
sources.erase(itr->second);
|
||||
// sdt::list::end() never changes during the lifetime of that
|
||||
// list.
|
||||
itr->second = sources.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
ignore_minimized);
|
||||
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
RTC_DCHECK(windows);
|
||||
windows->reserve(windows->size() + sources.size());
|
||||
std::copy(std::begin(sources), std::end(sources),
|
||||
std::back_inserter(*windows));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the window is occupying a full screen.
|
||||
@ -198,6 +250,37 @@ std::string GetWindowTitle(CFDictionaryRef window) {
|
||||
if (title && rtc::ToUtf8(title, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string GetWindowTitle(CGWindowID id) {
|
||||
std::string title;
|
||||
if (GetWindowRef(id, [&title](CFDictionaryRef window) {
|
||||
title = GetWindowTitle(window);
|
||||
})) {
|
||||
return title;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string GetWindowOwnerName(CFDictionaryRef window) {
|
||||
CFStringRef owner_name = reinterpret_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowOwnerName));
|
||||
std::string result;
|
||||
if (owner_name && rtc::ToUtf8(owner_name, &result)) {
|
||||
return result;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string GetWindowOwnerName(CGWindowID id) {
|
||||
std::string owner_name;
|
||||
if (GetWindowRef(id, [&owner_name](CFDictionaryRef window) {
|
||||
owner_name = GetWindowOwnerPid(window);
|
||||
})) {
|
||||
return owner_name;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@ -219,6 +302,31 @@ WindowId GetWindowId(CFDictionaryRef window) {
|
||||
return id;
|
||||
}
|
||||
|
||||
int GetWindowOwnerPid(CFDictionaryRef window) {
|
||||
CFNumberRef window_pid = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowOwnerPID));
|
||||
if (!window_pid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pid;
|
||||
if (!CFNumberGetValue(window_pid, kCFNumberIntType, &pid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int GetWindowOwnerPid(CGWindowID id) {
|
||||
int pid;
|
||||
if (GetWindowRef(id, [&pid](CFDictionaryRef window) {
|
||||
pid = GetWindowOwnerPid(window);
|
||||
})) {
|
||||
return pid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float GetScaleFactorAtPosition(const MacDesktopConfiguration& desktop_config,
|
||||
DesktopVector position) {
|
||||
// Find the dpi to physical pixel scale for the screen where the mouse cursor
|
||||
|
@ -48,10 +48,30 @@ bool IsWindowOnScreen(CGWindowID id);
|
||||
// valid title can be retrieved, this function returns an empty string.
|
||||
std::string GetWindowTitle(CFDictionaryRef window);
|
||||
|
||||
// Returns utf-8 encoded title of window |id|. If |id| cannot be found or no
|
||||
// valid title can be retrieved, this function returns an empty string.
|
||||
std::string GetWindowTitle(CGWindowID id);
|
||||
|
||||
// Returns utf-8 encoded owner name of |window|. If |window| is not a window or
|
||||
// if no valid owner name can be retrieved, returns an empty string.
|
||||
std::string GetWindowOwnerName(CFDictionaryRef window);
|
||||
|
||||
// Returns utf-8 encoded owner name of the given window |id|. If |id| cannot be
|
||||
// found or if no valid owner name can be retrieved, returns an empty string.
|
||||
std::string GetWindowOwnerName(CGWindowID id);
|
||||
|
||||
// Returns id of |window|. If |window| is not a window or the window id cannot
|
||||
// be retrieved, this function returns kNullWindowId.
|
||||
WindowId GetWindowId(CFDictionaryRef window);
|
||||
|
||||
// Returns the pid of the process owning |window|. Return 0 if |window| is not
|
||||
// a window or no valid owner can be retrieved.
|
||||
int GetWindowOwnerPid(CFDictionaryRef window);
|
||||
|
||||
// Returns the pid of the process owning the window |id|. Return 0 if |id|
|
||||
// cannot be found or no valid owner can be retrieved.
|
||||
int GetWindowOwnerPid(CGWindowID id);
|
||||
|
||||
// Returns the DIP to physical pixel scale at |position|. |position| is in
|
||||
// *unscaled* system coordinate, i.e. it's device-independent and the primary
|
||||
// monitor starts from (0, 0). If |position| is out of the system display, this
|
||||
|
Reference in New Issue
Block a user