Improve Linux application events and refactor app method receivers

This commit includes the addition of common events for the Linux platform. Refactored and standardized the method receivers for the application from 'm' to 'l'. Also, the application startup events in the window example have been updated according to the new naming scheme.
This commit is contained in:
Lea Anthony
2024-03-06 11:42:19 -06:00
committed by Travis McLane
parent bfa53dfd6c
commit 05b16f1d63
9 changed files with 103 additions and 57 deletions
+1
View File
@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="runtime.js"></script>
<style>body{ text-align: center; color: white; background-color: #191919; user-select: none; -ms-user-select: none; -webkit-user-select: none; }</style>
</head>
<body>
+1 -1
View File
@@ -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")
})
+36 -38
View File
@@ -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
}
+2 -2
View File
@@ -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()
+21
View File
@@ -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
})
}
}
+32 -8
View File
@@ -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))
+1 -1
View File
@@ -2,7 +2,7 @@
package application
func (m *linuxApp) dispatchOnMainThread(id uint) {
func (l *linuxApp) dispatchOnMainThread(id uint) {
dispatchOnMainThread(id)
}
+3 -3
View File
@@ -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()
+6 -4
View File
@@ -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())
})