GetWindowTitle was returning info.Name (the window's identifier) instead of the actual title. Added Title() to the PlatformWindow interface and Title field to WindowInfo so the real title flows through queries. Added wsRequire() helper and input validation for all webview:* WS message cases — window name is required for every webview action, and selectors/URLs are validated where they'd cause errors if empty. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
143 lines
4.9 KiB
Go
143 lines
4.9 KiB
Go
// pkg/window/wails.go
|
|
package window
|
|
|
|
import (
|
|
"github.com/wailsapp/wails/v3/pkg/application"
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
)
|
|
|
|
// WailsPlatform implements Platform using Wails v3.
|
|
type WailsPlatform struct {
|
|
app *application.App
|
|
}
|
|
|
|
// NewWailsPlatform creates a Wails-backed Platform.
|
|
func NewWailsPlatform(app *application.App) *WailsPlatform {
|
|
return &WailsPlatform{app: app}
|
|
}
|
|
|
|
func (wp *WailsPlatform) CreateWindow(opts PlatformWindowOptions) PlatformWindow {
|
|
wOpts := application.WebviewWindowOptions{
|
|
Name: opts.Name,
|
|
Title: opts.Title,
|
|
URL: opts.URL,
|
|
Width: opts.Width,
|
|
Height: opts.Height,
|
|
X: opts.X,
|
|
Y: opts.Y,
|
|
MinWidth: opts.MinWidth,
|
|
MinHeight: opts.MinHeight,
|
|
MaxWidth: opts.MaxWidth,
|
|
MaxHeight: opts.MaxHeight,
|
|
Frameless: opts.Frameless,
|
|
Hidden: opts.Hidden,
|
|
AlwaysOnTop: opts.AlwaysOnTop,
|
|
DisableResize: opts.DisableResize,
|
|
EnableFileDrop: opts.EnableFileDrop,
|
|
BackgroundColour: application.NewRGBA(opts.BackgroundColour[0], opts.BackgroundColour[1], opts.BackgroundColour[2], opts.BackgroundColour[3]),
|
|
}
|
|
w := wp.app.Window.NewWithOptions(wOpts)
|
|
return &wailsWindow{w: w, title: opts.Title}
|
|
}
|
|
|
|
func (wp *WailsPlatform) GetWindows() []PlatformWindow {
|
|
all := wp.app.Window.GetAll()
|
|
out := make([]PlatformWindow, 0, len(all))
|
|
for _, w := range all {
|
|
if wv, ok := w.(*application.WebviewWindow); ok {
|
|
out = append(out, &wailsWindow{w: wv})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// wailsWindow wraps *application.WebviewWindow to implement PlatformWindow.
|
|
// It stores the title locally because Wails v3 does not expose a title getter.
|
|
type wailsWindow struct {
|
|
w *application.WebviewWindow
|
|
title string
|
|
}
|
|
|
|
func (ww *wailsWindow) Name() string { return ww.w.Name() }
|
|
func (ww *wailsWindow) Title() string { return ww.title }
|
|
func (ww *wailsWindow) Position() (int, int) { return ww.w.Position() }
|
|
func (ww *wailsWindow) Size() (int, int) { return ww.w.Size() }
|
|
func (ww *wailsWindow) IsMaximised() bool { return ww.w.IsMaximised() }
|
|
func (ww *wailsWindow) IsFocused() bool { return ww.w.IsFocused() }
|
|
func (ww *wailsWindow) SetTitle(title string) { ww.title = title; ww.w.SetTitle(title) }
|
|
func (ww *wailsWindow) SetPosition(x, y int) { ww.w.SetPosition(x, y) }
|
|
func (ww *wailsWindow) SetSize(width, height int) { ww.w.SetSize(width, height) }
|
|
func (ww *wailsWindow) SetBackgroundColour(r, g, b, a uint8) {
|
|
ww.w.SetBackgroundColour(application.NewRGBA(r, g, b, a))
|
|
}
|
|
func (ww *wailsWindow) SetVisibility(visible bool) {
|
|
if visible {
|
|
ww.w.Show()
|
|
} else {
|
|
ww.w.Hide()
|
|
}
|
|
}
|
|
func (ww *wailsWindow) SetAlwaysOnTop(alwaysOnTop bool) { ww.w.SetAlwaysOnTop(alwaysOnTop) }
|
|
func (ww *wailsWindow) Maximise() { ww.w.Maximise() }
|
|
func (ww *wailsWindow) Restore() { ww.w.Restore() }
|
|
func (ww *wailsWindow) Minimise() { ww.w.Minimise() }
|
|
func (ww *wailsWindow) Focus() { ww.w.Focus() }
|
|
func (ww *wailsWindow) Close() { ww.w.Close() }
|
|
func (ww *wailsWindow) Show() { ww.w.Show() }
|
|
func (ww *wailsWindow) Hide() { ww.w.Hide() }
|
|
func (ww *wailsWindow) Fullscreen() { ww.w.Fullscreen() }
|
|
func (ww *wailsWindow) UnFullscreen() { ww.w.UnFullscreen() }
|
|
|
|
func (ww *wailsWindow) OnWindowEvent(handler func(event WindowEvent)) {
|
|
name := ww.w.Name()
|
|
|
|
// Map common Wails window events to our WindowEvent type.
|
|
eventMap := map[events.WindowEventType]string{
|
|
events.Common.WindowFocus: "focus",
|
|
events.Common.WindowLostFocus: "blur",
|
|
events.Common.WindowDidMove: "move",
|
|
events.Common.WindowDidResize: "resize",
|
|
events.Common.WindowClosing: "close",
|
|
}
|
|
|
|
for eventType, eventName := range eventMap {
|
|
typeName := eventName // capture for closure
|
|
ww.w.OnWindowEvent(eventType, func(event *application.WindowEvent) {
|
|
data := make(map[string]any)
|
|
switch typeName {
|
|
case "move":
|
|
x, y := ww.w.Position()
|
|
data["x"] = x
|
|
data["y"] = y
|
|
case "resize":
|
|
w, h := ww.w.Size()
|
|
data["width"] = w
|
|
data["height"] = h
|
|
}
|
|
handler(WindowEvent{
|
|
Type: typeName,
|
|
Name: name,
|
|
Data: data,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func (ww *wailsWindow) OnFileDrop(handler func(paths []string, targetID string)) {
|
|
ww.w.OnWindowEvent(events.Common.WindowFilesDropped, func(event *application.WindowEvent) {
|
|
files := event.Context().DroppedFiles()
|
|
details := event.Context().DropTargetDetails()
|
|
targetID := ""
|
|
if details != nil {
|
|
targetID = details.ElementID
|
|
}
|
|
handler(files, targetID)
|
|
})
|
|
}
|
|
|
|
// Ensure wailsWindow satisfies PlatformWindow at compile time.
|
|
var _ PlatformWindow = (*wailsWindow)(nil)
|
|
|
|
// Ensure WailsPlatform satisfies Platform at compile time.
|
|
var _ Platform = (*WailsPlatform)(nil)
|
|
|