5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-19 02:19:31 +08:00

[windows] Add support for click-through overlay window (#3667)

* [windows] Add support for click-through overlay window

* update changelog

* setIgnoreMouseEvents - exemple

* fix - remove unused import

* Add macOS+Linux support. Update example.

* Fix SetIgnoreMouseEvents before window created.

---------

Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
This commit is contained in:
bruxaodev 2024-08-18 07:50:22 -03:00 committed by GitHub
parent 96b97b25bf
commit fbcce0b20c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 152 additions and 34 deletions

View File

@ -22,8 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## v3.0.0-alpha.6 - 2024-07-30 ## v3.0.0-alpha.6 - 2024-07-30
### Fixed ### Fixed
- Module issues - Module issues
## v3.0.0-alpha.5 - 2024-07-30 ## v3.0.0-alpha.5 - 2024-07-30
@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Implement `setIcon` on linux by [@abichinger](https://github.com/abichinger) in [#3354](https://github.com/wailsapp/wails/pull/3354) - Implement `setIcon` on linux by [@abichinger](https://github.com/abichinger) in [#3354](https://github.com/wailsapp/wails/pull/3354)
- Add flag `-port` to dev command and support environment variable `WAILS_VITE_PORT` by [@abichinger](https://github.com/abichinger) in [#3429](https://github.com/wailsapp/wails/pull/3429) - Add flag `-port` to dev command and support environment variable `WAILS_VITE_PORT` by [@abichinger](https://github.com/abichinger) in [#3429](https://github.com/wailsapp/wails/pull/3429)
- Add tests for bound method calls by [@abichinger](https://github.com/abichinger) in [#3431](https://github.com/wailsapp/wails/pull/3431) - Add tests for bound method calls by [@abichinger](https://github.com/abichinger) in [#3431](https://github.com/wailsapp/wails/pull/3431)
- [windows] add `SetIgnoreMouseEvents` for already created window by [@bruxaodev](https://github.com/bruxaodev) in [#3667](https://github.com/wailsapp/wails/pull/3667)
### Fixed ### Fixed

View File

@ -0,0 +1,19 @@
# Window Example
This example is a demonstration of how to disable or enable mouse events.
## Running the example
To run the example, simply run the following command:
```bash
go run .
```
# Status
| Platform | Status |
|----------|---------|
| Mac | |
| Windows | Working |
| Linux | |

View File

@ -0,0 +1,36 @@
package main
import (
"log"
"github.com/wailsapp/wails/v3/pkg/application"
)
func main() {
app := application.New(application.Options{
Name: "WebviewWindow Demo",
Description: "A demo of the WebviewWindow API",
Assets: application.AlphaAssets,
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: false,
},
})
window := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Width: 800,
Height: 600,
Title: "Ignore Mouse Example",
URL: "https://wails.io",
IgnoreMouseEvents: false,
})
window.SetIgnoreMouseEvents(true)
log.Println("IgnoreMouseEvents set", window.IsIgnoreMouseEvents())
err := app.Run()
if err != nil {
log.Fatal(err)
}
}

View File

@ -217,7 +217,7 @@ func main() {
Show() Show()
windowCounter++ windowCounter++
}) })
myMenu.Add("New Frameless WebviewWindow"). myMenu.Add("New WebviewWindow (Frameless)").
SetAccelerator("CmdOrCtrl+F"). SetAccelerator("CmdOrCtrl+F").
OnClick(func(ctx *application.Context) { OnClick(func(ctx *application.Context) {
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
@ -231,23 +231,21 @@ func main() {
}).Show() }).Show()
windowCounter++ windowCounter++
}) })
if runtime.GOOS != "linux" { myMenu.Add("New WebviewWindow (Ignores mouse events)").
myMenu.Add("New WebviewWindow (ignores mouse events)"). SetAccelerator("CmdOrCtrl+F").
SetAccelerator("CmdOrCtrl+F"). OnClick(func(ctx *application.Context) {
OnClick(func(ctx *application.Context) { app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ HTML: "<div style='width: 100%; height: 95%; border: 3px solid red; background-color: \"0000\";'></div>",
HTML: "<div style='width: 100%; height: 95%; border: 3px solid red; background-color: \"0000\";'></div>", X: rand.Intn(1000),
X: rand.Intn(1000), Y: rand.Intn(800),
Y: rand.Intn(800), IgnoreMouseEvents: true,
IgnoreMouseEvents: true, BackgroundType: application.BackgroundTypeTransparent,
BackgroundType: application.BackgroundTypeTransparent, Mac: application.MacWindow{
Mac: application.MacWindow{ InvisibleTitleBarHeight: 50,
InvisibleTitleBarHeight: 50, },
}, }).Show()
}).Show() windowCounter++
windowCounter++ })
})
}
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)"). myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
OnClick(func(ctx *application.Context) { OnClick(func(ctx *application.Context) {

View File

@ -90,6 +90,8 @@ type (
setMinimiseButtonState(state ButtonState) setMinimiseButtonState(state ButtonState)
setMaximiseButtonState(state ButtonState) setMaximiseButtonState(state ButtonState)
setCloseButtonState(state ButtonState) setCloseButtonState(state ButtonState)
isIgnoreMouseEvents() bool
setIgnoreMouseEvents(ignore bool)
} }
) )
@ -1232,3 +1234,21 @@ func (w *WebviewWindow) addMenuBinding(a *accelerator, menuItem *MenuItem) {
defer w.menuBindingsLock.Unlock() defer w.menuBindingsLock.Unlock()
w.menuBindings[a.String()] = menuItem w.menuBindings[a.String()] = menuItem
} }
func (w *WebviewWindow) IsIgnoreMouseEvents() bool {
if w.impl == nil && !w.isDestroyed() {
return false
}
return InvokeSyncWithResult(w.impl.isIgnoreMouseEvents)
}
func (w *WebviewWindow) SetIgnoreMouseEvents(ignore bool) Window {
w.options.IgnoreMouseEvents = ignore
if w.impl == nil && !w.isDestroyed() {
return w
}
InvokeSync(func() {
w.impl.setIgnoreMouseEvents(ignore)
})
return w
}

View File

@ -689,12 +689,6 @@ static void windowShowMenu(void *window, void *menu, int x, int y) {
[nsMenu popUpMenuPositioningItem:nil atLocation:point inView:webView]; [nsMenu popUpMenuPositioningItem:nil atLocation:point inView:webView];
} }
// windowIgnoreMouseEvents makes the window ignore mouse events
static void windowIgnoreMouseEvents(void *window, bool ignore) {
WebviewWindow* nsWindow = (WebviewWindow*)window;
[nsWindow setIgnoresMouseEvents:ignore];
}
// Make the given window frameless // Make the given window frameless
static void windowSetFrameless(void *window, bool frameless) { static void windowSetFrameless(void *window, bool frameless) {
WebviewWindow* nsWindow = (WebviewWindow*)window; WebviewWindow* nsWindow = (WebviewWindow*)window;
@ -772,6 +766,16 @@ void windowFocus(void *window) {
[nsWindow makeKeyWindow]; [nsWindow makeKeyWindow];
} }
static bool isIgnoreMouseEvents(void *nsWindow) {
NSWindow *window = (__bridge NSWindow *)nsWindow;
return [window ignoresMouseEvents];
}
static void setIgnoreMouseEvents(void *nsWindow, bool ignore) {
NSWindow *window = (__bridge NSWindow *)nsWindow;
[window setIgnoresMouseEvents:ignore];
}
*/ */
import "C" import "C"
import ( import (
@ -1159,9 +1163,8 @@ func (w *macosWebviewWindow) run() {
w.setMaximiseButtonState(options.MaximiseButtonState) w.setMaximiseButtonState(options.MaximiseButtonState)
w.setCloseButtonState(options.CloseButtonState) w.setCloseButtonState(options.CloseButtonState)
if options.IgnoreMouseEvents { // Ignore mouse events if requested
C.windowIgnoreMouseEvents(w.nsWindow, C.bool(true)) w.setIgnoreMouseEvents(options.IgnoreMouseEvents)
}
titleBarOptions := macOptions.TitleBar titleBarOptions := macOptions.TitleBar
if !w.parent.options.Frameless { if !w.parent.options.Frameless {
@ -1302,3 +1305,11 @@ func (w *macosWebviewWindow) setMaximiseButtonState(state ButtonState) {
func (w *macosWebviewWindow) setCloseButtonState(state ButtonState) { func (w *macosWebviewWindow) setCloseButtonState(state ButtonState) {
C.setCloseButtonState(w.nsWindow, C.int(state)) C.setCloseButtonState(w.nsWindow, C.int(state))
} }
func (w *macosWebviewWindow) isIgnoreMouseEvents() bool {
return bool(C.isIgnoreMouseEvents(w.nsWindow))
}
func (w *macosWebviewWindow) setIgnoreMouseEvents(ignore bool) {
C.setIgnoreMouseEvents(w.nsWindow, C.bool(ignore))
}

View File

@ -42,8 +42,9 @@ type linuxWebviewWindow struct {
gtkmenu pointer gtkmenu pointer
ctxMenuOpened bool ctxMenuOpened bool
moveDebouncer func(func()) moveDebouncer func(func())
resizeDebouncer func(func()) resizeDebouncer func(func())
ignoreMouseEvents bool
} }
var ( var (
@ -280,9 +281,8 @@ func (w *linuxWebviewWindow) run() {
case WindowStateNormal: case WindowStateNormal:
} }
//if w.parent.options.IgnoreMouseEvents { // Ignore mouse events if requested
// windowIgnoreMouseEvents(w.window, w.webview, true) w.setIgnoreMouseEvents(options.IgnoreMouseEvents)
//}
startURL, err := assetserver.GetStartURL(w.parent.options.URL) startURL, err := assetserver.GetStartURL(w.parent.options.URL)
if err != nil { if err != nil {
@ -369,3 +369,17 @@ func (w *linuxWebviewWindow) setMaximiseButtonState(state ButtonState) {}
// SetCloseButtonState is unsupported on Linux // SetCloseButtonState is unsupported on Linux
func (w *linuxWebviewWindow) setCloseButtonState(state ButtonState) {} func (w *linuxWebviewWindow) setCloseButtonState(state ButtonState) {}
func (w *linuxWebviewWindow) isIgnoreMouseEvents() bool {
return w.ignoreMouseEvents
}
func (w *linuxWebviewWindow) setIgnoreMouseEvents(ignore bool) {
w.ignoreMouseEvents = ignore
if ignore {
C.gtk_widget_set_events((*C.GtkWidget)(unsafe.Pointer(w.window)), C.GDK_ENTER_NOTIFY_MASK|C.GDK_LEAVE_NOTIFY_MASK)
} else {
C.gtk_widget_set_events((*C.GtkWidget)(unsafe.Pointer(w.window)), C.GDK_ALL_EVENTS_MASK)
}
}

View File

@ -279,6 +279,8 @@ func (w *windowsWebviewWindow) run() {
w.setResizable(!options.DisableResize) w.setResizable(!options.DisableResize)
w.setIgnoreMouseEvents(options.IgnoreMouseEvents)
if options.Frameless { if options.Frameless {
// Inform the application of the frame change this is needed to trigger the WM_NCCALCSIZE event. // Inform the application of the frame change this is needed to trigger the WM_NCCALCSIZE event.
// => https://learn.microsoft.com/en-us/windows/win32/dwm/customframe#removing-the-standard-frame // => https://learn.microsoft.com/en-us/windows/win32/dwm/customframe#removing-the-standard-frame
@ -1761,3 +1763,18 @@ func (w *windowsWebviewWindow) setCloseButtonState(state ButtonState) {
func (w *windowsWebviewWindow) setGWLStyle(style int) { func (w *windowsWebviewWindow) setGWLStyle(style int) {
w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, uint32(style)) w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, uint32(style))
} }
func (w *windowsWebviewWindow) isIgnoreMouseEvents() bool {
exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
return exStyle&w32.WS_EX_TRANSPARENT != 0
}
func (w *windowsWebviewWindow) setIgnoreMouseEvents(ignore bool) {
exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
if ignore {
exStyle |= w32.WS_EX_LAYERED | w32.WS_EX_TRANSPARENT
} else {
exStyle &^= w32.WS_EX_TRANSPARENT
}
w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle))
}

View File

@ -36,6 +36,7 @@ type Window interface {
Info(message string, args ...any) Info(message string, args ...any)
IsFocused() bool IsFocused() bool
IsFullscreen() bool IsFullscreen() bool
IsIgnoreMouseEvents() bool
IsMaximised() bool IsMaximised() bool
IsMinimised() bool IsMinimised() bool
HandleKeyEvent(acceleratorString string) HandleKeyEvent(acceleratorString string)
@ -63,6 +64,7 @@ type Window interface {
SetMinSize(minWidth, minHeight int) Window SetMinSize(minWidth, minHeight int) Window
SetRelativePosition(x, y int) Window SetRelativePosition(x, y int) Window
SetResizable(b bool) Window SetResizable(b bool) Window
SetIgnoreMouseEvents(ignore bool) Window
SetSize(width, height int) Window SetSize(width, height int) Window
SetTitle(title string) Window SetTitle(title string) Window
SetURL(s string) Window SetURL(s string) Window