feature: V3 alpha feature/snapassist support (#4463)

* initial implementation

* Push missed files

* linux fix

* Update changelog, runtime and docs.
This commit is contained in:
Lea Anthony 2025-08-02 16:59:49 +10:00 committed by GitHub
commit 55277fd695
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 111 additions and 1 deletions

View file

@ -171,6 +171,37 @@ type Window interface {
}
```
### Common Window Methods
Windows provide many methods for controlling their appearance and behavior:
#### Display Control
- `Show()` - Shows the window
- `Hide()` - Hides the window
- `SetTitle(title string)` - Sets the window title
- `SetSize(width, height int)` - Sets the window size
- `SetPosition(x, y int)` - Sets the window position
- `Center()` - Centers the window on screen
- `SetAlwaysOnTop(bool)` - Sets whether window stays on top
#### Window State
- `Minimise()` - Minimizes the window
- `Maximise()` - Maximizes the window
- `UnMinimise()` - Restores from minimized state
- `UnMaximise()` - Restores from maximized state
- `Fullscreen()` - Enters fullscreen mode
- `UnFullscreen()` - Exits fullscreen mode
- `Restore()` - Restores window to normal state
- `IsMinimised() bool` - Checks if window is minimized
- `IsMaximised() bool` - Checks if window is maximized
- `IsFullscreen() bool` - Checks if window is fullscreen
#### Platform-Specific Methods
**Windows Only:**
- `Flash(bool)` - Flashes the taskbar button
- `SnapAssist()` - Triggers Windows 11 Snap Assist (Win+Z)
## Advanced Window Management
### Multi-Window Applications
@ -235,9 +266,18 @@ app.Event.On("data-updated", func(event *application.CustomEvent) {
- Support custom window icons
- Can be configured without system title bars
- Follow Windows window management conventions
- Support Windows 11 snap layouts
- Support Windows 11 snap layouts via `SnapAssist()` method
- Integrate with Windows taskbar features
**Windows 11 Snap Assist Example:**
```go
// Trigger Windows 11 Snap Assist
window.SnapAssist()
// This is equivalent to pressing Win+Z
// Shows snap layout options for the current window
```
</TabItem>
<TabItem label="Linux" icon="fa-brands:linux">

View file

@ -17,6 +17,7 @@ After processing, the content will be moved to the main changelog and this file
### Added
- Added Run go mod tidy automatically after wails init [@triadmoko](https://github.com/triadmoko) in [PR](https://github.com/wailsapp/wails/pull/4286)
- Windows Snapassist feature by @leaanthony in [PR](https://github.dev/wailsapp/wails/pull/4463)
## Changed
<!-- Changes in existing functionality -->

View file

@ -713,6 +713,14 @@ func main() {
})
}
if runtime.GOOS == "windows" {
stateMenu.Add("Snap Assist").OnClick(func(ctx *application.Context) {
currentWindow(func(w *application.WebviewWindow) {
w.SnapAssist()
})
})
}
printMenu := menu.AddSubmenu("Print")
printMenu.Add("Print").OnClick(func(ctx *application.Context) {
currentWindow(func(w *application.WebviewWindow) {

View file

@ -60,6 +60,7 @@ const ZoomMethod = 45;
const ZoomInMethod = 46;
const ZoomOutMethod = 47;
const ZoomResetMethod = 48;
const SnapAssistMethod = 49;
/**
* A record describing the position of a window.
@ -518,6 +519,14 @@ class Window {
ZoomReset(): Promise<void> {
return this[callerSym](ZoomResetMethod);
}
/**
* Triggers Windows 11 Snap Assist feature (Windows only).
* This is equivalent to pressing Win+Z and shows snap layout options.
*/
SnapAssist(): Promise<void> {
return this[callerSym](SnapAssistMethod);
}
}
/**

View file

@ -56,6 +56,7 @@ const (
WindowZoomIn = 46
WindowZoomOut = 47
WindowZoomReset = 48
WindowSnapAssist = 49
)
var windowMethodNames = map[int]string{
@ -108,6 +109,7 @@ var windowMethodNames = map[int]string{
WindowZoomIn: "ZoomIn",
WindowZoomOut: "ZoomOut",
WindowZoomReset: "ZoomReset",
WindowSnapAssist: "SnapAssist",
}
func (m *MessageProcessor) processWindowMethod(
@ -421,6 +423,9 @@ func (m *MessageProcessor) processWindowMethod(
case WindowZoomReset:
window.ZoomReset()
m.ok(rw)
case WindowSnapAssist:
window.SnapAssist()
m.ok(rw)
default:
m.httpError(rw, "Invalid window call:", fmt.Errorf("unknown method %d", method))
return

View file

@ -110,6 +110,7 @@ type (
hideMenuBar()
toggleMenuBar()
setMenu(menu *Menu)
snapAssist()
}
)
@ -1428,3 +1429,12 @@ func (w *WebviewWindow) ToggleMenuBar() {
}
InvokeSync(w.impl.toggleMenuBar)
}
// SnapAssist triggers the Windows Snap Assist feature by simulating Win+Z key combination.
// On Windows, this opens the snap layout options. On Linux and macOS, this is a no-op.
func (w *WebviewWindow) SnapAssist() {
if w.impl == nil || w.isDestroyed() {
return
}
InvokeSync(w.impl.snapAssist)
}

View file

@ -1438,3 +1438,4 @@ func (w *macosWebviewWindow) showMenuBar() {}
func (w *macosWebviewWindow) hideMenuBar() {}
func (w *macosWebviewWindow) toggleMenuBar() {}
func (w *macosWebviewWindow) setMenu(_ *Menu) {}
func (w *macosWebviewWindow) snapAssist() {} // No-op on macOS

View file

@ -427,3 +427,4 @@ func (w *linuxWebviewWindow) hide() {
func (w *linuxWebviewWindow) showMenuBar() {}
func (w *linuxWebviewWindow) hideMenuBar() {}
func (w *linuxWebviewWindow) toggleMenuBar() {}
func (w *linuxWebviewWindow) snapAssist() {} // No-op on Linux

View file

@ -2281,3 +2281,15 @@ func (w *windowsWebviewWindow) hideMenuBar() {
w32.SetMenu(w.hwnd, 0)
}
}
func (w *windowsWebviewWindow) snapAssist() {
// Simulate Win+Z key combination to trigger Snap Assist
// Press Windows key
w32.KeybdEvent(byte(w32.VK_LWIN), 0, 0, 0)
// Press Z key
w32.KeybdEvent(byte('Z'), 0, 0, 0)
// Release Z key
w32.KeybdEvent(byte('Z'), 0, w32.KEYEVENTF_KEYUP, 0)
// Release Windows key
w32.KeybdEvent(byte(w32.VK_LWIN), 0, w32.KEYEVENTF_KEYUP, 0)
}

View file

@ -86,4 +86,5 @@ type Window interface {
ZoomOut()
ZoomReset() Window
SetMenu(menu *Menu)
SnapAssist()
}

View file

@ -2900,6 +2900,13 @@ const (
INPUT_HARDWARE = 2
)
const (
KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP = 0x0002
KEYEVENTF_SCANCODE = 0x0008
KEYEVENTF_UNICODE = 0x0004
)
const (
MOUSEEVENTF_ABSOLUTE = 0x8000
MOUSEEVENTF_HWHEEL = 0x01000

View file

@ -149,6 +149,7 @@ var (
procChangeDisplaySettingsEx = moduser32.NewProc("ChangeDisplaySettingsExW")
procSetTimer = moduser32.NewProc("SetTimer")
procKillTimer = moduser32.NewProc("KillTimer")
procKeybdEvent = moduser32.NewProc("keybd_event")
procSendInput = moduser32.NewProc("SendInput")
procSetWindowsHookEx = moduser32.NewProc("SetWindowsHookExW")
procUnhookWindowsHookEx = moduser32.NewProc("UnhookWindowsHookEx")
@ -1492,3 +1493,17 @@ func TrackPopupMenu(hmenu HMENU, flags uint32, x, y int32, reserved int32, hwnd
uintptr(unsafe.Pointer(prcRect)))
return ret != 0
}
// KeybdEvent synthesizes a keystroke. The system can use such a synthesized keystroke to generate a WM_KEYUP or WM_KEYDOWN message.
// bVk: Virtual-key code
// bScan: Hardware scan code
// dwFlags: Controls various aspects of function operation (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)
// dwExtraInfo: Additional value associated with the keystroke
func KeybdEvent(bVk byte, bScan byte, dwFlags uint32, dwExtraInfo uintptr) {
procKeybdEvent.Call(
uintptr(bVk),
uintptr(bScan),
uintptr(dwFlags),
dwExtraInfo,
)
}