From 1f55f1635f1184109acce2d6eff2cc6837b6f1cc Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Mon, 3 Dec 2018 22:42:49 -0800 Subject: [PATCH] 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 --- atom/browser/api/atom_api_desktop_capturer.cc | 17 +++++++++++++---- atom/browser/api/atom_api_desktop_capturer.h | 7 ++++++- chromium_src/BUILD.gn | 8 +++++++- docs/api/desktop-capturer.md | 3 +++ docs/api/structures/desktop-capturer-source.md | 4 ++++ lib/browser/desktop-capturer.js | 16 +++++++++------- lib/renderer/api/desktop-capturer.js | 8 ++++++-- 7 files changed, 48 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index a87759da85472..b8a1bc7bbbefc 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -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::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 diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index 22be4c7710c68..0cb22961c3f3c 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -25,6 +25,9 @@ class DesktopCapturer : public mate::EventEmitter, 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 Create(v8::Isolate* isolate); @@ -34,7 +37,8 @@ class DesktopCapturer : public mate::EventEmitter, 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, std::vector 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) diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 93929067777cf..f293db611a202 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -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" ] } } diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index caff5de4b07be..5465ee7313f36 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -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) diff --git a/docs/api/structures/desktop-capturer-source.md b/docs/api/structures/desktop-capturer-source.md index 083f9e64f0a8d..ffb34b79b7dda 100644 --- a/docs/api/structures/desktop-capturer-source.md +++ b/docs/api/structures/desktop-capturer-source.md @@ -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. diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index 62e68bb4240fb..c2cdd73ef95cd 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -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) } } diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index e4ece821b9060..74f9e3b3e2617 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -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