From 2f66ed1dc80e71f76b0c1aa9905feac1f8735701 Mon Sep 17 00:00:00 2001 From: Pierre Curto Date: Wed, 8 Sep 2021 22:02:26 +0200 Subject: [PATCH] app: add Window.Raise to bring a window to the front Fixes gio#252 Signed-off-by: Pierre Curto --- app/internal/windows/windows.go | 1 + app/os.go | 3 +++ app/os_android.go | 2 ++ app/os_ios.go | 2 ++ app/os_js.go | 2 ++ app/os_macos.go | 10 ++++++++++ app/os_wayland.go | 2 ++ app/os_windows.go | 6 ++++++ app/os_x11.go | 23 +++++++++++++++++++++++ app/window.go | 10 ++++++++++ 10 files changed, 61 insertions(+) diff --git a/app/internal/windows/windows.go b/app/internal/windows/windows.go index 8edc3c13..e8dced0b 100644 --- a/app/internal/windows/windows.go +++ b/app/internal/windows/windows.go @@ -113,6 +113,7 @@ const ( SWP_NOOWNERZORDER = 0x0200 SWP_NOSIZE = 0x0001 SWP_NOZORDER = 0x0004 + SWP_SHOWWINDOW = 0x0040 USER_TIMER_MINIMUM = 0x0000000A diff --git a/app/os.go b/app/os.go index a5f2489d..812222bc 100644 --- a/app/os.go +++ b/app/os.go @@ -141,6 +141,9 @@ type driver interface { // SetCursor updates the current cursor to name. SetCursor(name pointer.CursorName) + // Raise the window at the top. + Raise() + // Close the window. Close() // Wakeup wakes up the event loop and sends a WakeupEvent. diff --git a/app/os_android.go b/app/os_android.go index 832e88b0..eb7a4138 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -822,6 +822,8 @@ func (w *window) Config() Config { return w.config } +func (w *window) Raise() {} + func (w *window) SetCursor(name pointer.CursorName) { runInJVM(javaVM(), func(env *C.JNIEnv) { setCursor(env, w.view, name) diff --git a/app/os_ios.go b/app/os_ios.go index ab1589f3..92c32fa2 100644 --- a/app/os_ios.go +++ b/app/os_ios.go @@ -275,6 +275,8 @@ func (w *window) Config() Config { return w.config } +func (w *window) Raise() {} + func (w *window) SetAnimating(anim bool) { v := w.view if v == 0 { diff --git a/app/os_js.go b/app/os_js.go index 61b2948a..5ccaf0da 100644 --- a/app/os_js.go +++ b/app/os_js.go @@ -534,6 +534,8 @@ func (w *window) Config() Config { return w.config } +func (w *window) Raise() {} + func (w *window) SetCursor(name pointer.CursorName) { style := w.cnv.Get("style") style.Set("cursor", string(name)) diff --git a/app/os_macos.go b/app/os_macos.go index a80e8a5b..bf32184b 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -127,6 +127,12 @@ static CFTypeRef layerForView(CFTypeRef viewRef) { NSView *view = (__bridge NSView *)viewRef; return (__bridge CFTypeRef)view.layer; } + +static void raiseWindow(CFTypeRef windowRef) { + NSWindow* window = (__bridge NSWindow *)windowRef; + [window makeKeyAndOrderFront:nil]; +} + */ import "C" @@ -268,6 +274,10 @@ func (w *window) SetAnimating(anim bool) { } } +func (w *window) Raise() { + C.raiseWindow(w.window) +} + func (w *window) runOnMain(f func()) { runOnMain(func() { // Make sure the view is still valid. The window might've been closed diff --git a/app/os_wayland.go b/app/os_wayland.go index 8ab930cb..0753fcd2 100644 --- a/app/os_wayland.go +++ b/app/os_wayland.go @@ -927,6 +927,8 @@ func (w *window) Config() Config { return w.config } +func (w *window) Raise() {} + func (w *window) SetCursor(name pointer.CursorName) { if name == pointer.CursorNone { C.wl_pointer_set_cursor(w.disp.seat.pointer, w.serial, nil, 0, 0) diff --git a/app/os_windows.go b/app/os_windows.go index 640d7321..7cd62913 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -663,6 +663,12 @@ func (w *window) Close() { windows.PostMessage(w.hwnd, windows.WM_CLOSE, 0, 0) } +func (w *window) Raise() { + windows.SetForegroundWindow(w.hwnd) + windows.SetWindowPos(w.hwnd, windows.HWND_TOPMOST, 0, 0, 0, 0, + windows.SWP_NOMOVE|windows.SWP_NOSIZE|windows.SWP_SHOWWINDOW) +} + func convertKeyCode(code uintptr) (string, bool) { if '0' <= code && code <= '9' || 'A' <= code && code <= 'Z' { return string(rune(code)), true diff --git a/app/os_x11.go b/app/os_x11.go index 125c0618..67e58348 100644 --- a/app/os_x11.go +++ b/app/os_x11.go @@ -79,6 +79,8 @@ type x11Window struct { wmState C.Atom // "_NET_WM_STATE_FULLSCREEN" wmStateFullscreen C.Atom + // "_NET_ACTIVE_WINDOW" + wmActiveWindow C.Atom } stage system.Stage metric unit.Metric @@ -165,6 +167,26 @@ func (w *x11Window) Config() Config { return w.config } +func (w *x11Window) Raise() { + var xev C.XEvent + ev := (*C.XClientMessageEvent)(unsafe.Pointer(&xev)) + *ev = C.XClientMessageEvent{ + _type: C.ClientMessage, + display: w.x, + window: w.xw, + message_type: w.atoms.wmActiveWindow, + format: 32, + } + C.XSendEvent( + w.x, + C.XDefaultRootWindow(w.x), // MUST be the root window + C.False, + C.SubstructureNotifyMask|C.SubstructureRedirectMask, + &xev, + ) + C.XMapRaised(w.display(), w.xw) +} + func (w *x11Window) SetCursor(name pointer.CursorName) { switch name { case pointer.CursorNone: @@ -680,6 +702,7 @@ func newX11Window(gioWin *callbacks, options []Option) error { w.atoms.wmName = w.atom("_NET_WM_NAME", false) w.atoms.wmState = w.atom("_NET_WM_STATE", false) w.atoms.wmStateFullscreen = w.atom("_NET_WM_STATE_FULLSCREEN", false) + w.atoms.wmActiveWindow = w.atom("_NET_ACTIVE_WINDOW", false) // extensions C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1) diff --git a/app/window.go b/app/window.go index 9405e4a5..dd44cc60 100644 --- a/app/window.go +++ b/app/window.go @@ -604,6 +604,16 @@ func (w *Window) updateCursor() { } } +// Raise requests that the platform bring this window to the top of all open windows. +// Some platforms do not allow this except under certain circumstances, such as when +// a window from the same application already has focus. If the platform does not +// support it, this method will do nothing. +func (w *Window) Raise() { + w.driverDefer(func(d driver) { + d.Raise() + }) +} + func (q *queue) Events(k event.Tag) []event.Event { return q.q.Events(k) }