mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-15 23:25:49 +01:00
* custom transport initial * transport codecs * runtime set transport * events transport * clauded example * bundled runtime * wip: transport * rework transports * rework dialog responses * cleanup * cleanup * improve error handling in HTTPTransport * cleanup * cleanup * cleanup * cleanup * review changes * review changes * review changes * review changes * review changes * review changes * review changes * move documentation to website docs * update doc * update changelog * introduce JSClient method for transport for embedding JS part in transport --------- Co-authored-by: Atterpac <Capretta.Michael@gmail.com> Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
171 lines
5.2 KiB
Go
171 lines
5.2 KiB
Go
package application
|
|
|
|
import (
|
|
"slices"
|
|
|
|
"github.com/samber/lo"
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
)
|
|
|
|
// EventManager manages event-related operations
|
|
type EventManager struct {
|
|
app *App
|
|
}
|
|
|
|
// newEventManager creates a new EventManager instance
|
|
func newEventManager(app *App) *EventManager {
|
|
return &EventManager{
|
|
app: app,
|
|
}
|
|
}
|
|
|
|
// Emit emits a custom event with the specified name and associated data.
|
|
// It returns a boolean indicating whether the event was cancelled by a hook.
|
|
//
|
|
// If no data argument is provided, Emit emits an event with nil data.
|
|
// When there is exactly one data argument, it will be used as the custom event's data field.
|
|
// When more than one argument is provided, the event's data field will be set to the argument slice.
|
|
//
|
|
// If the given event name is registered, Emit validates the data parameter
|
|
// against the expected data type. In case of a mismatch, Emit reports an error
|
|
// to the registered error handler for the application and cancels the event.
|
|
func (em *EventManager) Emit(name string, data ...any) bool {
|
|
event := &CustomEvent{Name: name}
|
|
|
|
if len(data) == 1 {
|
|
event.Data = data[0]
|
|
} else if len(data) > 1 {
|
|
event.Data = data
|
|
}
|
|
|
|
if err := em.app.customEventProcessor.Emit(event); err != nil {
|
|
globalApplication.handleError(err)
|
|
}
|
|
|
|
return event.IsCancelled()
|
|
}
|
|
|
|
// EmitEvent emits a custom event object (internal use)
|
|
// It returns a boolean indicating whether the event was cancelled by a hook.
|
|
//
|
|
// If the given event name is registered, emitEvent validates the data parameter
|
|
// against the expected data type. In case of a mismatch, emitEvent reports an error
|
|
// to the registered error handler for the application and cancels the event.
|
|
func (em *EventManager) EmitEvent(event *CustomEvent) bool {
|
|
if err := em.app.customEventProcessor.Emit(event); err != nil {
|
|
globalApplication.handleError(err)
|
|
}
|
|
|
|
return event.IsCancelled()
|
|
}
|
|
|
|
// On registers a listener for custom events
|
|
func (em *EventManager) On(name string, callback func(event *CustomEvent)) func() {
|
|
return em.app.customEventProcessor.On(name, callback)
|
|
}
|
|
|
|
// Off removes all listeners for a custom event
|
|
func (em *EventManager) Off(name string) {
|
|
em.app.customEventProcessor.Off(name)
|
|
}
|
|
|
|
// OnMultiple registers a listener for custom events that will be called N times
|
|
func (em *EventManager) OnMultiple(name string, callback func(event *CustomEvent), counter int) {
|
|
em.app.customEventProcessor.OnMultiple(name, callback, counter)
|
|
}
|
|
|
|
// Reset removes all custom event listeners
|
|
func (em *EventManager) Reset() {
|
|
em.app.customEventProcessor.OffAll()
|
|
}
|
|
|
|
// OnApplicationEvent registers a listener for application events
|
|
func (em *EventManager) OnApplicationEvent(eventType events.ApplicationEventType, callback func(event *ApplicationEvent)) func() {
|
|
eventID := uint(eventType)
|
|
em.app.applicationEventListenersLock.Lock()
|
|
defer em.app.applicationEventListenersLock.Unlock()
|
|
listener := &EventListener{
|
|
callback: callback,
|
|
}
|
|
em.app.applicationEventListeners[eventID] = append(em.app.applicationEventListeners[eventID], listener)
|
|
if em.app.impl != nil {
|
|
go func() {
|
|
defer handlePanic()
|
|
em.app.impl.on(eventID)
|
|
}()
|
|
}
|
|
|
|
return func() {
|
|
// lock the map
|
|
em.app.applicationEventListenersLock.Lock()
|
|
defer em.app.applicationEventListenersLock.Unlock()
|
|
// Remove listener
|
|
em.app.applicationEventListeners[eventID] = lo.Without(em.app.applicationEventListeners[eventID], listener)
|
|
}
|
|
}
|
|
|
|
// RegisterApplicationEventHook registers an application event hook
|
|
func (em *EventManager) RegisterApplicationEventHook(eventType events.ApplicationEventType, callback func(event *ApplicationEvent)) func() {
|
|
eventID := uint(eventType)
|
|
em.app.applicationEventHooksLock.Lock()
|
|
defer em.app.applicationEventHooksLock.Unlock()
|
|
thisHook := &eventHook{
|
|
callback: callback,
|
|
}
|
|
em.app.applicationEventHooks[eventID] = append(em.app.applicationEventHooks[eventID], thisHook)
|
|
|
|
return func() {
|
|
em.app.applicationEventHooksLock.Lock()
|
|
em.app.applicationEventHooks[eventID] = lo.Without(em.app.applicationEventHooks[eventID], thisHook)
|
|
em.app.applicationEventHooksLock.Unlock()
|
|
}
|
|
}
|
|
|
|
// Dispatch dispatches an event to listeners (internal use)
|
|
func (em *EventManager) dispatch(event *CustomEvent) {
|
|
// Snapshot listeners under Lock
|
|
em.app.wailsEventListenerLock.Lock()
|
|
listeners := slices.Clone(em.app.wailsEventListeners)
|
|
em.app.wailsEventListenerLock.Unlock()
|
|
|
|
for _, listener := range listeners {
|
|
if event.IsCancelled() {
|
|
return
|
|
}
|
|
listener.DispatchWailsEvent(event)
|
|
}
|
|
}
|
|
|
|
// HandleApplicationEvent handles application events (internal use)
|
|
func (em *EventManager) handleApplicationEvent(event *ApplicationEvent) {
|
|
defer handlePanic()
|
|
em.app.applicationEventListenersLock.RLock()
|
|
listeners, ok := em.app.applicationEventListeners[event.Id]
|
|
em.app.applicationEventListenersLock.RUnlock()
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// Process Hooks
|
|
em.app.applicationEventHooksLock.RLock()
|
|
hooks, ok := em.app.applicationEventHooks[event.Id]
|
|
em.app.applicationEventHooksLock.RUnlock()
|
|
if ok {
|
|
for _, thisHook := range hooks {
|
|
thisHook.callback(event)
|
|
if event.IsCancelled() {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, listener := range listeners {
|
|
go func() {
|
|
if event.IsCancelled() {
|
|
return
|
|
}
|
|
defer handlePanic()
|
|
listener.callback(event)
|
|
}()
|
|
}
|
|
}
|