mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 07:29:56 +08:00
264 lines
6.2 KiB
Go
264 lines
6.2 KiB
Go
//go:build linux
|
|
|
|
package application
|
|
|
|
/*
|
|
#include "gtk/gtk.h"
|
|
#include "webkit2/webkit2.h"
|
|
static guint get_compiled_gtk_major_version() { return GTK_MAJOR_VERSION; }
|
|
static guint get_compiled_gtk_minor_version() { return GTK_MINOR_VERSION; }
|
|
static guint get_compiled_gtk_micro_version() { return GTK_MICRO_VERSION; }
|
|
static guint get_compiled_webkit_major_version() { return WEBKIT_MAJOR_VERSION; }
|
|
static guint get_compiled_webkit_minor_version() { return WEBKIT_MINOR_VERSION; }
|
|
static guint get_compiled_webkit_micro_version() { return WEBKIT_MICRO_VERSION; }
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
"github.com/wailsapp/wails/v3/internal/operatingsystem"
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
)
|
|
|
|
func init() {
|
|
// FIXME: This should be handled appropriately in the individual files most likely.
|
|
// Set GDK_BACKEND=x11 if currently unset and XDG_SESSION_TYPE is unset, unspecified or x11 to prevent warnings
|
|
if os.Getenv("GDK_BACKEND") == "" && (os.Getenv("XDG_SESSION_TYPE") == "" || os.Getenv("XDG_SESSION_TYPE") == "unspecified" || os.Getenv("XDG_SESSION_TYPE") == "x11") {
|
|
_ = os.Setenv("GDK_BACKEND", "x11")
|
|
}
|
|
}
|
|
|
|
type linuxApp struct {
|
|
application pointer
|
|
parent *App
|
|
|
|
startupActions []func()
|
|
|
|
// Native -> uint
|
|
windowMap map[windowPointer]uint
|
|
windowMapLock sync.Mutex
|
|
|
|
theme string
|
|
|
|
icon pointer
|
|
}
|
|
|
|
func (a *linuxApp) GetFlags(options Options) map[string]any {
|
|
if options.Flags == nil {
|
|
options.Flags = make(map[string]any)
|
|
}
|
|
return options.Flags
|
|
}
|
|
|
|
func getNativeApplication() *linuxApp {
|
|
return globalApplication.impl.(*linuxApp)
|
|
}
|
|
|
|
func (a *linuxApp) hide() {
|
|
a.hideAllWindows()
|
|
}
|
|
|
|
func (a *linuxApp) show() {
|
|
a.showAllWindows()
|
|
}
|
|
|
|
func (a *linuxApp) on(eventID uint) {
|
|
// TODO: Test register/unregister events
|
|
//C.registerApplicationEvent(l.application, C.uint(eventID))
|
|
}
|
|
|
|
func (a *linuxApp) name() string {
|
|
return appName()
|
|
}
|
|
|
|
type rnr struct {
|
|
f func()
|
|
}
|
|
|
|
func (r rnr) run() {
|
|
r.f()
|
|
}
|
|
|
|
func (a *linuxApp) setApplicationMenu(menu *Menu) {
|
|
// FIXME: How do we avoid putting a menu?
|
|
if menu == nil {
|
|
// Create a default menu
|
|
menu = DefaultApplicationMenu()
|
|
globalApplication.ApplicationMenu = menu
|
|
}
|
|
}
|
|
|
|
func (a *linuxApp) run() error {
|
|
|
|
a.parent.OnApplicationEvent(events.Linux.ApplicationStartup, func(evt *ApplicationEvent) {
|
|
// TODO: What should happen here?
|
|
})
|
|
a.setupCommonEvents()
|
|
a.monitorThemeChanges()
|
|
return appRun(a.application)
|
|
}
|
|
|
|
func (a *linuxApp) unregisterWindow(w windowPointer) {
|
|
a.windowMapLock.Lock()
|
|
delete(a.windowMap, w)
|
|
a.windowMapLock.Unlock()
|
|
|
|
// If this was the last window...
|
|
if len(a.windowMap) == 0 && !a.parent.options.Linux.DisableQuitOnLastWindowClosed {
|
|
a.destroy()
|
|
}
|
|
}
|
|
|
|
func (a *linuxApp) destroy() {
|
|
if !globalApplication.shouldQuit() {
|
|
return
|
|
}
|
|
globalApplication.cleanup()
|
|
appDestroy(a.application)
|
|
}
|
|
|
|
func (a *linuxApp) isOnMainThread() bool {
|
|
return isOnMainThread()
|
|
}
|
|
|
|
// register our window to our parent mapping
|
|
func (a *linuxApp) registerWindow(window pointer, id uint) {
|
|
a.windowMapLock.Lock()
|
|
a.windowMap[windowPointer(window)] = id
|
|
a.windowMapLock.Unlock()
|
|
}
|
|
|
|
func (a *linuxApp) isDarkMode() bool {
|
|
return strings.Contains(a.theme, "dark")
|
|
}
|
|
|
|
func (a *linuxApp) monitorThemeChanges() {
|
|
go func() {
|
|
defer handlePanic()
|
|
conn, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
a.parent.info("[WARNING] Failed to connect to session bus; monitoring for theme changes will not function:", err)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
if err = conn.AddMatchSignal(
|
|
dbus.WithMatchObjectPath("/org/freedesktop/portal/desktop"),
|
|
); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
c := make(chan *dbus.Signal, 10)
|
|
conn.Signal(c)
|
|
|
|
getTheme := func(body []interface{}) (string, bool) {
|
|
if len(body) < 2 {
|
|
return "", false
|
|
}
|
|
if entry, ok := body[0].(string); !ok || entry != "org.gnome.desktop.interface" {
|
|
return "", false
|
|
}
|
|
if entry, ok := body[1].(string); ok && entry == "color-scheme" {
|
|
return body[2].(dbus.Variant).Value().(string), true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
for v := range c {
|
|
theme, ok := getTheme(v.Body)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
if theme != a.theme {
|
|
a.theme = theme
|
|
event := newApplicationEvent(events.Linux.SystemThemeChanged)
|
|
event.Context().setIsDarkMode(a.isDarkMode())
|
|
applicationEvents <- event
|
|
}
|
|
|
|
}
|
|
}()
|
|
}
|
|
|
|
func newPlatformApp(parent *App) *linuxApp {
|
|
|
|
name := strings.ToLower(strings.Replace(parent.options.Name, " ", "", -1))
|
|
if name == "" {
|
|
name = "undefined"
|
|
}
|
|
app := &linuxApp{
|
|
parent: parent,
|
|
application: appNew(name),
|
|
windowMap: map[windowPointer]uint{},
|
|
}
|
|
|
|
if parent.options.Linux.ProgramName != "" {
|
|
setProgramName(parent.options.Linux.ProgramName)
|
|
}
|
|
|
|
return app
|
|
}
|
|
|
|
// logPlatformInfo logs the platform information to the console
|
|
func (a *App) logPlatformInfo() {
|
|
info, err := operatingsystem.Info()
|
|
if err != nil {
|
|
a.error("Error getting OS info: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
wkVersion := operatingsystem.GetWebkitVersion()
|
|
platformInfo := info.AsLogSlice()
|
|
platformInfo = append(platformInfo, "Webkit2Gtk", wkVersion)
|
|
|
|
a.info("Platform Info:", platformInfo...)
|
|
}
|
|
|
|
//export processWindowEvent
|
|
func processWindowEvent(windowID C.uint, eventID C.uint) {
|
|
windowEvents <- &windowEvent{
|
|
WindowID: uint(windowID),
|
|
EventID: uint(eventID),
|
|
}
|
|
}
|
|
|
|
func buildVersionString(major, minor, micro C.uint) string {
|
|
return fmt.Sprintf("%d.%d.%d", uint(major), uint(minor), uint(micro))
|
|
}
|
|
|
|
func (a *App) platformEnvironment() map[string]any {
|
|
result := map[string]any{}
|
|
result["gtk3-compiled"] = buildVersionString(
|
|
C.get_compiled_gtk_major_version(),
|
|
C.get_compiled_gtk_minor_version(),
|
|
C.get_compiled_gtk_micro_version(),
|
|
)
|
|
result["gtk3-runtime"] = buildVersionString(
|
|
C.gtk_get_major_version(),
|
|
C.gtk_get_minor_version(),
|
|
C.gtk_get_micro_version(),
|
|
)
|
|
|
|
result["webkit2gtk-compiled"] = buildVersionString(
|
|
C.get_compiled_webkit_major_version(),
|
|
C.get_compiled_webkit_minor_version(),
|
|
C.get_compiled_webkit_micro_version(),
|
|
)
|
|
result["webkit2gtk-runtime"] = buildVersionString(
|
|
C.webkit_get_major_version(),
|
|
C.webkit_get_minor_version(),
|
|
C.webkit_get_micro_version(),
|
|
)
|
|
return result
|
|
}
|
|
|
|
func fatalHandler(errFunc func(error)) {
|
|
// Stub for windows function
|
|
return
|
|
}
|