diff --git a/qt6/mainthread/mainthread.cpp b/qt6/mainthread/mainthread.cpp new file mode 100644 index 00000000..a87d2b6b --- /dev/null +++ b/qt6/mainthread/mainthread.cpp @@ -0,0 +1,13 @@ +#include +#include + +#ifndef _Bool +#define _Bool bool +#endif +#include "_cgo_export.h" + +void mainthread_exec(intptr_t cb) { + QMetaObject::invokeMethod(qApp, [=]{ + mainthread_exec_handle(cb); + }, Qt::QueuedConnection); +} diff --git a/qt6/mainthread/mainthread.go b/qt6/mainthread/mainthread.go new file mode 100644 index 00000000..b37921d1 --- /dev/null +++ b/qt6/mainthread/mainthread.go @@ -0,0 +1,69 @@ +package mainthread + +import ( + "sync" + "runtime/cgo" +) + +/* +#cgo pkg-config: Qt6Core + +#include "mainthread.h" +*/ +import "C" + +// Start runs the callback in the main Qt thread. You should use this whenever +// accessing the main Qt GUI from inside a goroutine. +// This function is non-blocking. +func Start(gofunc func()) { + h := cgo.NewHandle(gofunc) + + C.mainthread_exec(C.intptr_t(h)) +} + +// Wait runs the callback in the main Qt thread. You should use this whenever +// accessing the main Qt GUI from inside a goroutine. +// The call blocks until the callback is executed in the main thread's eventloop. +func Wait(gofunc func()) { + // It's possible to use Qt::BlockingQueuedConnection to implement the + // blocking, but it has a deadlock risk + var wg sync.WaitGroup + wg.Add(1) + outerfunc := func() { + gofunc() + wg.Done() + } + Start(outerfunc) + wg.Wait() +} + +func Wait2[T any](gofunc func() T) (ret T) { + outerfunc := func() { + ret = gofunc() + } + Wait(outerfunc) + return ret +} + +func Wait3[T any](gofunc func() (T, error)) (ret T, err error) { + outerfunc := func() { + ret, err = gofunc() + } + Wait(outerfunc) + return ret, err +} + +//export mainthread_exec_handle +func mainthread_exec_handle(u uintptr) { + h := cgo.Handle(u) + + gofunc, ok := h.Value().(func()) + if !ok { + panic("miqt: callback of non-callback type (heap corruption?)") + } + + gofunc() + + // Free handle after use + h.Delete() +} diff --git a/qt6/mainthread/mainthread.h b/qt6/mainthread/mainthread.h new file mode 100644 index 00000000..f3124d07 --- /dev/null +++ b/qt6/mainthread/mainthread.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef QT_MAINTHREAD_H +#define QT_MAINTHREAD_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void mainthread_exec(intptr_t cb); + +#ifdef __cplusplus +} +#endif + +#endif