github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/linux/invoke.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package linux
     5  
     6  /*
     7  #cgo linux pkg-config: gtk+-3.0
     8  
     9  #include <stdio.h>
    10  #include "gtk/gtk.h"
    11  
    12  extern gboolean invokeCallbacks(void *);
    13  
    14  static inline void triggerInvokesOnMainThread() {
    15      g_idle_add((GSourceFunc)invokeCallbacks, NULL);
    16  }
    17  */
    18  import "C"
    19  import (
    20  	"runtime"
    21  	"sync"
    22  	"unsafe"
    23  
    24  	"golang.org/x/sys/unix"
    25  )
    26  
    27  var (
    28  	m         sync.Mutex
    29  	mainTid   int
    30  	dispatchq []func()
    31  )
    32  
    33  func invokeOnMainThread(f func()) {
    34  	if tryInvokeOnCurrentGoRoutine(f) {
    35  		return
    36  	}
    37  
    38  	m.Lock()
    39  	dispatchq = append(dispatchq, f)
    40  	m.Unlock()
    41  
    42  	C.triggerInvokesOnMainThread()
    43  }
    44  
    45  func tryInvokeOnCurrentGoRoutine(f func()) bool {
    46  	m.Lock()
    47  	mainThreadID := mainTid
    48  	m.Unlock()
    49  
    50  	runtime.LockOSThread()
    51  	defer runtime.UnlockOSThread()
    52  
    53  	if mainThreadID != unix.Gettid() {
    54  		return false
    55  	}
    56  	f()
    57  	return true
    58  }
    59  
    60  //export invokeCallbacks
    61  func invokeCallbacks(_ unsafe.Pointer) C.gboolean {
    62  	runtime.LockOSThread()
    63  	defer runtime.UnlockOSThread()
    64  
    65  	m.Lock()
    66  	if mainTid == 0 {
    67  		mainTid = unix.Gettid()
    68  	}
    69  
    70  	q := append([]func(){}, dispatchq...)
    71  	dispatchq = []func(){}
    72  	m.Unlock()
    73  
    74  	for _, v := range q {
    75  		v()
    76  	}
    77  	return C.G_SOURCE_REMOVE
    78  }