示例#1
0
func initGoType(fold *valueFold) {
	if cdata.Ref() == atomic.LoadUintptr(&guiPaintRef) {
		go RunMain(func() { _initGoType(fold, true) })
	} else {
		_initGoType(fold, false)
	}
}
示例#2
0
// wrapGoValue creates a new GoValue object in C++ land wrapping
// the Go value contained in the given interface.
//
// This must be run from the main GUI thread.
func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue unsafe.Pointer) {
	gvaluev := reflect.ValueOf(gvalue)
	gvaluek := gvaluev.Kind()
	if gvaluek == reflect.Struct && !hashable(gvalue) {
		name := gvaluev.Type().Name()
		if name != "" {
			name = " (" + name + ")"
		}
		panic("cannot hand an unhashable struct value" + name + " to QML logic; use its address instead")
	}
	if gvaluek == reflect.Ptr && gvaluev.Elem().Kind() == reflect.Ptr {
		panic("cannot hand pointer of pointer to QML logic; use a simple pointer instead")
	}

	painting := cdata.Ref() == atomic.LoadUintptr(&guiPaintRef)

	// Cannot reuse a jsOwner because the QML runtime may choose to destroy
	// the value _after_ we hand it a new reference to the same value.
	// See issue #68 for details.
	prev, ok := engine.values[gvalue]
	if ok && (prev.owner == cppOwner || painting) {
		return prev.cvalue
	}

	if painting {
		panic("cannot allocate new objects while painting")
	}

	parent := nilPtr
	if owner == cppOwner {
		parent = engine.addr
	}
	fold := &valueFold{
		engine: engine,
		gvalue: gvalue,
		owner:  owner,
	}
	fold.cvalue = C.newGoValue(unsafe.Pointer(fold), typeInfo(gvalue), parent)
	if prev != nil {
		// Put new fold first so the single cppOwner, if any, is always the first entry.
		fold.next = prev
		prev.prev = fold
	}
	engine.values[gvalue] = fold

	//fmt.Printf("[DEBUG] value alive (wrapped): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
	stats.valuesAlive(+1)
	C.engineSetContextForObject(engine.addr, fold.cvalue)
	switch owner {
	case cppOwner:
		C.engineSetOwnershipCPP(engine.addr, fold.cvalue)
	case jsOwner:
		C.engineSetOwnershipJS(engine.addr, fold.cvalue)
	}
	return fold.cvalue
}
示例#3
0
// Run runs the main QML event loop, runs f, and then terminates the
// event loop once f returns.
//
// Most functions from the qml package block until Run is called.
//
// The Run function must necessarily be called from the same goroutine as
// the main function or the application may fail when running on Mac OS.
func Run(f func() error) error {
	if cdata.Ref() != guiMainRef {
		panic("Run must be called on the initial goroutine so apps are portable to Mac OS")
	}
	if !atomic.CompareAndSwapInt32(&initialized, 0, 1) {
		panic("qml.Run called more than once")
	}
	C.newGuiApplication()
	C.idleTimerInit((*C.int32_t)(&guiIdleRun))
	done := make(chan error, 1)
	go func() {
		RunMain(func() {}) // Block until the event loop is running.
		done <- f()
		C.applicationExit()
	}()
	C.applicationExec()
	return <-done
}
示例#4
0
// RunMain runs f in the main QML thread and waits for f to return.
//
// This is meant to be used by extensions that integrate directly with the
// underlying QML logic.
func RunMain(f func()) {
	ref := cdata.Ref()
	if ref == guiMainRef || ref == atomic.LoadUintptr(&guiPaintRef) {
		// Already within the GUI or render threads. Attempting to wait would deadlock.
		f()
		return
	}

	// Tell Qt we're waiting for the idle hook to be called.
	if atomic.AddInt32(&guiIdleRun, 1) == 1 {
		C.idleTimerStart()
	}

	// Send f to be executed by the idle hook in the main GUI thread.
	guiFunc <- f

	// Wait until f is done executing.
	<-guiDone
}
示例#5
0
//export hookGoValuePaint
func hookGoValuePaint(enginep, foldp unsafe.Pointer, reflectIndex C.intptr_t) {
	// Besides a convenience this is a workaround for http://golang.org/issue/8588
	defer printPaintPanic()
	defer atomic.StoreUintptr(&guiPaintRef, 0)

	// The main GUI thread is mutex-locked while paint methods are called,
	// so no two paintings should be happening at the same time.
	atomic.StoreUintptr(&guiPaintRef, cdata.Ref())

	fold := ensureEngine(enginep, foldp)
	if fold.init.IsValid() {
		return
	}

	painter := &Painter{engine: fold.engine, obj: &Common{fold.cvalue, fold.engine, newConnections()}}
	v := reflect.ValueOf(fold.gvalue)
	method := v.Method(int(reflectIndex))
	method.Call([]reflect.Value{reflect.ValueOf(painter)})
}
示例#6
0
func init() {
	runtime.LockOSThread()
	guiMainRef = cdata.Ref()
}