Some checks failed
Security Scan / security (push) Failing after 24s
Rebuilt from scratch on current dev (post-fleet AX passes). Stub files: - application.go (expanded App with 12 managers, WebviewWindow satisfies Window) - application_options.go (Options, Mac/Win/Linux/iOS/Android, Server, TLS, Assets) - browser_manager.go, browser_window.go (~47 no-op methods) - clipboard.go, context_menu.go, dialog.go (full dialog builder API) - environment.go, events.go (EventManager with On/Off/Emit/Reset) - keybinding.go, menuitem.go (42 Role constants) - screen.go (Rect/Point/Size geometry), services.go (generic Service[T]) - webview_window_options.go (full platform types) - window.go (Window interface ~50 methods) Wails v3 submodule at internal/wails3/ pinned to alpha 74. All 16 gui packages build and test clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
778 lines
20 KiB
Go
778 lines
20 KiB
Go
package application
|
|
|
|
import (
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
)
|
|
|
|
// Context mirrors the callback context type exposed by Wails.
|
|
//
|
|
// item.OnClick(func(ctx *Context) { openPrefs() })
|
|
type Context struct {
|
|
clickedMenuItem *MenuItem
|
|
contextMenuData *ContextMenuData
|
|
checked bool
|
|
}
|
|
|
|
func newContext() *Context { return &Context{} }
|
|
|
|
func (ctx *Context) withClickedMenuItem(item *MenuItem) *Context {
|
|
ctx.clickedMenuItem = item
|
|
return ctx
|
|
}
|
|
|
|
func (ctx *Context) withContextMenuData(data *ContextMenuData) *Context {
|
|
ctx.contextMenuData = data
|
|
return ctx
|
|
}
|
|
|
|
func (ctx *Context) withChecked(checked bool) *Context {
|
|
ctx.checked = checked
|
|
return ctx
|
|
}
|
|
|
|
// Logger is a minimal logger surface used by the GUI packages.
|
|
type Logger struct{}
|
|
|
|
func (l Logger) Info(message string, args ...any) {}
|
|
|
|
// RGBA stores a colour with alpha.
|
|
//
|
|
// colour := NewRGBA(255, 128, 0, 255) // opaque orange
|
|
type RGBA struct {
|
|
Red, Green, Blue, Alpha uint8
|
|
}
|
|
|
|
// NewRGBA constructs an RGBA value.
|
|
//
|
|
// colour := NewRGBA(255, 128, 0, 255) // opaque orange
|
|
func NewRGBA(red, green, blue, alpha uint8) RGBA {
|
|
return RGBA{Red: red, Green: green, Blue: blue, Alpha: alpha}
|
|
}
|
|
|
|
// Menu is a menu tree used by the GUI wrappers.
|
|
//
|
|
// menu := NewMenu()
|
|
// menu.Add("Save").SetAccelerator("CmdOrCtrl+S").OnClick(func(ctx *Context) { save() })
|
|
type Menu struct {
|
|
label string
|
|
Items []*MenuItem
|
|
}
|
|
|
|
// NewMenu creates a new, empty Menu.
|
|
//
|
|
// menu := NewMenu()
|
|
func NewMenu() *Menu { return &Menu{} }
|
|
|
|
// Add appends a new text item with the given label.
|
|
func (m *Menu) Add(label string) *MenuItem {
|
|
item := NewMenuItem(label)
|
|
item.disabled = false
|
|
m.Items = append(m.Items, item)
|
|
return item
|
|
}
|
|
|
|
// AddSeparator appends a separator item.
|
|
func (m *Menu) AddSeparator() {
|
|
m.Items = append(m.Items, NewMenuItemSeparator())
|
|
}
|
|
|
|
// AddSubmenu appends a submenu item and returns the child Menu.
|
|
func (m *Menu) AddSubmenu(label string) *Menu {
|
|
item := NewSubMenuItem(label)
|
|
m.Items = append(m.Items, item)
|
|
return item.submenu
|
|
}
|
|
|
|
// AddRole appends a platform-role item.
|
|
func (m *Menu) AddRole(role Role) {
|
|
m.Items = append(m.Items, NewRole(role))
|
|
}
|
|
|
|
// AppendItem appends an already-constructed MenuItem.
|
|
func (m *Menu) AppendItem(item *MenuItem) {
|
|
m.Items = append(m.Items, item)
|
|
}
|
|
|
|
// Clone returns a deep copy of the menu tree.
|
|
func (m *Menu) Clone() *Menu {
|
|
cloned := &Menu{label: m.label}
|
|
for _, item := range m.Items {
|
|
cloned.Items = append(cloned.Items, item.Clone())
|
|
}
|
|
return cloned
|
|
}
|
|
|
|
// Destroy frees all items in the menu.
|
|
func (m *Menu) Destroy() {
|
|
for _, item := range m.Items {
|
|
item.Destroy()
|
|
}
|
|
m.Items = nil
|
|
}
|
|
|
|
func (m *Menu) setContextData(data *ContextMenuData) {
|
|
for _, item := range m.Items {
|
|
item.contextMenuData = data
|
|
if item.submenu != nil {
|
|
item.submenu.setContextData(data)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MenuManager owns the application menu.
|
|
//
|
|
// app.Menu.SetApplicationMenu(menu)
|
|
type MenuManager struct {
|
|
applicationMenu *Menu
|
|
}
|
|
|
|
func (m *MenuManager) SetApplicationMenu(menu *Menu) { m.applicationMenu = menu }
|
|
|
|
// SystemTray represents a tray instance.
|
|
type SystemTray struct {
|
|
icon []byte
|
|
templateIcon []byte
|
|
tooltip string
|
|
label string
|
|
menu *Menu
|
|
attachedWindow Window
|
|
}
|
|
|
|
func (t *SystemTray) SetIcon(data []byte) { t.icon = append([]byte(nil), data...) }
|
|
func (t *SystemTray) SetTemplateIcon(data []byte) { t.templateIcon = append([]byte(nil), data...) }
|
|
func (t *SystemTray) SetTooltip(text string) { t.tooltip = text }
|
|
func (t *SystemTray) SetLabel(text string) { t.label = text }
|
|
func (t *SystemTray) SetMenu(menu *Menu) { t.menu = menu }
|
|
|
|
// AttachWindow associates a window with the tray icon (shown on click).
|
|
func (t *SystemTray) AttachWindow(w Window) { t.attachedWindow = w }
|
|
|
|
// SystemTrayManager creates tray instances.
|
|
type SystemTrayManager struct{}
|
|
|
|
func (m *SystemTrayManager) New() *SystemTray { return &SystemTray{} }
|
|
|
|
// WindowEventContext carries drag-and-drop details for a window event.
|
|
type WindowEventContext struct {
|
|
droppedFiles []string
|
|
dropDetails *DropTargetDetails
|
|
}
|
|
|
|
func (c *WindowEventContext) DroppedFiles() []string {
|
|
return append([]string(nil), c.droppedFiles...)
|
|
}
|
|
|
|
func (c *WindowEventContext) DropTargetDetails() *DropTargetDetails {
|
|
if c.dropDetails == nil {
|
|
return nil
|
|
}
|
|
details := *c.dropDetails
|
|
return &details
|
|
}
|
|
|
|
// DropTargetDetails mirrors the fields consumed by the GUI wrappers.
|
|
type DropTargetDetails struct {
|
|
ElementID string
|
|
}
|
|
|
|
// WindowEvent mirrors the event object passed to window callbacks.
|
|
type WindowEvent struct {
|
|
ctx *WindowEventContext
|
|
}
|
|
|
|
func (e *WindowEvent) Context() *WindowEventContext {
|
|
if e.ctx == nil {
|
|
e.ctx = &WindowEventContext{}
|
|
}
|
|
return e.ctx
|
|
}
|
|
|
|
// WebviewWindow is a lightweight, in-memory window implementation
|
|
// that satisfies the Window interface.
|
|
type WebviewWindow struct {
|
|
mu sync.RWMutex
|
|
opts WebviewWindowOptions
|
|
windowID uint
|
|
title string
|
|
posX, posY int
|
|
sizeW, sizeH int
|
|
maximised bool
|
|
focused bool
|
|
visible bool
|
|
alwaysOnTop bool
|
|
isFullscreen bool
|
|
closed bool
|
|
zoom float64
|
|
resizable bool
|
|
ignoreMouseEvents bool
|
|
enabled bool
|
|
eventHandlers map[events.WindowEventType][]func(*WindowEvent)
|
|
}
|
|
|
|
var globalWindowID uint
|
|
var globalWindowIDMu sync.Mutex
|
|
|
|
func nextWindowID() uint {
|
|
globalWindowIDMu.Lock()
|
|
defer globalWindowIDMu.Unlock()
|
|
globalWindowID++
|
|
return globalWindowID
|
|
}
|
|
|
|
func newWebviewWindow(options WebviewWindowOptions) *WebviewWindow {
|
|
return &WebviewWindow{
|
|
opts: options,
|
|
windowID: nextWindowID(),
|
|
title: options.Title,
|
|
posX: options.X,
|
|
posY: options.Y,
|
|
sizeW: options.Width,
|
|
sizeH: options.Height,
|
|
visible: !options.Hidden,
|
|
alwaysOnTop: options.AlwaysOnTop,
|
|
zoom: options.Zoom,
|
|
resizable: !options.DisableResize,
|
|
enabled: true,
|
|
eventHandlers: make(map[events.WindowEventType][]func(*WindowEvent)),
|
|
}
|
|
}
|
|
|
|
// ID returns the unique numeric identifier for the window.
|
|
func (w *WebviewWindow) ID() uint { return w.windowID }
|
|
|
|
// Name returns the window name set in WebviewWindowOptions.
|
|
func (w *WebviewWindow) Name() string { return w.opts.Name }
|
|
|
|
// Show makes the window visible and returns it for chaining.
|
|
func (w *WebviewWindow) Show() Window {
|
|
w.mu.Lock()
|
|
w.visible = true
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// Hide makes the window invisible and returns it for chaining.
|
|
func (w *WebviewWindow) Hide() Window {
|
|
w.mu.Lock()
|
|
w.visible = false
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// IsVisible reports whether the window is currently visible.
|
|
func (w *WebviewWindow) IsVisible() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.visible
|
|
}
|
|
|
|
// Close marks the window as closed.
|
|
func (w *WebviewWindow) Close() {
|
|
w.mu.Lock()
|
|
w.closed = true
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// Focus marks the window as focused.
|
|
func (w *WebviewWindow) Focus() {
|
|
w.mu.Lock()
|
|
w.focused = true
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// Run is a no-op in the stub (the real implementation enters the run loop).
|
|
func (w *WebviewWindow) Run() {}
|
|
|
|
// Center is a no-op in the stub.
|
|
func (w *WebviewWindow) Center() {}
|
|
|
|
// Position returns the current x/y position.
|
|
func (w *WebviewWindow) Position() (int, int) {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.posX, w.posY
|
|
}
|
|
|
|
// RelativePosition returns the position relative to the screen.
|
|
func (w *WebviewWindow) RelativePosition() (int, int) {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.posX, w.posY
|
|
}
|
|
|
|
// Size returns the current width and height.
|
|
func (w *WebviewWindow) Size() (int, int) {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.sizeW, w.sizeH
|
|
}
|
|
|
|
// Width returns the current window width.
|
|
func (w *WebviewWindow) Width() int {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.sizeW
|
|
}
|
|
|
|
// Height returns the current window height.
|
|
func (w *WebviewWindow) Height() int {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.sizeH
|
|
}
|
|
|
|
// Bounds returns the window's position and size as a Rect.
|
|
func (w *WebviewWindow) Bounds() Rect {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return Rect{X: w.posX, Y: w.posY, Width: w.sizeW, Height: w.sizeH}
|
|
}
|
|
|
|
// SetPosition sets the top-left corner position.
|
|
func (w *WebviewWindow) SetPosition(x, y int) {
|
|
w.mu.Lock()
|
|
w.posX, w.posY = x, y
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// SetRelativePosition sets position relative to the screen and returns the window.
|
|
func (w *WebviewWindow) SetRelativePosition(x, y int) Window {
|
|
w.SetPosition(x, y)
|
|
return w
|
|
}
|
|
|
|
// SetSize sets the window dimensions and returns the window.
|
|
func (w *WebviewWindow) SetSize(width, height int) Window {
|
|
w.mu.Lock()
|
|
w.sizeW, w.sizeH = width, height
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// SetBounds sets position and size in one call.
|
|
func (w *WebviewWindow) SetBounds(bounds Rect) {
|
|
w.mu.Lock()
|
|
w.posX, w.posY = bounds.X, bounds.Y
|
|
w.sizeW, w.sizeH = bounds.Width, bounds.Height
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// SetMaxSize is a no-op in the stub.
|
|
func (w *WebviewWindow) SetMaxSize(maxWidth, maxHeight int) Window { return w }
|
|
|
|
// SetMinSize is a no-op in the stub.
|
|
func (w *WebviewWindow) SetMinSize(minWidth, minHeight int) Window { return w }
|
|
|
|
// EnableSizeConstraints is a no-op in the stub.
|
|
func (w *WebviewWindow) EnableSizeConstraints() {}
|
|
|
|
// DisableSizeConstraints is a no-op in the stub.
|
|
func (w *WebviewWindow) DisableSizeConstraints() {}
|
|
|
|
// Resizable reports whether the user can resize the window.
|
|
func (w *WebviewWindow) Resizable() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.resizable
|
|
}
|
|
|
|
// SetResizable enables or disables user resizing and returns the window.
|
|
func (w *WebviewWindow) SetResizable(b bool) Window {
|
|
w.mu.Lock()
|
|
w.resizable = b
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// Maximise maximises the window and returns it.
|
|
func (w *WebviewWindow) Maximise() Window {
|
|
w.mu.Lock()
|
|
w.maximised = true
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// UnMaximise restores from maximised state.
|
|
func (w *WebviewWindow) UnMaximise() {
|
|
w.mu.Lock()
|
|
w.maximised = false
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// ToggleMaximise toggles between maximised and normal.
|
|
func (w *WebviewWindow) ToggleMaximise() {
|
|
w.mu.Lock()
|
|
w.maximised = !w.maximised
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// IsMaximised reports whether the window is maximised.
|
|
func (w *WebviewWindow) IsMaximised() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.maximised
|
|
}
|
|
|
|
// Minimise minimises the window and returns it.
|
|
func (w *WebviewWindow) Minimise() Window {
|
|
w.mu.Lock()
|
|
w.visible = false
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// UnMinimise restores from minimised state.
|
|
func (w *WebviewWindow) UnMinimise() {
|
|
w.mu.Lock()
|
|
w.visible = true
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// IsMinimised always returns false in the stub.
|
|
func (w *WebviewWindow) IsMinimised() bool { return false }
|
|
|
|
// Fullscreen enters fullscreen and returns the window.
|
|
func (w *WebviewWindow) Fullscreen() Window {
|
|
w.mu.Lock()
|
|
w.isFullscreen = true
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// UnFullscreen exits fullscreen.
|
|
func (w *WebviewWindow) UnFullscreen() {
|
|
w.mu.Lock()
|
|
w.isFullscreen = false
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// ToggleFullscreen toggles between fullscreen and normal.
|
|
func (w *WebviewWindow) ToggleFullscreen() {
|
|
w.mu.Lock()
|
|
w.isFullscreen = !w.isFullscreen
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// IsFullscreen reports whether the window is in fullscreen mode.
|
|
func (w *WebviewWindow) IsFullscreen() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.isFullscreen
|
|
}
|
|
|
|
// Restore exits both fullscreen and maximised states.
|
|
func (w *WebviewWindow) Restore() {
|
|
w.mu.Lock()
|
|
w.maximised = false
|
|
w.isFullscreen = false
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// SnapAssist is a no-op in the stub.
|
|
func (w *WebviewWindow) SnapAssist() {}
|
|
|
|
// SetTitle updates the window title and returns the window.
|
|
func (w *WebviewWindow) SetTitle(title string) Window {
|
|
w.mu.Lock()
|
|
w.title = title
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// SetURL is a no-op in the stub.
|
|
func (w *WebviewWindow) SetURL(s string) Window { return w }
|
|
|
|
// SetHTML is a no-op in the stub.
|
|
func (w *WebviewWindow) SetHTML(html string) Window { return w }
|
|
|
|
// SetMinimiseButtonState is a no-op in the stub.
|
|
func (w *WebviewWindow) SetMinimiseButtonState(state ButtonState) Window { return w }
|
|
|
|
// SetMaximiseButtonState is a no-op in the stub.
|
|
func (w *WebviewWindow) SetMaximiseButtonState(state ButtonState) Window { return w }
|
|
|
|
// SetCloseButtonState is a no-op in the stub.
|
|
func (w *WebviewWindow) SetCloseButtonState(state ButtonState) Window { return w }
|
|
|
|
// SetMenu is a no-op in the stub.
|
|
func (w *WebviewWindow) SetMenu(menu *Menu) {}
|
|
|
|
// ShowMenuBar is a no-op in the stub.
|
|
func (w *WebviewWindow) ShowMenuBar() {}
|
|
|
|
// HideMenuBar is a no-op in the stub.
|
|
func (w *WebviewWindow) HideMenuBar() {}
|
|
|
|
// ToggleMenuBar is a no-op in the stub.
|
|
func (w *WebviewWindow) ToggleMenuBar() {}
|
|
|
|
// SetBackgroundColour is a no-op in the stub.
|
|
func (w *WebviewWindow) SetBackgroundColour(colour RGBA) Window { return w }
|
|
|
|
// SetAlwaysOnTop sets the always-on-top flag and returns the window.
|
|
func (w *WebviewWindow) SetAlwaysOnTop(b bool) Window {
|
|
w.mu.Lock()
|
|
w.alwaysOnTop = b
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// SetFrameless is a no-op in the stub.
|
|
func (w *WebviewWindow) SetFrameless(frameless bool) Window { return w }
|
|
|
|
// ToggleFrameless is a no-op in the stub.
|
|
func (w *WebviewWindow) ToggleFrameless() {}
|
|
|
|
// SetIgnoreMouseEvents sets the mouse-event passthrough flag and returns the window.
|
|
func (w *WebviewWindow) SetIgnoreMouseEvents(ignore bool) Window {
|
|
w.mu.Lock()
|
|
w.ignoreMouseEvents = ignore
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// IsIgnoreMouseEvents reports whether mouse events are being ignored.
|
|
func (w *WebviewWindow) IsIgnoreMouseEvents() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.ignoreMouseEvents
|
|
}
|
|
|
|
// SetContentProtection is a no-op in the stub.
|
|
func (w *WebviewWindow) SetContentProtection(protection bool) Window { return w }
|
|
|
|
// GetZoom returns the current zoom magnification.
|
|
func (w *WebviewWindow) GetZoom() float64 {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.zoom
|
|
}
|
|
|
|
// SetZoom sets the zoom magnification and returns the window.
|
|
func (w *WebviewWindow) SetZoom(magnification float64) Window {
|
|
w.mu.Lock()
|
|
w.zoom = magnification
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// Zoom is a no-op in the stub.
|
|
func (w *WebviewWindow) Zoom() {}
|
|
|
|
// ZoomIn is a no-op in the stub.
|
|
func (w *WebviewWindow) ZoomIn() {}
|
|
|
|
// ZoomOut is a no-op in the stub.
|
|
func (w *WebviewWindow) ZoomOut() {}
|
|
|
|
// ZoomReset resets zoom to 1.0 and returns the window.
|
|
func (w *WebviewWindow) ZoomReset() Window {
|
|
w.mu.Lock()
|
|
w.zoom = 1.0
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// GetBorderSizes returns zero insets in the stub.
|
|
func (w *WebviewWindow) GetBorderSizes() *LRTB { return &LRTB{} }
|
|
|
|
// GetScreen returns nil in the stub.
|
|
func (w *WebviewWindow) GetScreen() (*Screen, error) { return nil, nil }
|
|
|
|
// ExecJS is a no-op in the stub.
|
|
func (w *WebviewWindow) ExecJS(js string) {}
|
|
|
|
// EmitEvent always returns false in the stub.
|
|
func (w *WebviewWindow) EmitEvent(name string, data ...any) bool { return false }
|
|
|
|
// DispatchWailsEvent is a no-op in the stub.
|
|
func (w *WebviewWindow) DispatchWailsEvent(event *CustomEvent) {}
|
|
|
|
// OnWindowEvent registers an event callback and returns an unsubscribe function.
|
|
func (w *WebviewWindow) OnWindowEvent(eventType events.WindowEventType, callback func(event *WindowEvent)) func() {
|
|
w.mu.Lock()
|
|
w.eventHandlers[eventType] = append(w.eventHandlers[eventType], callback)
|
|
w.mu.Unlock()
|
|
return func() {}
|
|
}
|
|
|
|
// RegisterHook is an alias for OnWindowEvent.
|
|
func (w *WebviewWindow) RegisterHook(eventType events.WindowEventType, callback func(event *WindowEvent)) func() {
|
|
return w.OnWindowEvent(eventType, callback)
|
|
}
|
|
|
|
// handleDragAndDropMessage is a no-op in the stub.
|
|
func (w *WebviewWindow) handleDragAndDropMessage(filenames []string, dropTarget *DropTargetDetails) {}
|
|
|
|
// InitiateFrontendDropProcessing is a no-op in the stub.
|
|
func (w *WebviewWindow) InitiateFrontendDropProcessing(filenames []string, x int, y int) {}
|
|
|
|
// HandleMessage is a no-op in the stub.
|
|
func (w *WebviewWindow) HandleMessage(message string) {}
|
|
|
|
// HandleWindowEvent is a no-op in the stub.
|
|
func (w *WebviewWindow) HandleWindowEvent(id uint) {}
|
|
|
|
// HandleKeyEvent is a no-op in the stub.
|
|
func (w *WebviewWindow) HandleKeyEvent(acceleratorString string) {}
|
|
|
|
// OpenContextMenu is a no-op in the stub.
|
|
func (w *WebviewWindow) OpenContextMenu(data *ContextMenuData) {}
|
|
|
|
// AttachModal is a no-op in the stub.
|
|
func (w *WebviewWindow) AttachModal(modalWindow Window) {}
|
|
|
|
// OpenDevTools is a no-op in the stub.
|
|
func (w *WebviewWindow) OpenDevTools() {}
|
|
|
|
// Print always returns nil in the stub.
|
|
func (w *WebviewWindow) Print() error { return nil }
|
|
|
|
// Flash is a no-op in the stub.
|
|
func (w *WebviewWindow) Flash(enabled bool) {}
|
|
|
|
// IsFocused reports whether the window has focus.
|
|
func (w *WebviewWindow) IsFocused() bool {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.focused
|
|
}
|
|
|
|
// NativeWindow returns nil in the stub.
|
|
func (w *WebviewWindow) NativeWindow() unsafe.Pointer { return nil }
|
|
|
|
// SetEnabled sets the window's enabled state.
|
|
func (w *WebviewWindow) SetEnabled(enabled bool) {
|
|
w.mu.Lock()
|
|
w.enabled = enabled
|
|
w.mu.Unlock()
|
|
}
|
|
|
|
// Reload is a no-op in the stub.
|
|
func (w *WebviewWindow) Reload() {}
|
|
|
|
// ForceReload is a no-op in the stub.
|
|
func (w *WebviewWindow) ForceReload() {}
|
|
|
|
// Info is a no-op in the stub.
|
|
func (w *WebviewWindow) Info(message string, args ...any) {}
|
|
|
|
// Error is a no-op in the stub.
|
|
func (w *WebviewWindow) Error(message string, args ...any) {}
|
|
|
|
// shouldUnconditionallyClose always returns false in the stub.
|
|
func (w *WebviewWindow) shouldUnconditionallyClose() bool { return false }
|
|
|
|
// Internal editing stubs — satisfy the Window interface.
|
|
func (w *WebviewWindow) cut() {}
|
|
func (w *WebviewWindow) copy() {}
|
|
func (w *WebviewWindow) paste() {}
|
|
func (w *WebviewWindow) undo() {}
|
|
func (w *WebviewWindow) redo() {}
|
|
func (w *WebviewWindow) delete() {}
|
|
func (w *WebviewWindow) selectAll() {}
|
|
|
|
// Title returns the current window title.
|
|
func (w *WebviewWindow) Title() string {
|
|
w.mu.RLock()
|
|
defer w.mu.RUnlock()
|
|
return w.title
|
|
}
|
|
|
|
// WindowManager manages in-memory windows.
|
|
//
|
|
// win := app.Window.NewWithOptions(application.WebviewWindowOptions{Title: "Main"})
|
|
type WindowManager struct {
|
|
mu sync.RWMutex
|
|
windows map[uint]*WebviewWindow
|
|
}
|
|
|
|
func (wm *WindowManager) init() {
|
|
if wm.windows == nil {
|
|
wm.windows = make(map[uint]*WebviewWindow)
|
|
}
|
|
}
|
|
|
|
// NewWithOptions creates and registers a new window.
|
|
func (wm *WindowManager) NewWithOptions(options WebviewWindowOptions) *WebviewWindow {
|
|
window := newWebviewWindow(options)
|
|
wm.mu.Lock()
|
|
wm.init()
|
|
wm.windows[window.windowID] = window
|
|
wm.mu.Unlock()
|
|
return window
|
|
}
|
|
|
|
// New creates a window with default options.
|
|
func (wm *WindowManager) New() *WebviewWindow {
|
|
return wm.NewWithOptions(WebviewWindowOptions{})
|
|
}
|
|
|
|
// GetAll returns all managed windows as the Window interface slice.
|
|
func (wm *WindowManager) GetAll() []Window {
|
|
wm.mu.RLock()
|
|
defer wm.mu.RUnlock()
|
|
out := make([]Window, 0, len(wm.windows))
|
|
for _, window := range wm.windows {
|
|
out = append(out, window)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// GetByName finds a window by name, returning it and whether it was found.
|
|
func (wm *WindowManager) GetByName(name string) (Window, bool) {
|
|
wm.mu.RLock()
|
|
defer wm.mu.RUnlock()
|
|
for _, window := range wm.windows {
|
|
if window.opts.Name == name {
|
|
return window, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// GetByID finds a window by its numeric ID.
|
|
func (wm *WindowManager) GetByID(id uint) (Window, bool) {
|
|
wm.mu.RLock()
|
|
defer wm.mu.RUnlock()
|
|
window, exists := wm.windows[id]
|
|
return window, exists
|
|
}
|
|
|
|
// Remove unregisters a window by ID.
|
|
func (wm *WindowManager) Remove(windowID uint) {
|
|
wm.mu.Lock()
|
|
wm.init()
|
|
delete(wm.windows, windowID)
|
|
wm.mu.Unlock()
|
|
}
|
|
|
|
// App is the top-level application object used by the GUI packages.
|
|
//
|
|
// app := &application.App{}
|
|
// win := app.Window.NewWithOptions(application.WebviewWindowOptions{Title: "Main"})
|
|
type App struct {
|
|
Logger Logger
|
|
Window WindowManager
|
|
Menu MenuManager
|
|
SystemTray SystemTrayManager
|
|
Dialog DialogManager
|
|
Event EventManager
|
|
Browser BrowserManager
|
|
Clipboard ClipboardManager
|
|
ContextMenu ContextMenuManager
|
|
Environment EnvironmentManager
|
|
Screen ScreenManager
|
|
KeyBinding KeyBindingManager
|
|
}
|
|
|
|
// Quit is a no-op in the stub.
|
|
func (a *App) Quit() {}
|
|
|
|
// NewMenu creates a new empty Menu.
|
|
func (a *App) NewMenu() *Menu {
|
|
return NewMenu()
|
|
}
|