Added cgo-safe callback code for GTK+ signals. GTK+ signals work!
This commit is contained in:
parent
c40b7b5599
commit
7a99d42d65
|
@ -0,0 +1,27 @@
|
||||||
|
// +build !windows,!darwin,!plan9
|
||||||
|
|
||||||
|
// 16 february 2014
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
cgo doesn't support calling Go functions by default; we have to mark them for export. Not a problem, except arguments to GTK+ callbacks depend on the callback itself. Since we're generating callback functions as simple closures of one type, this file will wrap the generated callbacks in the appropriate callback type. We pass the actual generated pointer to the extra data parameter of the callback.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #cgo pkg-config: gtk+-3.0
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// extern gboolean our_delete_event_callback(GtkWidget *, GdkEvent *, gpointer);
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
//export our_delete_event_callback
|
||||||
|
func our_delete_event_callback(widget *C.GtkWidget, event *C.GdkEvent, what C.gpointer) C.gboolean {
|
||||||
|
f := *(*func() bool)(unsafe.Pointer(what))
|
||||||
|
return togbool(f())
|
||||||
|
}
|
||||||
|
|
||||||
|
var callbacks = map[string]C.GCallback{
|
||||||
|
"delete-event": C.GCallback(C.our_delete_event_callback),
|
||||||
|
}
|
|
@ -5,9 +5,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// #cgo pkg-config: gtk+-3.0
|
// #cgo pkg-config: gtk+-3.0
|
||||||
|
@ -21,10 +19,6 @@ import "C"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
gtkWidget C.GtkWidget
|
gtkWidget C.GtkWidget
|
||||||
|
|
||||||
// these are needed for signals
|
|
||||||
gdkEvent C.GdkEvent
|
|
||||||
gpointer C.gpointer
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func fromgbool(b C.gboolean) bool {
|
func fromgbool(b C.gboolean) bool {
|
||||||
|
@ -64,22 +58,16 @@ func gtk_window_new() *gtkWidget {
|
||||||
return (*gtkWidget)(unsafe.Pointer(C.gtk_window_new(0)))
|
return (*gtkWidget)(unsafe.Pointer(C.gtk_window_new(0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// because *gtkWidget and *C.GtkWidget are not compatible
|
// shorthand
|
||||||
func gtkwidget(g *gtkWidget) (*C.GtkWidget) {
|
func gtkwidget(what *gtkWidget) *C.GtkWidget {
|
||||||
return (*C.GtkWidget)(unsafe.Pointer(g))
|
return (*C.GtkWidget)(unsafe.Pointer(what))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do we need the argument?
|
func g_signal_connect(obj *gtkWidget, sig string, callback func() bool) {
|
||||||
// TODO fine-tune the function type
|
ccallback := callbacks[sig]
|
||||||
func g_signal_connect(obj *gtkWidget, sig string, callback interface{}) {
|
|
||||||
v := reflect.ValueOf(callback)
|
|
||||||
if v.Kind() != reflect.Func {
|
|
||||||
panic(fmt.Sprintf("UI library internal error: callback %v given to g_signal_connect not a function", v))
|
|
||||||
}
|
|
||||||
ccallback := C.GCallback(unsafe.Pointer(v.Pointer()))
|
|
||||||
csig := C.CString(sig)
|
csig := C.CString(sig)
|
||||||
defer C.free(unsafe.Pointer(csig))
|
defer C.free(unsafe.Pointer(csig))
|
||||||
C.gSignalConnect(gtkwidget(obj), csig, ccallback, unsafe.Pointer(nil))
|
C.gSignalConnect(gtkwidget(obj), csig, ccallback, unsafe.Pointer(&callback))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO ensure this works if called on an individual control
|
// TODO ensure this works if called on an individual control
|
||||||
|
|
|
@ -19,16 +19,16 @@ type classData struct {
|
||||||
make func() *gtkWidget
|
make func() *gtkWidget
|
||||||
setText func(widget *gtkWidget, text string)
|
setText func(widget *gtkWidget, text string)
|
||||||
// ...
|
// ...
|
||||||
signals map[string]func(*sysData) interface{}
|
signals map[string]func(*sysData) func() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var classTypes = [nctypes]*classData{
|
var classTypes = [nctypes]*classData{
|
||||||
c_window: &classData{
|
c_window: &classData{
|
||||||
make: gtk_window_new,
|
make: gtk_window_new,
|
||||||
setText: gtk_window_set_title,
|
setText: gtk_window_set_title,
|
||||||
signals: map[string]func(*sysData) interface{}{
|
signals: map[string]func(*sysData) func() bool{
|
||||||
"delete-event": func(w *sysData) interface{} {
|
"delete-event": func(w *sysData) func() bool {
|
||||||
return func(*gtkWidget, *gdkEvent, gpointer) bool {
|
return func() bool {
|
||||||
if w.event != nil {
|
if w.event != nil {
|
||||||
w.event <- struct{}{}
|
w.event <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue