feat: implement BrowserWindow.moveTop on X11 (#16629)
It was implemented on Mac and Win but not on X11. Tested on Ubuntu 16.04 and 18.04. Also added a unit test in spec/api-browser-window-spec.js. This test BrowserWindow.moveTop verifies that calling moveTop on a window does not give the focus to this window. notes: BrowserWindow.moveTop is now available on Linux/x11 https://github.com/electron/electron/issues/12516
This commit is contained in:
parent
db11b9b13b
commit
27bd47a333
9 changed files with 73 additions and 13 deletions
|
@ -548,11 +548,9 @@ std::vector<int> TopLevelWindow::GetPosition() {
|
|||
return result;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
void TopLevelWindow::MoveTop() {
|
||||
window_->MoveTop();
|
||||
}
|
||||
#endif
|
||||
|
||||
void TopLevelWindow::SetTitle(const std::string& title) {
|
||||
window_->SetTitle(title);
|
||||
|
@ -1067,9 +1065,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setResizable", &TopLevelWindow::SetResizable)
|
||||
.SetMethod("isResizable", &TopLevelWindow::IsResizable)
|
||||
.SetMethod("setMovable", &TopLevelWindow::SetMovable)
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
.SetMethod("moveTop", &TopLevelWindow::MoveTop)
|
||||
#endif
|
||||
.SetMethod("isMovable", &TopLevelWindow::IsMovable)
|
||||
.SetMethod("setMinimizable", &TopLevelWindow::SetMinimizable)
|
||||
.SetMethod("isMinimizable", &TopLevelWindow::IsMinimizable)
|
||||
|
|
|
@ -126,9 +126,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
|
|||
void SetResizable(bool resizable);
|
||||
bool IsResizable();
|
||||
void SetMovable(bool movable);
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
void MoveTop();
|
||||
#endif
|
||||
bool IsMovable();
|
||||
void SetMinimizable(bool minimizable);
|
||||
bool IsMinimizable();
|
||||
|
|
|
@ -113,9 +113,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual double GetSheetOffsetX();
|
||||
virtual double GetSheetOffsetY();
|
||||
virtual void SetResizable(bool resizable) = 0;
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
virtual void MoveTop() = 0;
|
||||
#endif
|
||||
virtual bool IsResizable() = 0;
|
||||
virtual void SetMovable(bool movable) = 0;
|
||||
virtual bool IsMovable() = 0;
|
||||
|
|
|
@ -657,15 +657,19 @@ void NativeWindowViews::SetResizable(bool resizable) {
|
|||
resizable_ = resizable;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void NativeWindowViews::MoveTop() {
|
||||
// TODO(julien.isorce): fix chromium in order to use existing
|
||||
// widget()->StackAtTop().
|
||||
#if defined(OS_WIN)
|
||||
gfx::Point pos = GetPosition();
|
||||
gfx::Size size = GetSize();
|
||||
::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
|
||||
size.width(), size.height(),
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||
}
|
||||
#elif defined(USE_X11)
|
||||
atom::MoveWindowToForeground(GetAcceleratedWidget());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsResizable() {
|
||||
#if defined(OS_WIN)
|
||||
|
|
|
@ -74,9 +74,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) override;
|
||||
void SetResizable(bool resizable) override;
|
||||
#if defined(OS_WIN)
|
||||
void MoveTop() override;
|
||||
#endif
|
||||
bool IsResizable() override;
|
||||
void SetMovable(bool movable) override;
|
||||
bool IsMovable() override;
|
||||
|
|
|
@ -88,4 +88,25 @@ bool ShouldUseGlobalMenuBar() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void MoveWindowToForeground(::Window xwindow) {
|
||||
XDisplay* xdisplay = gfx::GetXDisplay();
|
||||
XEvent xclient;
|
||||
memset(&xclient, 0, sizeof(xclient));
|
||||
|
||||
xclient.type = ClientMessage;
|
||||
xclient.xclient.display = xdisplay;
|
||||
xclient.xclient.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[2] = Above;
|
||||
xclient.xclient.data.l[3] = 0;
|
||||
xclient.xclient.data.l[4] = 0;
|
||||
|
||||
XSendEvent(xdisplay, DefaultRootWindow(xdisplay), x11::False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
|
||||
XFlush(xdisplay);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -23,6 +23,9 @@ 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.
|
||||
void MoveWindowToForeground(::Window xwindow);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_
|
||||
|
|
|
@ -1089,7 +1089,7 @@ can not be focused on.
|
|||
|
||||
Returns `Boolean` - Whether the window is always on top of other windows.
|
||||
|
||||
#### `win.moveTop()` _macOS_ _Windows_
|
||||
#### `win.moveTop()`
|
||||
|
||||
Moves window to top(z-order) regardless of focus
|
||||
|
||||
|
|
|
@ -494,6 +494,48 @@ describe('BrowserWindow module', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('BrowserWindow.moveTop()', () => {
|
||||
it('should not steal focus', async () => {
|
||||
const posDelta = 50
|
||||
const wShownInactive = emittedOnce(w, 'show')
|
||||
w.showInactive()
|
||||
await wShownInactive
|
||||
assert(!w.isFocused())
|
||||
|
||||
const otherWindow = new BrowserWindow({ show: false, title: 'otherWindow' })
|
||||
const otherWindowShown = emittedOnce(otherWindow, 'show')
|
||||
otherWindow.loadURL('data:text/html,<html><body background-color: rgba(255,255,255,0)></body></html>')
|
||||
otherWindow.show()
|
||||
await otherWindowShown
|
||||
assert(otherWindow.isFocused())
|
||||
|
||||
w.moveTop()
|
||||
const wPos = w.getPosition()
|
||||
const wMoving = emittedOnce(w, 'move')
|
||||
w.setPosition(wPos[0] + posDelta, wPos[1] + posDelta)
|
||||
await wMoving
|
||||
assert(!w.isFocused())
|
||||
assert(otherWindow.isFocused())
|
||||
|
||||
const wFocused = emittedOnce(w, 'focus')
|
||||
w.focus()
|
||||
await wFocused
|
||||
assert(w.isFocused())
|
||||
|
||||
otherWindow.moveTop()
|
||||
const otherWindowPos = otherWindow.getPosition()
|
||||
const otherWindowMoving = emittedOnce(otherWindow, 'move')
|
||||
otherWindow.setPosition(otherWindowPos[0] + posDelta, otherWindowPos[1] + posDelta)
|
||||
await otherWindowMoving
|
||||
assert(!otherWindow.isFocused())
|
||||
assert(w.isFocused())
|
||||
|
||||
await closeWindow(otherWindow, { assertSingleWindow: false }).then(() => {
|
||||
assert.strictEqual(BrowserWindow.getAllWindows().length, 2) // Test window + w
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('BrowserWindow.capturePage(rect)', (done) => {
|
||||
it('returns a Promise with a Buffer', async () => {
|
||||
const image = await w.capturePage({
|
||||
|
|
Loading…
Add table
Reference in a new issue