diff --git a/v3/examples/events/assets/index.html b/v3/examples/events/assets/index.html index d8e0906e..a64a42c3 100644 --- a/v3/examples/events/assets/index.html +++ b/v3/examples/events/assets/index.html @@ -3,6 +3,7 @@ Title + diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index 9c0e390f..41fc4660 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -24,7 +24,7 @@ func main() { ApplicationShouldTerminateAfterLastWindowClosed: false, }, }) - app.On(events.Mac.ApplicationDidFinishLaunching, func(event *application.Event) { + app.On(events.Common.ApplicationStarted, func(event *application.Event) { log.Println("ApplicationDidFinishLaunching") }) diff --git a/v3/pkg/application/application_linux.go b/v3/pkg/application/application_linux.go index 4272cd5c..c3b54673 100644 --- a/v3/pkg/application/application_linux.go +++ b/v3/pkg/application/application_linux.go @@ -35,7 +35,7 @@ type linuxApp struct { theme string } -func (m *linuxApp) GetFlags(options Options) map[string]any { +func (l *linuxApp) GetFlags(options Options) map[string]any { if options.Flags == nil { options.Flags = make(map[string]any) } @@ -46,30 +46,30 @@ func getNativeApplication() *linuxApp { return globalApplication.impl.(*linuxApp) } -func (m *linuxApp) hide() { - hideAllWindows(m.application) +func (l *linuxApp) hide() { + hideAllWindows(l.application) } -func (m *linuxApp) show() { - showAllWindows(m.application) +func (l *linuxApp) show() { + showAllWindows(l.application) } -func (m *linuxApp) on(eventID uint) { +func (l *linuxApp) on(eventID uint) { // TODO: What do we need to do here? log.Println("linuxApp.on()", eventID) } -func (m *linuxApp) setIcon(icon []byte) { +func (l *linuxApp) setIcon(icon []byte) { log.Println("linuxApp.setIcon", "not implemented") } -func (m *linuxApp) name() string { +func (l *linuxApp) name() string { return appName() } -func (m *linuxApp) getCurrentWindowID() uint { - return getCurrentWindowID(m.application, m.windows) +func (l *linuxApp) getCurrentWindowID() uint { + return getCurrentWindowID(l.application, l.windows) } type rnr struct { @@ -80,9 +80,9 @@ func (r rnr) run() { r.f() } -func (m *linuxApp) getApplicationMenu() pointer { - if m.applicationMenu != nilPointer { - return m.applicationMenu +func (l *linuxApp) getApplicationMenu() pointer { + if l.applicationMenu != nilPointer { + return l.applicationMenu } menu := globalApplication.ApplicationMenu @@ -90,12 +90,12 @@ func (m *linuxApp) getApplicationMenu() pointer { InvokeSync(func() { menu.Update() }) - m.applicationMenu = (menu.impl).(*linuxMenu).native + l.applicationMenu = (menu.impl).(*linuxMenu).native } - return m.applicationMenu + return l.applicationMenu } -func (m *linuxApp) setApplicationMenu(menu *Menu) { +func (l *linuxApp) setApplicationMenu(menu *Menu) { // FIXME: How do we avoid putting a menu? if menu == nil { // Create a default menu @@ -104,46 +104,44 @@ func (m *linuxApp) setApplicationMenu(menu *Menu) { } } -func (m *linuxApp) run() error { +func (l *linuxApp) run() error { - // Add a hook to the ApplicationDidFinishLaunching event - // FIXME: add Wails specific events - i.e. Shouldn't platform specific ones be translated to Wails events? - m.parent.On(events.Mac.ApplicationDidFinishLaunching, func(evt *Event) { - // Do we need to do anything now? - fmt.Println("events.Mac.ApplicationDidFinishLaunching received!") + l.parent.On(events.Linux.ApplicationStartup, func(evt *Event) { + fmt.Println("events.Linux.ApplicationStartup received!") }) - m.monitorThemeChanges() - return appRun(m.application) + l.setupCommonEvents() + l.monitorThemeChanges() + return appRun(l.application) } -func (m *linuxApp) destroy() { +func (l *linuxApp) destroy() { if !globalApplication.shouldQuit() { return } globalApplication.cleanup() - appDestroy(m.application) + appDestroy(l.application) } -func (m *linuxApp) isOnMainThread() bool { +func (l *linuxApp) isOnMainThread() bool { return isOnMainThread() } // register our window to our parent mapping -func (m *linuxApp) registerWindow(window pointer, id uint) { - m.windowsLock.Lock() - m.windows[windowPointer(window)] = id - m.windowsLock.Unlock() +func (l *linuxApp) registerWindow(window pointer, id uint) { + l.windowsLock.Lock() + l.windows[windowPointer(window)] = id + l.windowsLock.Unlock() } -func (m *linuxApp) isDarkMode() bool { - return strings.Contains(m.theme, "dark") +func (l *linuxApp) isDarkMode() bool { + return strings.Contains(l.theme, "dark") } -func (m *linuxApp) monitorThemeChanges() { +func (l *linuxApp) monitorThemeChanges() { go func() { conn, err := dbus.ConnectSessionBus() if err != nil { - m.parent.info("[WARNING] Failed to connect to session bus; monitoring for theme changes will not function:", err) + l.parent.info("[WARNING] Failed to connect to session bus; monitoring for theme changes will not function:", err) return } defer conn.Close() @@ -176,10 +174,10 @@ func (m *linuxApp) monitorThemeChanges() { continue } - if theme != m.theme { - m.theme = theme + if theme != l.theme { + l.theme = theme event := newApplicationEvent(events.Common.ThemeChanged) - event.Context().setIsDarkMode(m.isDarkMode()) + event.Context().setIsDarkMode(l.isDarkMode()) applicationEvents <- event } diff --git a/v3/pkg/application/dialogs_linux.go b/v3/pkg/application/dialogs_linux.go index 4943766f..49499dda 100644 --- a/v3/pkg/application/dialogs_linux.go +++ b/v3/pkg/application/dialogs_linux.go @@ -1,7 +1,7 @@ package application -func (m *linuxApp) showAboutDialog(title string, message string, icon []byte) { - window := globalApplication.getWindowForID(m.getCurrentWindowID()) +func (l *linuxApp) showAboutDialog(title string, message string, icon []byte) { + window := globalApplication.getWindowForID(l.getCurrentWindowID()) var parent uintptr if window != nil { parent, _ = window.(*WebviewWindow).NativeWindowHandle() diff --git a/v3/pkg/application/events_common_linux.go b/v3/pkg/application/events_common_linux.go new file mode 100644 index 00000000..530ac156 --- /dev/null +++ b/v3/pkg/application/events_common_linux.go @@ -0,0 +1,21 @@ +//go:build linux + +package application + +import "github.com/wailsapp/wails/v3/pkg/events" + +var commonApplicationEventMap = map[events.ApplicationEventType]events.ApplicationEventType{ + events.Linux.ApplicationStartup: events.Common.ApplicationStarted, + events.Linux.SystemThemeChanged: events.Common.ThemeChanged, +} + +func (l *linuxApp) setupCommonEvents() { + for sourceEvent, targetEvent := range commonApplicationEventMap { + sourceEvent := sourceEvent + targetEvent := targetEvent + l.parent.On(sourceEvent, func(event *Event) { + event.Id = uint(targetEvent) + applicationEvents <- event + }) + } +} diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 36db3d50..379af254 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -206,7 +206,36 @@ func dispatchOnMainThreadCallback(callbackID C.uint) { //export activateLinux func activateLinux(data pointer) { - // NOOP: Callback for now + processApplicationEvent(C.uint(events.Linux.ApplicationStartup), data) +} + +//export processApplicationEvent +func processApplicationEvent(eventID C.uint, data pointer) { + event := newApplicationEvent(events.ApplicationEventType(eventID)) + + //if data != nil { + // dataCStrJSON := C.serializationNSDictionary(data) + // if dataCStrJSON != nil { + // defer C.free(unsafe.Pointer(dataCStrJSON)) + // + // dataJSON := C.GoString(dataCStrJSON) + // var result map[string]any + // err := json.Unmarshal([]byte(dataJSON), &result) + // + // if err != nil { + // panic(err) + // } + // + // event.Context().setData(result) + // } + //} + + switch event.Id { + case uint(events.Linux.SystemThemeChanged): + isDark := globalApplication.IsDarkMode() + event.Context().setIsDarkMode(isDark) + } + applicationEvents <- event } func isOnMainThread() bool { @@ -236,17 +265,12 @@ func appNew(name string) pointer { func appRun(app pointer) error { application := (*C.GApplication)(app) + //TODO: Only set this if we configure it to do so C.g_application_hold(application) // allows it to run without a window signal := C.CString("activate") defer C.free(unsafe.Pointer(signal)) - C.g_signal_connect_data( - C.gpointer(application), - signal, - C.GCallback(C.activateLinux), - nil, - nil, - 0) + C.signal_connect(unsafe.Pointer(application), signal, C.activateLinux, nil) status := C.g_application_run(application, 0, nil) C.g_application_release(application) C.g_object_unref(C.gpointer(app)) diff --git a/v3/pkg/application/mainthread_linux.go b/v3/pkg/application/mainthread_linux.go index 572b081b..2a5ff3e2 100644 --- a/v3/pkg/application/mainthread_linux.go +++ b/v3/pkg/application/mainthread_linux.go @@ -2,7 +2,7 @@ package application -func (m *linuxApp) dispatchOnMainThread(id uint) { +func (l *linuxApp) dispatchOnMainThread(id uint) { dispatchOnMainThread(id) } diff --git a/v3/pkg/application/screen_linux.go b/v3/pkg/application/screen_linux.go index 36411045..526752ac 100644 --- a/v3/pkg/application/screen_linux.go +++ b/v3/pkg/application/screen_linux.go @@ -7,17 +7,17 @@ import ( "sync" ) -func (m *linuxApp) getPrimaryScreen() (*Screen, error) { +func (l *linuxApp) getPrimaryScreen() (*Screen, error) { return nil, fmt.Errorf("not implemented") } -func (m *linuxApp) getScreens() ([]*Screen, error) { +func (l *linuxApp) getScreens() ([]*Screen, error) { var wg sync.WaitGroup var screens []*Screen var err error wg.Add(1) InvokeSync(func() { - screens, err = getScreens(m.application) + screens, err = getScreens(l.application) wg.Done() }) wg.Wait() diff --git a/v3/pkg/application/webview_window_linux.go b/v3/pkg/application/webview_window_linux.go index 1f36059e..5314ea6b 100644 --- a/v3/pkg/application/webview_window_linux.go +++ b/v3/pkg/application/webview_window_linux.go @@ -259,11 +259,12 @@ func (w *linuxWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) { func newWindowImpl(parent *WebviewWindow) *linuxWebviewWindow { // (*C.struct__GtkWidget)(m.native) //var menubar *C.struct__GtkWidget - return &linuxWebviewWindow{ + result := &linuxWebviewWindow{ application: getNativeApplication().application, parent: parent, // menubar: menubar, } + return result } func (w *linuxWebviewWindow) setTitle(title string) { @@ -405,9 +406,7 @@ func (w *linuxWebviewWindow) run() { } w.setURL(startURL) - // We need to wait for the HTML to load before we can execute the javascript - // FIXME: What event is this? DomReady? - w.parent.On(events.Mac.WebViewDidFinishNavigation, func(_ *WindowEvent) { + w.parent.On(events.Linux.WindowLoadChanged, func(_ *WindowEvent) { if w.parent.options.JS != "" { w.execJS(w.parent.options.JS) } @@ -416,6 +415,9 @@ func (w *linuxWebviewWindow) run() { w.execJS(js) } }) + w.parent.On(events.Linux.WindowDeleteEvent, func(e *WindowEvent) { + w.parent.emit(events.Common.WindowClosing) + }) w.parent.RegisterHook(events.Linux.WindowLoadChanged, func(e *WindowEvent) { w.execJS(runtime.Core()) })