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:
parent
77f73830e8
commit
1f55f1635f
7 changed files with 48 additions and 15 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "base/threading/thread_restrictions.h"
|
#include "base/threading/thread_restrictions.h"
|
||||||
#include "chrome/browser/media/webrtc/desktop_media_list.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 "content/public/browser/desktop_capture.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.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(
|
atom::api::NativeImage::Create(
|
||||||
isolate, gfx::Image(source.media_list_source.thumbnail)));
|
isolate, gfx::Image(source.media_list_source.thumbnail)));
|
||||||
dict.Set("display_id", source.display_id);
|
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);
|
return ConvertToV8(isolate, dict);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -60,7 +67,9 @@ DesktopCapturer::~DesktopCapturer() {}
|
||||||
|
|
||||||
void DesktopCapturer::StartHandling(bool capture_window,
|
void DesktopCapturer::StartHandling(bool capture_window,
|
||||||
bool capture_screen,
|
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 defined(OS_WIN)
|
||||||
if (content::desktop_capture::CreateDesktopCaptureOptions()
|
if (content::desktop_capture::CreateDesktopCaptureOptions()
|
||||||
.allow_directx_capturer()) {
|
.allow_directx_capturer()) {
|
||||||
|
@ -134,8 +143,8 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||||
capture_window_ = false;
|
capture_window_ = false;
|
||||||
const auto& media_list_sources = list->GetSources();
|
const auto& media_list_sources = list->GetSources();
|
||||||
for (const auto& media_list_source : media_list_sources) {
|
for (const auto& media_list_source : media_list_sources) {
|
||||||
window_sources.emplace_back(
|
window_sources.emplace_back(DesktopCapturer::Source{
|
||||||
DesktopCapturer::Source{media_list_source, std::string()});
|
media_list_source, std::string(), fetch_window_icons_});
|
||||||
}
|
}
|
||||||
std::move(window_sources.begin(), window_sources.end(),
|
std::move(window_sources.begin(), window_sources.end(),
|
||||||
std::back_inserter(captured_sources_));
|
std::back_inserter(captured_sources_));
|
||||||
|
@ -187,7 +196,7 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!capture_window_ && !capture_screen_)
|
if (!capture_window_ && !capture_screen_)
|
||||||
Emit("finished", captured_sources_);
|
Emit("finished", captured_sources_, fetch_window_icons_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -25,6 +25,9 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
|
||||||
DesktopMediaList::Source media_list_source;
|
DesktopMediaList::Source media_list_source;
|
||||||
// Will be an empty string if not available.
|
// Will be an empty string if not available.
|
||||||
std::string display_id;
|
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);
|
static mate::Handle<DesktopCapturer> Create(v8::Isolate* isolate);
|
||||||
|
@ -34,7 +37,8 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
|
||||||
|
|
||||||
void StartHandling(bool capture_window,
|
void StartHandling(bool capture_window,
|
||||||
bool capture_screen,
|
bool capture_screen,
|
||||||
const gfx::Size& thumbnail_size);
|
const gfx::Size& thumbnail_size,
|
||||||
|
bool fetch_window_icons);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit DesktopCapturer(v8::Isolate* isolate);
|
explicit DesktopCapturer(v8::Isolate* isolate);
|
||||||
|
@ -59,6 +63,7 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
|
||||||
std::vector<DesktopCapturer::Source> captured_sources_;
|
std::vector<DesktopCapturer::Source> captured_sources_;
|
||||||
bool capture_window_ = false;
|
bool capture_window_ = false;
|
||||||
bool capture_screen_ = false;
|
bool capture_screen_ = false;
|
||||||
|
bool fetch_window_icons_ = false;
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
bool using_directx_capturer_ = false;
|
bool using_directx_capturer_ = false;
|
||||||
#endif // defined(OS_WIN)
|
#endif // defined(OS_WIN)
|
||||||
|
|
|
@ -72,6 +72,7 @@ static_library("chrome") {
|
||||||
"//chrome/browser/media/webrtc/desktop_media_list_observer.h",
|
"//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.cc",
|
||||||
"//chrome/browser/media/webrtc/native_desktop_media_list.h",
|
"//chrome/browser/media/webrtc/native_desktop_media_list.h",
|
||||||
|
"//chrome/browser/media/webrtc/window_icon_util.h",
|
||||||
]
|
]
|
||||||
deps += [ "//ui/snapshot" ]
|
deps += [ "//ui/snapshot" ]
|
||||||
}
|
}
|
||||||
|
@ -93,6 +94,7 @@ static_library("chrome") {
|
||||||
|
|
||||||
if (is_mac) {
|
if (is_mac) {
|
||||||
sources += [
|
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.h",
|
||||||
"//chrome/browser/ui/cocoa/color_chooser_mac.mm",
|
"//chrome/browser/ui/cocoa/color_chooser_mac.mm",
|
||||||
]
|
]
|
||||||
|
@ -100,6 +102,7 @@ static_library("chrome") {
|
||||||
|
|
||||||
if (is_win) {
|
if (is_win) {
|
||||||
sources += [
|
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.cc",
|
||||||
"//chrome/browser/ui/views/color_chooser_dialog.h",
|
"//chrome/browser/ui/views/color_chooser_dialog.h",
|
||||||
"//chrome/browser/ui/views/color_chooser_win.cc",
|
"//chrome/browser/ui/views/color_chooser_win.cc",
|
||||||
|
@ -126,7 +129,10 @@ static_library("chrome") {
|
||||||
]
|
]
|
||||||
|
|
||||||
if (is_linux) {
|
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" ]
|
deps += [ "//third_party/speech-dispatcher" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,9 @@ The `desktopCapturer` module has the following methods:
|
||||||
to be captured, available types are `screen` and `window`.
|
to be captured, available types are `screen` and `window`.
|
||||||
* `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail
|
* `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail
|
||||||
should be scaled to. Default is `150` x `150`.
|
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
|
* `callback` Function
|
||||||
* `error` Error
|
* `error` Error
|
||||||
* `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md)
|
* `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md)
|
||||||
|
|
|
@ -17,3 +17,7 @@
|
||||||
On some platforms, this is equivalent to the `XX` portion of the `id` field
|
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
|
above and on others it will differ. It will be an empty string if not
|
||||||
available.
|
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.
|
||||||
|
|
|
@ -11,19 +11,20 @@ let requestsQueue = []
|
||||||
const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES'
|
const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES'
|
||||||
const capturerResult = (id) => `ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`
|
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 = {
|
const request = {
|
||||||
id,
|
id,
|
||||||
options: {
|
options: {
|
||||||
captureWindow,
|
captureWindow,
|
||||||
captureScreen,
|
captureScreen,
|
||||||
thumbnailSize
|
thumbnailSize,
|
||||||
|
fetchWindowIcons
|
||||||
},
|
},
|
||||||
webContents: event.sender
|
webContents: event.sender
|
||||||
}
|
}
|
||||||
requestsQueue.push(request)
|
requestsQueue.push(request)
|
||||||
if (requestsQueue.length === 1) {
|
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
|
// 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.
|
// Receiving sources result from main process, now send them back to renderer.
|
||||||
const handledRequest = requestsQueue.shift()
|
const handledRequest = requestsQueue.shift()
|
||||||
const handledWebContents = handledRequest.webContents
|
const handledWebContents = handledRequest.webContents
|
||||||
|
@ -44,7 +45,8 @@ desktopCapturer.emit = (event, name, sources) => {
|
||||||
id: source.id,
|
id: source.id,
|
||||||
name: source.name,
|
name: source.name,
|
||||||
thumbnail: source.thumbnail.toDataURL(),
|
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 the requestsQueue is not empty, start a new request handling.
|
||||||
if (requestsQueue.length > 0) {
|
if (requestsQueue.length > 0) {
|
||||||
const { captureWindow, captureScreen, thumbnailSize } = requestsQueue[0].options
|
const { captureWindow, captureScreen, thumbnailSize, fetchWindowIcons } = requestsQueue[0].options
|
||||||
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize)
|
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,12 @@ exports.getSources = function (options, callback) {
|
||||||
height: 150
|
height: 150
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options.fetchWindowIcons == null) {
|
||||||
|
options.fetchWindowIcons = false
|
||||||
|
}
|
||||||
|
|
||||||
const id = incrementId()
|
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) => {
|
return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => {
|
||||||
callback(null, (() => {
|
callback(null, (() => {
|
||||||
const results = []
|
const results = []
|
||||||
|
@ -39,7 +42,8 @@ exports.getSources = function (options, callback) {
|
||||||
id: source.id,
|
id: source.id,
|
||||||
name: source.name,
|
name: source.name,
|
||||||
thumbnail: nativeImage.createFromDataURL(source.thumbnail),
|
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
|
return results
|
||||||
|
|
Loading…
Reference in a new issue