diff --git a/go.mod b/go.mod index ce33273..00758d6 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.brut.systems/judah/xx go 1.25.0 + +require github.com/ebitengine/purego v0.9.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..13a1cc2 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= +github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= diff --git a/osthread/osthread.go b/osthread/osthread.go index 8be5ec2..c855f66 100644 --- a/osthread/osthread.go +++ b/osthread/osthread.go @@ -50,16 +50,20 @@ func Go(fn func()) { // Call schedules a function to be run on the main operating system thread, blocking until it returns. func Call(fn func()) { - done := make(chan any) - queue <- func() { - defer func() { - done <- nil - }() - + if onmainthread() { fn() - } + } else { + done := make(chan any) + queue <- func() { + defer func() { + done <- nil + }() - <-done + fn() + } + + <-done + } } var queue chan func() diff --git a/osthread/osthread_anyone.go b/osthread/osthread_anyone.go new file mode 100644 index 0000000..cd85c4c --- /dev/null +++ b/osthread/osthread_anyone.go @@ -0,0 +1,7 @@ +//go:build !(windows || unix || darwin) + +package osthread + +func onmainthread() bool { + return false +} diff --git a/osthread/osthread_darwin.go b/osthread/osthread_darwin.go new file mode 100644 index 0000000..d2aea0d --- /dev/null +++ b/osthread/osthread_darwin.go @@ -0,0 +1,33 @@ +//go:build darwin + +package osthread + +import "github.com/ebitengine/purego/objc" + +func onmainthread() bool { + return objc.Send[bool](objc.ID(cls_nsthread), sel_isMainThread) +} + +var ( + cls_nsthread objc.Class + cls_nsapplication objc.Class + cls_nsapp objc.Class + + sel_isMainThread objc.SEL + sel_sharedApplication objc.SEL + sel_run objc.SEL +) + +func init() { + cls_nsthread = objc.GetClass("NSThread") + cls_nsapplication = objc.GetClass("NSApplication") + cls_nsapp = objc.GetClass("NSApp") + + sel_isMainThread = objc.RegisterName("isMainThread") + sel_sharedApplication = objc.RegisterName("sharedApplication") + sel_run = objc.RegisterName("run") + + // Just a bit of magic + objc.ID(cls_nsapplication).Send(sel_sharedApplication) + objc.ID(cls_nsapp).Send(sel_run) +} diff --git a/osthread/osthread_linux.go b/osthread/osthread_linux.go new file mode 100644 index 0000000..b5c1a6d --- /dev/null +++ b/osthread/osthread_linux.go @@ -0,0 +1,26 @@ +//go:build linux + +package osthread + +import ( + "github.com/ebitengine/purego" +) + +func onmainthread() bool { + return getpid() == gettid() +} + +var ( + getpid func() int32 + gettid func() int32 +) + +func init() { + libc, err := purego.Dlopen("libc.so.6", purego.RTLD_GLOBAL|purego.RTLD_NOW) + if err != nil { + panic(err) + } + + purego.RegisterLibFunc(&getpid, libc, "getpid") + purego.RegisterLibFunc(&gettid, libc, "gettid") +} diff --git a/osthread/osthread_windows.go b/osthread/osthread_windows.go new file mode 100644 index 0000000..0c7cff3 --- /dev/null +++ b/osthread/osthread_windows.go @@ -0,0 +1,24 @@ +//go:build windows + +package osthread + +import ( + "syscall" + + "github.com/ebitengine/purego" +) + +func onmainthread() bool { + return mainThreadId == getCurrentThreadId() +} + +var ( + mainThreadId int32 + getCurrentThreadId func() int32 +) + +func init() { + kernel32 := syscall.NewLazyDLL("kernel.dll").Handle() + purego.RegisterLibFunc(&getCurrentThreadId, kernel32, "GetCurrentThreadId") + mainThreadId = getCurrentThreadId() +}