feat: add support for DesktopCapturerSource.appIcon

Useful to get the icon of the application owning the source.
Only available for sources of type window, i.e. not for screen.

https://github.com/electron/electron/issues/14845
This commit is contained in:
Julien Isorce 2018-12-03 22:42:49 -08:00 committed by Cheng Zhao
parent 77f73830e8
commit 1f55f1635f
7 changed files with 48 additions and 15 deletions

View file

@ -14,6 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/media/webrtc/desktop_media_list.h"
#include "chrome/browser/media/webrtc/window_icon_util.h"
#include "content/public/browser/desktop_capture.h"
#include "native_mate/dictionary.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
@ -42,6 +43,12 @@ struct Converter<atom::api::DesktopCapturer::Source> {
atom::api::NativeImage::Create(
isolate, gfx::Image(source.media_list_source.thumbnail)));
dict.Set("display_id", source.display_id);
if (source.fetch_icon) {
dict.Set(
"appIcon",
atom::api::NativeImage::Create(
isolate, gfx::Image(GetWindowIcon(source.media_list_source.id))));
}
return ConvertToV8(isolate, dict);
}
};
@ -60,7 +67,9 @@ DesktopCapturer::~DesktopCapturer() {}
void DesktopCapturer::StartHandling(bool capture_window,
bool capture_screen,
const gfx::Size& thumbnail_size) {
const gfx::Size& thumbnail_size,
bool fetch_window_icons) {
fetch_window_icons_ = fetch_window_icons;
#if defined(OS_WIN)
if (content::desktop_capture::CreateDesktopCaptureOptions()
.allow_directx_capturer()) {
@ -134,8 +143,8 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
capture_window_ = false;
const auto& media_list_sources = list->GetSources();
for (const auto& media_list_source : media_list_sources) {
window_sources.emplace_back(
DesktopCapturer::Source{media_list_source, std::string()});
window_sources.emplace_back(DesktopCapturer::Source{
media_list_source, std::string(), fetch_window_icons_});
}
std::move(window_sources.begin(), window_sources.end(),
std::back_inserter(captured_sources_));
@ -187,7 +196,7 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
}
if (!capture_window_ && !capture_screen_)
Emit("finished", captured_sources_);
Emit("finished", captured_sources_, fetch_window_icons_);
}
// static

View file

@ -25,6 +25,9 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
DesktopMediaList::Source media_list_source;
// Will be an empty string if not available.
std::string display_id;
// Whether or not this source should provide an icon.
bool fetch_icon = false;
};
static mate::Handle<DesktopCapturer> Create(v8::Isolate* isolate);
@ -34,7 +37,8 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
void StartHandling(bool capture_window,
bool capture_screen,
const gfx::Size& thumbnail_size);
const gfx::Size& thumbnail_size,
bool fetch_window_icons);
protected:
explicit DesktopCapturer(v8::Isolate* isolate);
@ -59,6 +63,7 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
std::vector<DesktopCapturer::Source> captured_sources_;
bool capture_window_ = false;
bool capture_screen_ = false;
bool fetch_window_icons_ = false;
#if defined(OS_WIN)
bool using_directx_capturer_ = false;
#endif // defined(OS_WIN)

View file

@ -72,6 +72,7 @@ static_library("chrome") {
"//chrome/browser/media/webrtc/desktop_media_list_observer.h",
"//chrome/browser/media/webrtc/native_desktop_media_list.cc",
"//chrome/browser/media/webrtc/native_desktop_media_list.h",
"//chrome/browser/media/webrtc/window_icon_util.h",
]
deps += [ "//ui/snapshot" ]
}
@ -93,6 +94,7 @@ static_library("chrome") {
if (is_mac) {
sources += [
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
"//chrome/browser/ui/cocoa/color_chooser_mac.h",
"//chrome/browser/ui/cocoa/color_chooser_mac.mm",
]
@ -100,6 +102,7 @@ static_library("chrome") {
if (is_win) {
sources += [
"//chrome/browser/media/webrtc/window_icon_util_win.cc",
"//chrome/browser/ui/views/color_chooser_dialog.cc",
"//chrome/browser/ui/views/color_chooser_dialog.h",
"//chrome/browser/ui/views/color_chooser_win.cc",
@ -126,7 +129,10 @@ static_library("chrome") {
]
if (is_linux) {
sources += [ "//chrome/browser/speech/tts_linux.cc" ]
sources += [
"//chrome/browser/media/webrtc/window_icon_util_x11.cc",
"//chrome/browser/speech/tts_linux.cc",
]
deps += [ "//third_party/speech-dispatcher" ]
}
}

View file

@ -84,6 +84,9 @@ The `desktopCapturer` module has the following methods:
to be captured, available types are `screen` and `window`.
* `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail
should be scaled to. Default is `150` x `150`.
* `fetchWindowIcons` Boolean (optional) - Set to true to enable fetching window icons. The default
value is false. When false the appIcon property of the sources return null. Same if a source has
the type screen.
* `callback` Function
* `error` Error
* `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md)

View file

@ -17,3 +17,7 @@
On some platforms, this is equivalent to the `XX` portion of the `id` field
above and on others it will differ. It will be an empty string if not
available.
* `appIcon` [NativeImage](../native-image.md) - An icon image of the
application that owns the window or null if the source has a type screen.
The size of the icon is not known in advance and depends on what the
the application provides.

View file

@ -11,19 +11,20 @@ let requestsQueue = []
const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES'
const capturerResult = (id) => `ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`
ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, id) => {
ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, fetchWindowIcons, id) => {
const request = {
id,
options: {
captureWindow,
captureScreen,
thumbnailSize
thumbnailSize,
fetchWindowIcons
},
webContents: event.sender
}
requestsQueue.push(request)
if (requestsQueue.length === 1) {
desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize)
desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
}
// If the WebContents is destroyed before receiving result, just remove the
@ -33,7 +34,7 @@ ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize,
})
})
desktopCapturer.emit = (event, name, sources) => {
desktopCapturer.emit = (event, name, sources, fetchWindowIcons) => {
// Receiving sources result from main process, now send them back to renderer.
const handledRequest = requestsQueue.shift()
const handledWebContents = handledRequest.webContents
@ -44,7 +45,8 @@ desktopCapturer.emit = (event, name, sources) => {
id: source.id,
name: source.name,
thumbnail: source.thumbnail.toDataURL(),
display_id: source.display_id
display_id: source.display_id,
appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
}
})
@ -67,7 +69,7 @@ desktopCapturer.emit = (event, name, sources) => {
// If the requestsQueue is not empty, start a new request handling.
if (requestsQueue.length > 0) {
const { captureWindow, captureScreen, thumbnailSize } = requestsQueue[0].options
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize)
const { captureWindow, captureScreen, thumbnailSize, fetchWindowIcons } = requestsQueue[0].options
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
}
}

View file

@ -28,9 +28,12 @@ exports.getSources = function (options, callback) {
height: 150
}
}
if (options.fetchWindowIcons == null) {
options.fetchWindowIcons = false
}
const id = incrementId()
ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id)
ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, options.fetchWindowIcons, id)
return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => {
callback(null, (() => {
const results = []
@ -39,7 +42,8 @@ exports.getSources = function (options, callback) {
id: source.id,
name: source.name,
thumbnail: nativeImage.createFromDataURL(source.thumbnail),
display_id: source.display_id
display_id: source.display_id,
appIcon: source.appIcon ? nativeImage.createFromDataURL(source.appIcon) : null
})
})
return results