[v3 linux] use invokeSync

This commit is contained in:
Travis McLane 2023-09-11 17:08:19 -05:00
commit 2f7c6834d0
12 changed files with 320 additions and 282 deletions

185
v3/go.mod
View file

@ -3,100 +3,101 @@ module github.com/wailsapp/wails/v3
go 1.21
require (
github.com/bep/debounce v1.2.1
github.com/ebitengine/purego v0.4.0-alpha.4
github.com/go-git/go-git/v5 v5.3.0
github.com/go-ole/go-ole v1.2.6
github.com/go-task/task/v3 v3.29.1
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/gorilla/pat v1.0.1
github.com/gorilla/sessions v1.2.1
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
github.com/leaanthony/clir v1.6.0
github.com/leaanthony/go-ansi-parser v1.6.1
github.com/leaanthony/gosod v1.0.3
github.com/leaanthony/winicon v1.0.0
github.com/lmittmann/tint v1.0.0
github.com/markbates/goth v1.77.0
github.com/matryer/is v1.4.0
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.19
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.51
github.com/samber/lo v1.38.1
github.com/shoenig/go-m1cpu v0.1.6
github.com/tc-hib/winres v0.1.6
github.com/wailsapp/go-webview2 v1.0.6-0.20230901120557-e959fdf1ccc3
github.com/wailsapp/mimetype v1.4.1
golang.org/x/net v0.10.0
golang.org/x/sys v0.11.0
modernc.org/sqlite v1.21.0
github.com/bep/debounce v1.2.1
github.com/ebitengine/purego v0.4.0-alpha.4
github.com/go-git/go-git/v5 v5.3.0
github.com/go-ole/go-ole v1.2.6
github.com/go-task/task/v3 v3.29.1
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/gorilla/pat v1.0.1
github.com/gorilla/sessions v1.2.1
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
github.com/leaanthony/clir v1.6.0
github.com/leaanthony/go-ansi-parser v1.6.1
github.com/leaanthony/gosod v1.0.3
github.com/leaanthony/winicon v1.0.0
github.com/lmittmann/tint v1.0.0
github.com/markbates/goth v1.77.0
github.com/matryer/is v1.4.0
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.19
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.51
github.com/samber/lo v1.38.1
github.com/shoenig/go-m1cpu v0.1.6
github.com/tc-hib/winres v0.1.6
github.com/wailsapp/go-webview2 v1.0.6-0.20230901120557-e959fdf1ccc3
github.com/wailsapp/mimetype v1.4.1
golang.org/x/net v0.10.0
golang.org/x/sys v0.11.0
modernc.org/sqlite v1.21.0
)
require (
atomicgo.dev/cursor v0.1.1 // indirect
atomicgo.dev/keyboard v0.2.8 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.2.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/gookit/color v1.5.2 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/mux v1.6.2 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/lithammer/fuzzysearch v1.1.5 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-zglob v0.0.4 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/radovskyb/watcher v1.0.7 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sajari/fuzzy v1.0.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.3 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
atomicgo.dev/cursor v0.1.1 // indirect
atomicgo.dev/keyboard v0.2.8 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.2.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/gookit/color v1.5.2 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/mux v1.6.2 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/lithammer/fuzzysearch v1.1.5 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-zglob v0.0.4 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/radovskyb/watcher v1.0.7 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sajari/fuzzy v1.0.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.3 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
)
replace github.com/ebitengine/purego v0.4.0-alpha.4 => github.com/tmclane/purego v0.0.0-20230601213035-1f25e70d7b01
// replace github.com/ebitengine/purego v0.4.0-alpha.4 => github.com/tmclane/purego v0.0.0-20230601213035-1f25e70d7b01
replace github.com/ebitengine/purego v0.4.0-alpha.4 => /home/tmclane/Projects/P/purego

View file

@ -2,6 +2,7 @@ package application
import (
"encoding/json"
"fmt"
"log"
"log/slog"
"net/http"
@ -446,7 +447,7 @@ func (a *App) Run() error {
a.runLock.Unlock()
// set the application menu
if runtime.GOOS == "darwin" || runtime.GOOS == "linux" {
if runtime.GOOS == "darwin" {
a.impl.setApplicationMenu(a.ApplicationMenu)
}
a.impl.setIcon(a.options.Icon)
@ -569,6 +570,7 @@ func (a *App) Quit() {
}
func (a *App) SetMenu(menu *Menu) {
fmt.Println("App.SetMenu")
a.ApplicationMenu = menu
if a.impl != nil {
a.impl.setApplicationMenu(menu)

View file

@ -51,11 +51,12 @@ func (m *linuxApp) show() {
func (m *linuxApp) on(eventID uint) {
// TODO: What do we need to do here?
log.Println("linuxApp.on()", eventID)
// log.Println("linuxApp.on()", eventID)
}
func (m *linuxApp) setIcon(icon []byte) {
fmt.Println("linuxApp.setIcon", "not implemented")
log.Println("linuxApp.setIcon", "not implemented")
}
func (m *linuxApp) name() string {
@ -66,17 +67,36 @@ func (m *linuxApp) getCurrentWindowID() uint {
return getCurrentWindowID(m.application, m.windows)
}
type rnr struct {
f func()
}
func (r rnr) run() {
r.f()
}
func (m *linuxApp) getApplicationMenu() pointer {
if m.applicationMenu != nilPointer {
return m.applicationMenu
}
menu := globalApplication.ApplicationMenu
if menu != nil {
invokeSync(func() {
menu.Update()
})
m.applicationMenu = (menu.impl).(*linuxMenu).native
}
return m.applicationMenu
}
func (m *linuxApp) setApplicationMenu(menu *Menu) {
// FIXME: How do we avoid putting a menu?
if menu == nil {
// Create a default menu
menu = defaultApplicationMenu()
globalApplication.ApplicationMenu = menu
}
globalApplication.dispatchOnMainThread(func() {
fmt.Println("setApplicationMenu")
menu.Update()
m.applicationMenu = (menu.impl).(*linuxMenu).native
})
}
func (m *linuxApp) run() error {
@ -96,8 +116,7 @@ func (m *linuxApp) destroy() {
}
func (m *linuxApp) isOnMainThread() bool {
// FIXME: How do we detect this properly?
return false
return isOnMainThread()
}
// register our window to our parent mapping

View file

@ -129,17 +129,23 @@ type pointer unsafe.Pointer
type GSList C.GSList
type GSListPointer *GSList
const (
nilPointer pointer = nil
nilRadioGroup GSListPointer = nil
)
var (
nilRadioGroup GSListPointer = nil
gtkSignalHandlers map[*C.GtkWidget]C.gulong
gtkSignalToMenuItem map[*C.GtkWidget]*MenuItem
mainThreadId *C.GThread
)
func init() {
fmt.Println("linux_cgo")
gtkSignalHandlers = map[*C.GtkWidget]C.gulong{}
gtkSignalToMenuItem = map[*C.GtkWidget]*MenuItem{}
mainThreadId = C.g_thread_self()
fmt.Println("init mainthread=", mainThreadId)
}
// mainthread stuff
@ -155,6 +161,13 @@ func dispatchOnMainThreadCallback(callbackID C.uint) {
//export activateLinux
func activateLinux(data pointer) {
// NOOP: Callback for now
fmt.Println("activateLinux", mainThreadId)
}
func isOnMainThread() bool {
threadId := C.g_thread_self()
// fmt.Println("isOnMainThread = ", threadId == mainThreadId)
return threadId == mainThreadId
}
// implementation below
@ -173,8 +186,16 @@ func appNew(name string) pointer {
func appRun(app pointer) error {
application := (*C.GApplication)(app)
C.g_application_hold(application) // allows it to run without a window
signal := C.CString("activate")
C.g_signal_connect_data(C.gpointer(application), signal, C.GCallback(C.activateLinux), nil, nil, 0)
defer C.free(unsafe.Pointer(signal))
C.g_signal_connect_data(
C.gpointer(application),
signal,
C.GCallback(C.activateLinux),
nil,
nil,
0)
status := C.g_application_run(application, 0, nil)
C.g_application_release(application)
C.g_object_unref(C.gpointer(app))
@ -557,13 +578,16 @@ func windowMinimize(window pointer) {
C.gtk_window_iconify((*C.GtkWindow)(window))
}
func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) (window pointer, webview pointer) {
func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) (window, webview, vbox pointer) {
window = pointer(C.gtk_application_window_new((*C.GtkApplication)(application)))
C.g_object_ref_sink(C.gpointer(window))
webview = windowNewWebview(windowId, gpuPolicy)
vbox := pointer(C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0))
C.gtk_container_add((*C.GtkContainer)(window), (*C.GtkWidget)(vbox))
vbox = pointer(C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0))
name := C.CString("webview-box")
defer C.free(unsafe.Pointer(name))
C.gtk_widget_set_name((*C.GtkWidget)(vbox), name)
C.gtk_container_add((*C.GtkContainer)(window), (*C.GtkWidget)(vbox))
if menu != nil {
C.gtk_box_pack_start((*C.GtkBox)(vbox), (*C.GtkWidget)(menu), 0, 0, 0)
}
@ -634,9 +658,20 @@ func windowShow(window pointer) {
C.gtk_widget_show_all((*C.GtkWidget)(window))
}
func windowSetBackgroundColour(webview pointer, colour RGBA) {
func windowSetBackgroundColour(vbox, webview pointer, colour RGBA) {
rgba := C.GdkRGBA{C.double(colour.Red) / 255.0, C.double(colour.Green) / 255.0, C.double(colour.Blue) / 255.0, C.double(colour.Alpha) / 255.0}
C.webkit_web_view_set_background_color((*C.WebKitWebView)(webview), &rgba)
colour.Alpha = 255
cssStr := C.CString(fmt.Sprintf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", colour.Red, colour.Green, colour.Blue, float32(colour.Alpha)/255.0))
provider := C.gtk_css_provider_new()
C.gtk_style_context_add_provider(
C.gtk_widget_get_style_context((*C.GtkWidget)(vbox)),
(*C.GtkStyleProvider)(unsafe.Pointer(provider)),
C.GTK_STYLE_PROVIDER_PRIORITY_USER)
C.g_object_unref(C.gpointer(provider))
C.gtk_css_provider_load_from_data(provider, cssStr, -1, nil)
C.free(unsafe.Pointer(cssStr))
}
func windowSetGeometryHints(window pointer, minWidth, minHeight, maxWidth, maxHeight int) {

View file

@ -25,6 +25,10 @@ type GSList struct {
type GSListPointer *GSList
const (
nilPointer pointer = 0
)
const (
GSourceRemove int = 0
@ -77,6 +81,7 @@ var (
nilRadioGroup GSListPointer = nil
gtkSignalHandlers map[pointer]uint = map[pointer]uint{}
gtkSignalToMenuItem map[pointer]*MenuItem = map[pointer]*MenuItem{}
mainThreadId uint64
)
const (
@ -87,9 +92,9 @@ const (
)
var (
gtk uintptr
version int
webkit uintptr
gtk uintptr
gtkVersion int
webkit uintptr
// function references
gApplicationHold func(pointer)
@ -107,6 +112,7 @@ var (
gSignalConnectObject func(pointer, string, pointer, pointer, int) uint
gSignalHandlerBlock func(pointer, uint)
gSignalHandlerUnblock func(pointer, uint)
gThreadSelf func() uint64
// gdk functions
gdkDisplayGetMonitor func(pointer, int) pointer
@ -225,7 +231,7 @@ func init() {
if err != nil {
panic(err)
}
version = 3
gtkVersion = 3
webkit, err = purego.Dlopen(webkit4, purego.RTLD_NOW|purego.RTLD_GLOBAL)
if err != nil {
@ -249,6 +255,7 @@ func init() {
purego.RegisterLibFunc(&gSignalConnectObject, gtk, "g_signal_connect_object")
purego.RegisterLibFunc(&gSignalHandlerBlock, gtk, "g_signal_handler_block")
purego.RegisterLibFunc(&gSignalHandlerUnblock, gtk, "g_signal_handler_unblock")
purego.RegisterLibFunc(&gThreadSelf, gtk, "g_thread_self")
// GDK
purego.RegisterLibFunc(&gdkDisplayGetMonitor, gtk, "gdk_display_get_monitor")
@ -352,6 +359,8 @@ func init() {
// mainthread stuff
func dispatchOnMainThread(id uint) {
fmt.Println("dispatchOnMainThread", gThreadSelf())
gIdleAdd(purego.NewCallback(func(pointer) int {
executeOnMainThread(id)
return GSourceRemove
@ -376,6 +385,9 @@ func appNew(name string) pointer {
}
func appRun(application pointer) error {
mainThreadId = gThreadSelf()
fmt.Println("linux_purego: appRun threadID", mainThreadId)
app := pointer(application)
activate := func() {
// TODO: Do we care?
@ -765,7 +777,7 @@ func windowMinimize(window pointer) {
gtkWindowMinimize(window)
}
func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) (pointer, pointer) {
func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) (pointer, pointer, pointer) {
window := gtkApplicationWindowNew(application)
gObjectRefSink(window)
webview := windowNewWebview(windowId, gpuPolicy)
@ -776,7 +788,7 @@ func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int)
gtkBoxPackStart(vbox, menu, 0, 0, 0)
}
gtkBoxPackStart(vbox, webview, 1, 1, 0)
return pointer(window), pointer(webview)
return pointer(window), pointer(webview), pointer(vbox)
}
func windowNewWebview(parentId uint, gpuPolicy int) pointer {
@ -826,7 +838,7 @@ func windowShow(window pointer) {
gtkWidgetShowAll(pointer(window))
}
func windowSetBackgroundColour(webview pointer, colour RGBA) {
func windowSetBackgroundColour(vbox, webview pointer, colour RGBA) {
// FIXME: Use a struct!
rgba := make([]byte, 4*8) // C.sizeof_GdkRGBA == 32
rgbaPointer := pointer(unsafe.Pointer(&rgba[0]))
@ -841,6 +853,19 @@ func windowSetBackgroundColour(webview pointer, colour RGBA) {
return
}
webkitWebViewSetBackgroundColor(pointer(webview), rgbaPointer)
/*
colour.Alpha = 255
cssStr := C.CString(fmt.Sprintf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", colour.Red, colour.Green, colour.Blue, float32(colour.Alpha)/255.0))
provider := C.gtk_css_provider_new()
C.gtk_style_context_add_provider(
C.gtk_widget_get_style_context((*C.GtkWidget)(vbox)),
(*C.GtkStyleProvider)(unsafe.Pointer(provider)),
C.GTK_STYLE_PROVIDER_PRIORITY_USER)
C.g_object_unref(C.gpointer(provider))
C.gtk_css_provider_load_from_data(provider, cssStr, -1, nil)
C.free(unsafe.Pointer(cssStr))
*/
}
func windowSetGeometryHints(window pointer, minWidth, minHeight, maxWidth, maxHeight int) {
@ -1151,3 +1176,7 @@ func runSaveFileDialog(dialog *SaveFileDialogStruct) (string, error) {
return results[0], nil
}
func isOnMainThread() bool {
return mainThreadId == gThreadSelf()
}

View file

@ -15,6 +15,10 @@ func newMenuImpl(menu *Menu) *linuxMenu {
return result
}
func (m *linuxMenu) run() {
m.update()
}
func (m *linuxMenu) update() {
m.processMenu(m.menu)
}

View file

@ -14,7 +14,7 @@ type linuxMenuItem struct {
}
func (l linuxMenuItem) setTooltip(tooltip string) {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func(){
l.blockSignal()
defer l.unBlockSignal()
menuItemSetToolTip(l.native, tooltip)
@ -34,7 +34,7 @@ func (l linuxMenuItem) unBlockSignal() {
}
func (l linuxMenuItem) setLabel(s string) {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetLabel(l.native, s)
@ -46,7 +46,7 @@ func (l linuxMenuItem) isChecked() bool {
}
func (l linuxMenuItem) setDisabled(disabled bool) {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetDisabled(l.native, disabled)
@ -54,7 +54,7 @@ func (l linuxMenuItem) setDisabled(disabled bool) {
}
func (l linuxMenuItem) setChecked(checked bool) {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetChecked(l.native, checked)
@ -62,7 +62,7 @@ func (l linuxMenuItem) setChecked(checked bool) {
}
func (l linuxMenuItem) setHidden(hidden bool) {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
widgetSetVisible(l.native, hidden)

View file

@ -16,7 +16,7 @@ func (m *linuxApp) getScreens() ([]*Screen, error) {
var screens []*Screen
var err error
wg.Add(1)
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
screens, err = getScreens(m.application)
wg.Done()
})

View file

@ -2,10 +2,11 @@ package application
import (
"fmt"
"github.com/wailsapp/wails/v3/pkg/events"
"runtime"
"sync"
"time"
"github.com/wailsapp/wails/v3/pkg/events"
)
type IconPosition int
@ -149,6 +150,7 @@ func (s *SystemTray) SetDarkModeIcon(icon []byte) *SystemTray {
}
func (s *SystemTray) SetMenu(menu *Menu) *SystemTray {
fmt.Println("SystemTray.SetMenu", menu, s.impl)
if s.impl == nil {
s.menu = menu
} else {

View file

@ -2,6 +2,8 @@
package application
import "fmt"
type linuxSystemTray struct {
id uint
label string
@ -17,6 +19,7 @@ func (s *linuxSystemTray) setIconPosition(position int) {
}
func (s *linuxSystemTray) setMenu(menu *Menu) {
fmt.Println("linuxSystemTray.SetMenu")
s.menu = menu
}
@ -33,7 +36,7 @@ func (s *linuxSystemTray) bounds() (*Rect, error) {
}
func (s *linuxSystemTray) run() {
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
// if s.nsStatusItem != nil {
// Fatal("System tray '%d' already running", s.id)
// }
@ -57,7 +60,7 @@ func (s *linuxSystemTray) run() {
func (s *linuxSystemTray) setIcon(icon []byte) {
s.icon = icon
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
// s.nsImage = unsafe.Pointer(C.imageFromBytes((*C.uchar)(&icon[0]), C.int(len(icon))))
// C.systemTraySetIcon(s.nsStatusItem, s.nsImage, C.int(s.iconPosition), C.bool(s.isTemplateIcon))
})
@ -65,7 +68,7 @@ func (s *linuxSystemTray) setIcon(icon []byte) {
func (s *linuxSystemTray) setDarkModeIcon(icon []byte) {
s.icon = icon
globalApplication.dispatchOnMainThread(func() {
invokeSync(func() {
// s.nsImage = unsafe.Pointer(C.imageFromBytes((*C.uchar)(&icon[0]), C.int(len(icon))))
// C.systemTraySetIcon(s.nsStatusItem, s.nsImage, C.int(s.iconPosition), C.bool(s.isTemplateIcon))
})

View file

@ -3,11 +3,12 @@ package application
import (
"errors"
"fmt"
"github.com/samber/lo"
"github.com/wailsapp/wails/v3/pkg/events"
"runtime"
"strings"
"sync"
"github.com/samber/lo"
"github.com/wailsapp/wails/v3/pkg/events"
)
type (
@ -277,7 +278,7 @@ func (w *WebviewWindow) Show() *WebviewWindow {
return w
}
if w.impl == nil {
w.run()
invokeSync(w.run)
return w
}
invokeSync(w.impl.show)
@ -657,10 +658,12 @@ func (w *WebviewWindow) Destroy() {
if w.impl == nil {
return
}
// Cancel the callbacks
for _, cancelFunc := range w.cancellers {
cancelFunc()
}
invokeSync(w.impl.destroy)
}

View file

@ -5,7 +5,6 @@ package application
import (
"fmt"
"net/url"
"sync"
"unsafe"
"github.com/wailsapp/wails/v3/pkg/events"
@ -104,21 +103,15 @@ func (w *linuxWebviewWindow) getScreen() (*Screen, error) {
}
func (w *linuxWebviewWindow) focus() {
globalApplication.dispatchOnMainThread(func() {
windowPresent(w.window)
})
windowPresent(w.window)
}
func (w *linuxWebviewWindow) show() {
globalApplication.dispatchOnMainThread(func() {
windowShow(w.window)
})
windowShow(w.window)
}
func (w *linuxWebviewWindow) hide() {
globalApplication.dispatchOnMainThread(func() {
windowHide(w.window)
})
windowHide(w.window)
}
func (w *linuxWebviewWindow) isNormal() bool {
@ -140,26 +133,21 @@ func (w *linuxWebviewWindow) disableSizeConstraints() {
}
func (w *linuxWebviewWindow) unfullscreen() {
fmt.Println("unfullscreen")
globalApplication.dispatchOnMainThread(func() {
windowUnfullscreen(w.window)
w.unmaximise()
})
windowUnfullscreen(w.window)
w.unmaximise()
}
func (w *linuxWebviewWindow) fullscreen() {
w.maximise()
w.lastWidth, w.lastHeight = w.size()
globalApplication.dispatchOnMainThread(func() {
x, y, width, height, scale := windowGetCurrentMonitorGeometry(w.window)
if x == -1 && y == -1 && width == -1 && height == -1 {
return
}
w.setMinMaxSize(0, 0, width*scale, height*scale)
w.setSize(width*scale, height*scale)
windowFullscreen(w.window)
w.setRelativePosition(0, 0)
})
x, y, width, height, scale := windowGetCurrentMonitorGeometry(w.window)
if x == -1 && y == -1 && width == -1 && height == -1 {
return
}
w.setMinMaxSize(0, 0, width*scale, height*scale)
w.setSize(width*scale, height*scale)
windowFullscreen(w.window)
w.setRelativePosition(0, 0)
}
func (w *linuxWebviewWindow) unminimise() {
@ -222,19 +210,17 @@ func (w *linuxWebviewWindow) forceReload() {
}
func (w *linuxWebviewWindow) center() {
globalApplication.dispatchOnMainThread(func() {
x, y, width, height, _ := windowGetCurrentMonitorGeometry(w.window)
if x == -1 && y == -1 && width == -1 && height == -1 {
return
}
windowWidth, windowHeight := windowGetSize(w.window)
x, y, width, height, _ := windowGetCurrentMonitorGeometry(w.window)
if x == -1 && y == -1 && width == -1 && height == -1 {
return
}
windowWidth, windowHeight := windowGetSize(w.window)
newX := ((width - int(windowWidth)) / 2) + x
newY := ((height - int(windowHeight)) / 2) + y
newX := ((width - int(windowWidth)) / 2) + x
newY := ((height - int(windowHeight)) / 2) + y
// Place the window at the center of the monitor
windowMove(w.window, newX, newY)
})
// Place the window at the center of the monitor
windowMove(w.window, newX, newY)
}
func (w *linuxWebviewWindow) isMinimised() bool {
@ -242,27 +228,11 @@ func (w *linuxWebviewWindow) isMinimised() bool {
}
func (w *linuxWebviewWindow) isMaximised() bool {
return w.syncMainThreadReturningBool(func() bool {
return windowIsMaximized(w.window)
})
return windowIsMaximized(w.window)
}
func (w *linuxWebviewWindow) isFullscreen() bool {
return w.syncMainThreadReturningBool(func() bool {
return windowIsFullscreen(w.window)
})
}
func (w *linuxWebviewWindow) syncMainThreadReturningBool(fn func() bool) bool {
var wg sync.WaitGroup
wg.Add(1)
var result bool
globalApplication.dispatchOnMainThread(func() {
result = fn()
wg.Done()
})
wg.Wait()
return result
return windowIsFullscreen(w.window)
}
func (w *linuxWebviewWindow) restore() {
@ -344,26 +314,12 @@ func (w *linuxWebviewWindow) toggleDevTools() {
}
func (w *linuxWebviewWindow) size() (int, int) {
/* var width, height C.int
var wg sync.WaitGroup
wg.Add(1)
globalApplication.dispatchOnMainThread(func() {
C.gtk_window_get_size((*C.GtkWindow)(w.window), &width, &height)
wg.Done()
})
wg.Wait()
return int(width), int(height)
*/
// Does this need to be guarded?
return windowGetSize(w.window)
}
func (w *linuxWebviewWindow) setRelativePosition(x, y int) {
mx, my, _, _, _ := windowGetCurrentMonitorGeometry(w.window)
globalApplication.dispatchOnMainThread(func() {
windowMove(w.window, x+mx, y+my)
})
windowMove(w.window, x+mx, y+my)
}
func (w *linuxWebviewWindow) width() int {
@ -383,13 +339,7 @@ func (w *linuxWebviewWindow) setAbsolutePosition(x int, y int) {
func (w *linuxWebviewWindow) absolutePosition() (int, int) {
var x, y int
var wg sync.WaitGroup
wg.Add(1)
globalApplication.dispatchOnMainThread(func() {
x, y = windowGetAbsolutePosition(w.window)
wg.Done()
})
wg.Wait()
x, y = windowGetAbsolutePosition(w.window)
return x, y
}
@ -399,76 +349,74 @@ func (w *linuxWebviewWindow) run() {
}
app := getNativeApplication()
menu := app.applicationMenu
globalApplication.dispatchOnMainThread(func() {
w.window, w.webview = windowNew(app.application, menu, w.parent.id, 1)
app.registerWindow(w.window, w.parent.id) // record our mapping
w.connectSignals()
if w.parent.options.EnableDragAndDrop {
w.enableDND()
}
w.setTitle(w.parent.options.Title)
w.setAlwaysOnTop(w.parent.options.AlwaysOnTop)
w.setResizable(!w.parent.options.DisableResize)
// only set min/max size if actually set
if w.parent.options.MinWidth != 0 &&
w.parent.options.MinHeight != 0 &&
w.parent.options.MaxWidth != 0 &&
w.parent.options.MaxHeight != 0 {
w.setMinMaxSize(
w.parent.options.MinWidth,
w.parent.options.MinHeight,
w.parent.options.MaxWidth,
w.parent.options.MaxHeight,
)
}
w.setSize(w.parent.options.Width, w.parent.options.Height)
w.setZoom(w.parent.options.Zoom)
w.setBackgroundColour(w.parent.options.BackgroundColour)
w.setFrameless(w.parent.options.Frameless)
menu := app.getApplicationMenu()
w.window, w.webview, w.vbox = windowNew(app.application, menu, w.parent.id, 1)
app.registerWindow(w.window, w.parent.id) // record our mapping
w.connectSignals()
if w.parent.options.EnableDragAndDrop {
w.enableDND()
}
w.setTitle(w.parent.options.Title)
w.setAlwaysOnTop(w.parent.options.AlwaysOnTop)
w.setResizable(!w.parent.options.DisableResize)
// only set min/max size if actually set
if w.parent.options.MinWidth != 0 &&
w.parent.options.MinHeight != 0 &&
w.parent.options.MaxWidth != 0 &&
w.parent.options.MaxHeight != 0 {
w.setMinMaxSize(
w.parent.options.MinWidth,
w.parent.options.MinHeight,
w.parent.options.MaxWidth,
w.parent.options.MaxHeight,
)
}
w.setSize(w.parent.options.Width, w.parent.options.Height)
w.setZoom(w.parent.options.Zoom)
w.setBackgroundColour(w.parent.options.BackgroundColour)
w.setFrameless(w.parent.options.Frameless)
if w.parent.options.X != 0 || w.parent.options.Y != 0 {
w.setRelativePosition(w.parent.options.X, w.parent.options.Y)
} else {
fmt.Println("attempting to set in the center")
w.center()
}
switch w.parent.options.StartState {
case WindowStateMaximised:
w.maximise()
case WindowStateMinimised:
w.minimise()
case WindowStateFullscreen:
w.fullscreen()
}
if w.parent.options.URL != "" {
w.setURL(w.parent.options.URL)
}
// 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) {
if w.parent.options.JS != "" {
w.execJS(w.parent.options.JS)
}
if w.parent.options.CSS != "" {
js := fmt.Sprintf("(function() { var style = document.createElement('style'); style.appendChild(document.createTextNode('%s')); document.head.appendChild(style); })();", w.parent.options.CSS)
w.execJS(js)
}
})
if w.parent.options.HTML != "" {
w.setHTML(w.parent.options.HTML)
}
if !w.parent.options.Hidden {
w.show()
if w.parent.options.X != 0 || w.parent.options.Y != 0 {
w.setRelativePosition(w.parent.options.X, w.parent.options.Y)
} else {
fmt.Println("attempting to set in the center")
w.center()
w.center() // needs to be queued until after GTK starts up!
}
switch w.parent.options.StartState {
case WindowStateMaximised:
w.maximise()
case WindowStateMinimised:
w.minimise()
case WindowStateFullscreen:
w.fullscreen()
}
if w.parent.options.URL != "" {
w.setURL(w.parent.options.URL)
}
// 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) {
if w.parent.options.JS != "" {
w.execJS(w.parent.options.JS)
}
if w.parent.options.CSS != "" {
js := fmt.Sprintf("(function() { var style = document.createElement('style'); style.appendChild(document.createTextNode('%s')); document.head.appendChild(style); })();", w.parent.options.CSS)
w.execJS(js)
}
})
if w.parent.options.HTML != "" {
w.setHTML(w.parent.options.HTML)
}
if !w.parent.options.Hidden {
w.show()
if w.parent.options.X != 0 || w.parent.options.Y != 0 {
w.setRelativePosition(w.parent.options.X, w.parent.options.Y)
} else {
w.center() // needs to be queued until after GTK starts up!
}
}
})
}
}
func (w *linuxWebviewWindow) setTransparent() {
@ -479,18 +427,12 @@ func (w *linuxWebviewWindow) setBackgroundColour(colour RGBA) {
if colour.Alpha < 255 {
w.setTransparent()
}
windowSetBackgroundColour(w.webview, colour)
windowSetBackgroundColour(w.vbox, w.webview, colour)
}
func (w *linuxWebviewWindow) relativePosition() (int, int) {
var x, y int
var wg sync.WaitGroup
wg.Add(1)
go globalApplication.dispatchOnMainThread(func() {
x, y = windowGetRelativePosition(w.window)
wg.Done()
})
wg.Wait()
x, y = windowGetRelativePosition(w.window)
return x, y
}
@ -499,9 +441,7 @@ func (w *linuxWebviewWindow) destroy() {
}
func (w *linuxWebviewWindow) setEnabled(enabled bool) {
globalApplication.dispatchOnMainThread(func() {
widgetSetSensitive(w.window, enabled)
})
widgetSetSensitive(w.window, enabled)
}
func (w *linuxWebviewWindow) setHTML(html string) {