feat: Implement BrowserWindow.getMediaSourceId() and BrowserWindow.moveAbove(mediaSourceId) (#18926)
* feat: Implement BrowserWindow.moveAbove(mediaSourceId) BrowserWindow.{focus,blur,moveTop}() are not enough in some situations. For example when implementing an overlay that follows another window that can lose focus. In that case it is useful to move the overlay above the tracked window. sourceId is a string in the format of DesktopCapturerSource.id, for example "window:1869:0". Notes: Added BrowserWindow.moveAbove(mediaSourceId) https://github.com/electron/electron/issues/18922 * feat: Implement BrowserWindow.getMediaSourceId Return the Window id in the format of DesktopCapturerSource's id. For example "window🔢0". https://github.com/electron/electron/issues/16460 Notes: Added BrowserWindow.getMediaSourceId
This commit is contained in:
parent
d0c7a91a50
commit
680399f476
12 changed files with 320 additions and 4 deletions
|
@ -553,6 +553,11 @@ std::vector<int> TopLevelWindow::GetPosition() {
|
|||
result[1] = pos.y();
|
||||
return result;
|
||||
}
|
||||
void TopLevelWindow::MoveAbove(const std::string& sourceId,
|
||||
mate::Arguments* args) {
|
||||
if (!window_->MoveAbove(sourceId))
|
||||
args->ThrowError("Invalid media source id");
|
||||
}
|
||||
|
||||
void TopLevelWindow::MoveTop() {
|
||||
window_->MoveTop();
|
||||
|
@ -731,6 +736,11 @@ void TopLevelWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string TopLevelWindow::GetMediaSourceId() const {
|
||||
return window_->GetDesktopMediaID().ToString();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> TopLevelWindow::GetNativeWindowHandle() {
|
||||
// TODO(MarshallOfSound): Replace once
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/1253094/ has
|
||||
|
@ -1077,6 +1087,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setMaximumSize", &TopLevelWindow::SetMaximumSize)
|
||||
.SetMethod("getMaximumSize", &TopLevelWindow::GetMaximumSize)
|
||||
.SetMethod("setSheetOffset", &TopLevelWindow::SetSheetOffset)
|
||||
.SetMethod("moveAbove", &TopLevelWindow::MoveAbove)
|
||||
.SetMethod("moveTop", &TopLevelWindow::MoveTop)
|
||||
.SetMethod("_setResizable", &TopLevelWindow::SetResizable)
|
||||
.SetMethod("_isResizable", &TopLevelWindow::IsResizable)
|
||||
|
@ -1136,6 +1147,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setBrowserView", &TopLevelWindow::SetBrowserView)
|
||||
.SetMethod("addBrowserView", &TopLevelWindow::AddBrowserView)
|
||||
.SetMethod("removeBrowserView", &TopLevelWindow::RemoveBrowserView)
|
||||
.SetMethod("getMediaSourceId", &TopLevelWindow::GetMediaSourceId)
|
||||
.SetMethod("getNativeWindowHandle",
|
||||
&TopLevelWindow::GetNativeWindowHandle)
|
||||
.SetMethod("setProgressBar", &TopLevelWindow::SetProgressBar)
|
||||
|
|
|
@ -127,6 +127,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
|
|||
void SetResizable(bool resizable);
|
||||
bool IsResizable();
|
||||
void SetMovable(bool movable);
|
||||
void MoveAbove(const std::string& sourceId, mate::Arguments* args);
|
||||
void MoveTop();
|
||||
bool IsMovable();
|
||||
void SetMinimizable(bool minimizable);
|
||||
|
@ -173,6 +174,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
|
|||
virtual void RemoveBrowserView(v8::Local<v8::Value> value);
|
||||
virtual std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
|
||||
virtual void ResetBrowserViews();
|
||||
std::string GetMediaSourceId() const;
|
||||
v8::Local<v8::Value> GetNativeWindowHandle();
|
||||
void SetProgressBar(double progress, mate::Arguments* args);
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/supports_user_data.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "extensions/browser/app_window/size_constraints.h"
|
||||
#include "shell/browser/native_window_observer.h"
|
||||
|
@ -111,6 +112,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual double GetSheetOffsetX();
|
||||
virtual double GetSheetOffsetY();
|
||||
virtual void SetResizable(bool resizable) = 0;
|
||||
virtual bool MoveAbove(const std::string& sourceId) = 0;
|
||||
virtual void MoveTop() = 0;
|
||||
virtual bool IsResizable() = 0;
|
||||
virtual void SetMovable(bool movable) = 0;
|
||||
|
@ -156,6 +158,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void SetParentWindow(NativeWindow* parent);
|
||||
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual void RemoveBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual content::DesktopMediaID GetDesktopMediaID() const = 0;
|
||||
virtual gfx::NativeView GetNativeView() const = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
|
||||
|
|
|
@ -59,6 +59,7 @@ class NativeWindowMac : public NativeWindow {
|
|||
void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) override;
|
||||
void SetResizable(bool resizable) override;
|
||||
bool MoveAbove(const std::string& sourceId) override;
|
||||
void MoveTop() override;
|
||||
bool IsResizable() override;
|
||||
void SetMovable(bool movable) override;
|
||||
|
@ -108,6 +109,7 @@ class NativeWindowMac : public NativeWindow {
|
|||
void AddBrowserView(NativeBrowserView* browser_view) override;
|
||||
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
content::DesktopMediaID GetDesktopMediaID() const override;
|
||||
gfx::NativeView GetNativeView() const override;
|
||||
gfx::NativeWindow GetNativeWindow() const override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "shell/browser/native_browser_view_mac.h"
|
||||
#include "shell/browser/ui/cocoa/atom_native_widget_mac.h"
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "shell/common/deprecate_util.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/mac/window_list_utils.h"
|
||||
#include "ui/gfx/skia_util.h"
|
||||
#include "ui/gl/gpu_switching_manager.h"
|
||||
#include "ui/views/background.h"
|
||||
|
@ -724,6 +726,21 @@ void NativeWindowMac::SetContentSizeConstraints(
|
|||
NativeWindow::SetContentSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
bool NativeWindowMac::MoveAbove(const std::string& sourceId) {
|
||||
const content::DesktopMediaID id = content::DesktopMediaID::Parse(sourceId);
|
||||
if (id.type != content::DesktopMediaID::TYPE_WINDOW)
|
||||
return false;
|
||||
|
||||
// Check if the window source is valid.
|
||||
const CGWindowID window_id = id.id;
|
||||
if (!webrtc::GetWindowOwnerPid(window_id))
|
||||
return false;
|
||||
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:id.id];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindowMac::MoveTop() {
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:0];
|
||||
}
|
||||
|
@ -1128,7 +1145,12 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() const {
|
|||
}
|
||||
|
||||
gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const {
|
||||
return gfx::kNullAcceleratedWidget;
|
||||
return [window_ windowNumber];
|
||||
}
|
||||
|
||||
content::DesktopMediaID NativeWindowMac::GetDesktopMediaID() const {
|
||||
return content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW,
|
||||
GetAcceleratedWidget());
|
||||
}
|
||||
|
||||
NativeWindowHandle NativeWindowMac::GetNativeWindowHandle() const {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "base/stl_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "shell/browser/api/atom_api_web_contents.h"
|
||||
#include "shell/browser/native_browser_view_views.h"
|
||||
|
@ -647,6 +648,31 @@ void NativeWindowViews::SetResizable(bool resizable) {
|
|||
resizable_ = resizable;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
|
||||
const content::DesktopMediaID id = content::DesktopMediaID::Parse(sourceId);
|
||||
if (id.type != content::DesktopMediaID::TYPE_WINDOW)
|
||||
return false;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
const HWND otherWindow = reinterpret_cast<HWND>(id.id);
|
||||
if (!::IsWindow(otherWindow))
|
||||
return false;
|
||||
|
||||
gfx::Point pos = GetPosition();
|
||||
gfx::Size size = GetSize();
|
||||
::SetWindowPos(GetAcceleratedWidget(), otherWindow, pos.x(), pos.y(),
|
||||
size.width(), size.height(),
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||
#elif defined(USE_X11)
|
||||
if (!IsWindowValid(id.id))
|
||||
return false;
|
||||
|
||||
electron::MoveWindowAbove(GetAcceleratedWidget(), id.id);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindowViews::MoveTop() {
|
||||
// TODO(julien.isorce): fix chromium in order to use existing
|
||||
// widget()->StackAtTop().
|
||||
|
@ -1117,6 +1143,37 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
|
|||
return false;
|
||||
}
|
||||
|
||||
content::DesktopMediaID NativeWindowViews::GetDesktopMediaID() const {
|
||||
const gfx::AcceleratedWidget accelerated_widget = GetAcceleratedWidget();
|
||||
content::DesktopMediaID::Id window_handle = content::DesktopMediaID::kNullId;
|
||||
content::DesktopMediaID::Id aura_id = content::DesktopMediaID::kNullId;
|
||||
#if defined(OS_WIN)
|
||||
window_handle =
|
||||
reinterpret_cast<content::DesktopMediaID::Id>(accelerated_widget);
|
||||
#elif defined(USE_X11)
|
||||
window_handle = accelerated_widget;
|
||||
#endif
|
||||
aura::WindowTreeHost* const host =
|
||||
aura::WindowTreeHost::GetForAcceleratedWidget(accelerated_widget);
|
||||
aura::Window* const aura_window = host ? host->window() : nullptr;
|
||||
if (aura_window) {
|
||||
aura_id = content::DesktopMediaID::RegisterNativeWindow(
|
||||
content::DesktopMediaID::TYPE_WINDOW, aura_window)
|
||||
.window_id;
|
||||
}
|
||||
|
||||
// No constructor to pass the aura_id. Make sure to not use the other
|
||||
// constructor that has a third parameter, it is for yet another purpose.
|
||||
content::DesktopMediaID result = content::DesktopMediaID(
|
||||
content::DesktopMediaID::TYPE_WINDOW, window_handle);
|
||||
|
||||
// Confusing but this is how content::DesktopMediaID is designed. The id
|
||||
// property is the window handle whereas the window_id property is an id
|
||||
// given by a map containing all aura instances.
|
||||
result.window_id = aura_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
|
||||
if (GetNativeWindow() && GetNativeWindow()->GetHost())
|
||||
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
|
||||
|
|
|
@ -68,6 +68,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) override;
|
||||
void SetResizable(bool resizable) override;
|
||||
bool MoveAbove(const std::string& sourceId) override;
|
||||
void MoveTop() override;
|
||||
bool IsResizable() override;
|
||||
void SetMovable(bool movable) override;
|
||||
|
@ -124,6 +125,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
|
||||
bool IsVisibleOnAllWorkspaces() override;
|
||||
|
||||
content::DesktopMediaID GetDesktopMediaID() const override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
NativeWindowHandle GetNativeWindowHandle() const override;
|
||||
|
||||
|
|
|
@ -89,6 +89,10 @@ bool ShouldUseGlobalMenuBar() {
|
|||
}
|
||||
|
||||
void MoveWindowToForeground(::Window xwindow) {
|
||||
MoveWindowAbove(xwindow, 0);
|
||||
}
|
||||
|
||||
void MoveWindowAbove(::Window xwindow, ::Window other_xwindow) {
|
||||
XDisplay* xdisplay = gfx::GetXDisplay();
|
||||
XEvent xclient;
|
||||
memset(&xclient, 0, sizeof(xclient));
|
||||
|
@ -99,7 +103,7 @@ void MoveWindowToForeground(::Window xwindow) {
|
|||
xclient.xclient.message_type = GetAtom("_NET_RESTACK_WINDOW");
|
||||
xclient.xclient.format = 32;
|
||||
xclient.xclient.data.l[0] = 2;
|
||||
xclient.xclient.data.l[1] = 0;
|
||||
xclient.xclient.data.l[1] = other_xwindow;
|
||||
xclient.xclient.data.l[2] = Above;
|
||||
xclient.xclient.data.l[3] = 0;
|
||||
xclient.xclient.data.l[4] = 0;
|
||||
|
@ -109,4 +113,9 @@ void MoveWindowToForeground(::Window xwindow) {
|
|||
XFlush(xdisplay);
|
||||
}
|
||||
|
||||
bool IsWindowValid(::Window xwindow) {
|
||||
XWindowAttributes attrs;
|
||||
return XGetWindowAttributes(gfx::GetXDisplay(), xwindow, &attrs);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
|
|
@ -23,9 +23,15 @@ void SetWindowType(::Window xwindow, const std::string& type);
|
|||
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
|
||||
bool ShouldUseGlobalMenuBar();
|
||||
|
||||
// Bring the given window to the front and give it the focus.
|
||||
// Bring the given window to the front regardless of focus.
|
||||
void MoveWindowToForeground(::Window xwindow);
|
||||
|
||||
// Move a given window above the other one.
|
||||
void MoveWindowAbove(::Window xwindow, ::Window other_xwindow);
|
||||
|
||||
// Return true is the given window exists, false otherwise.
|
||||
bool IsWindowValid(::Window xwindow);
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_UI_X_X_WINDOW_UTILS_H_
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue