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

[v3] Update application.On and window.On to return functions that unregister the listener. WebviewWindow.onApplicationEvent is a helper which will manage the unregistering for you on window destroy.

This commit is contained in:
Lea Anthony 2023-04-29 19:39:05 +10:00 committed by Misite Bao
parent 178ea9c8c5
commit f08ae2fc62
3 changed files with 66 additions and 13 deletions

View File

@ -1,6 +1,7 @@
package application
import (
"github.com/samber/lo"
"log"
"net/http"
"os"
@ -23,6 +24,10 @@ func init() {
runtime.LockOSThread()
}
type EventListener struct {
callback func()
}
func New(appOptions Options) *App {
if globalApplication != nil {
return globalApplication
@ -32,7 +37,7 @@ func New(appOptions Options) *App {
result := &App{
options: appOptions,
applicationEventListeners: make(map[uint][]func()),
applicationEventListeners: make(map[uint][]*EventListener),
systemTrays: make(map[uint]*SystemTray),
log: logger.New(appOptions.Logger.CustomLoggers...),
contextMenus: make(map[string]*Menu),
@ -155,7 +160,7 @@ var webviewRequests = make(chan *webViewAssetRequest)
type App struct {
options Options
applicationEventListeners map[uint][]func()
applicationEventListeners map[uint][]*EventListener
applicationEventListenersLock sync.RWMutex
// Windows
@ -216,14 +221,25 @@ func (a *App) deleteWindowByID(id uint) {
delete(a.windows, id)
}
func (a *App) On(eventType events.ApplicationEventType, callback func()) {
func (a *App) On(eventType events.ApplicationEventType, callback func()) func() {
eventID := uint(eventType)
a.applicationEventListenersLock.Lock()
defer a.applicationEventListenersLock.Unlock()
a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], callback)
listener := &EventListener{
callback: callback,
}
a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], listener)
if a.impl != nil {
go a.impl.on(eventID)
}
return func() {
// lock the map
a.applicationEventListenersLock.Lock()
defer a.applicationEventListenersLock.Unlock()
// Remove listener
a.applicationEventListeners[eventID] = lo.Without(a.applicationEventListeners[eventID], listener)
}
}
func (a *App) NewWebviewWindow() *WebviewWindow {
return a.NewWebviewWindowWithOptions(&WebviewWindowOptions{})
@ -383,7 +399,7 @@ func (a *App) handleApplicationEvent(event uint) {
return
}
for _, listener := range listeners {
go listener()
go listener.callback()
}
}

View File

@ -2,6 +2,7 @@ package application
import (
"fmt"
"github.com/samber/lo"
"sync"
"time"
@ -61,17 +62,25 @@ type (
}
)
type WindowEventListener struct {
callback func(ctx *WindowEventContext)
}
type WebviewWindow struct {
options *WebviewWindowOptions
impl webviewWindowImpl
implLock sync.RWMutex
id uint
eventListeners map[uint][]func(ctx *WindowEventContext)
eventListeners map[uint][]*WindowEventListener
eventListenersLock sync.RWMutex
contextMenus map[string]*Menu
contextMenusLock sync.RWMutex
// A map of listener cancellation functions
cancellersLock sync.RWMutex
cancellers []func()
}
var windowID uint
@ -84,6 +93,13 @@ func getWindowID() uint {
return windowID
}
// Use onApplicationEvent to register a callback for an application event from a window.
// This will handle tidying up the callback when the window is destroyed
func (w *WebviewWindow) onApplicationEvent(eventType events.ApplicationEventType, callback func()) {
cancelFn := globalApplication.On(eventType, callback)
w.addCancellationFunction(cancelFn)
}
func NewWindow(options *WebviewWindowOptions) *WebviewWindow {
if options.Width == 0 {
options.Width = 800
@ -98,13 +114,19 @@ func NewWindow(options *WebviewWindowOptions) *WebviewWindow {
result := &WebviewWindow{
id: getWindowID(),
options: options,
eventListeners: make(map[uint][]func(ctx *WindowEventContext)),
eventListeners: make(map[uint][]*WindowEventListener),
contextMenus: make(map[string]*Menu),
}
return result
}
func (w *WebviewWindow) addCancellationFunction(canceller func()) {
w.cancellersLock.Lock()
defer w.cancellersLock.Unlock()
w.cancellers = append(w.cancellers, canceller)
}
func (w *WebviewWindow) SetTitle(title string) *WebviewWindow {
w.implLock.RLock()
defer w.implLock.RUnlock()
@ -371,20 +393,30 @@ func (w *WebviewWindow) Center() {
w.impl.center()
}
func (w *WebviewWindow) On(eventType events.WindowEventType, callback func(ctx *WindowEventContext)) {
func (w *WebviewWindow) On(eventType events.WindowEventType, callback func(ctx *WindowEventContext)) func() {
eventID := uint(eventType)
w.eventListenersLock.Lock()
defer w.eventListenersLock.Unlock()
w.eventListeners[eventID] = append(w.eventListeners[eventID], callback)
windowEventListener := &WindowEventListener{
callback: callback,
}
w.eventListeners[eventID] = append(w.eventListeners[eventID], windowEventListener)
if w.impl != nil {
w.impl.on(eventID)
}
return func() {
w.eventListenersLock.Lock()
defer w.eventListenersLock.Unlock()
w.eventListeners[eventID] = lo.Without(w.eventListeners[eventID], windowEventListener)
}
}
func (w *WebviewWindow) handleWindowEvent(id uint) {
w.eventListenersLock.RLock()
for _, callback := range w.eventListeners[id] {
go callback(blankWindowEventContext)
for _, listener := range w.eventListeners[id] {
go listener.callback(blankWindowEventContext)
}
w.eventListenersLock.RUnlock()
}
@ -416,6 +448,10 @@ func (w *WebviewWindow) Destroy() {
if w.impl == nil {
return
}
// Cancel the callbacks
for _, cancelFunc := range w.cancellers {
cancelFunc()
}
w.impl.destroy()
}
@ -631,7 +667,7 @@ func (w *WebviewWindow) handleDragAndDropMessage(event *dragAndDropMessage) {
ctx := newWindowEventContext()
ctx.setDroppedFiles(event.filenames)
for _, listener := range w.eventListeners[uint(events.FilesDropped)] {
listener(ctx)
listener.callback(ctx)
}
}

View File

@ -140,7 +140,8 @@ func (w *windowsWebviewWindow) _run() {
switch options.Windows.Theme {
case SystemDefault:
w.updateTheme(w32.IsCurrentlyDarkMode())
globalApplication.On(events.Windows.SystemThemeChanged, func() {
// Setup a listener to respond to theme changes
w.parent.onApplicationEvent(events.Windows.SystemThemeChanged, func() {
w.updateTheme(w32.IsCurrentlyDarkMode())
})
case Light: