Improved signals handling

This commit is contained in:
Michał Derkacz
2011-09-21 17:49:50 +02:00
parent 74ef31ccab
commit d80fb2adea
3 changed files with 44 additions and 35 deletions

View File

@@ -42,31 +42,31 @@ func TestSignal(t *testing.T) {
// Connect a.handler(*Object, int) to the signal. // Connect a.handler(*Object, int) to the signal.
// o will be passed as its first argument. Second argument of type int will // o will be passed as its first argument. Second argument of type int will
// be passed from second argument passed to the Emit function. // be passed from second argument passed to the Emit function.
o.ConnectSid(s, (*A).handler, &a) o.ConnectSid(s, 0, (*A).handler, &a)
// Connect a.noiHandler(int) to the signal. // Connect a.noiHandler(int) to the signal.
// o will not be passed to the method. An argument of type int will be // o will not be passed to the method. An argument of type int will be
// passed from second argument passed to the Emit function. // passed from second argument passed to the Emit function.
o.ConnectSidNoi(s, (*A).noiHandler, &a) o.ConnectSidNoi(s, 0, (*A).noiHandler, &a)
// Connect funcHandler(*Object, int)to the signal. // Connect funcHandler(*Object, int)to the signal.
// o will be passed as its first argument. Second argument of type int // o will be passed as its first argument. Second argument of type int
// will be passed from second argument passed to the Emit function. // will be passed from second argument passed to the Emit function.
o.ConnectSid(s, funcHandler, nil) o.ConnectSid(s, 0, funcHandler, nil)
// Connect funcNoiHandler(int) to the signal. // Connect funcNoiHandler(int) to the signal.
// o will not be passed to the function. An argument of type int will be // o will not be passed to the function. An argument of type int will be
// passed from second argument passed to the Emit function. // passed from second argument passed to the Emit function.
o.ConnectSidNoi(s, funcNoiHandler, nil) o.ConnectSidNoi(s, 0, funcNoiHandler, nil)
// Connect funcHandlerParam0(A, *Object, int) to the signal. // Connect funcHandlerParam0(A, *Object, int) to the signal.
// &a will be passed as its first argument, o will be passed as its second // &a will be passed as its first argument, o will be passed as its second
// argument. The thrid argument of type int will be from second argument // argument. The thrid argument of type int will be from second argument
// passed to the Emit function. // passed to the Emit function.
o.ConnectSid(s, funcHandlerParam0, &a) o.ConnectSid(s, 0, funcHandlerParam0, &a)
// Emit signal with 123 integer as argument. // Emit signal with 123 integer as argument.
o.EmitById(s, 123) o.EmitById(s, 0, 123)
} }
// Like TestSignal but uses signal names // Like TestSignal but uses signal names

View File

@@ -81,24 +81,20 @@ GoClosure* _object_closure_new(gboolean no_inst, gpointer p0) {
} }
static inline static inline
gulong _signal_connect(GObject* inst, guint sig, GoClosure* cl) { gulong _signal_connect(GObject* inst, guint id, GQuark detail, GoClosure* cl) {
return g_signal_connect_closure_by_id( return g_signal_connect_closure_by_id(
inst, inst,
sig, id,
0, detail,
(GClosure*) cl, (GClosure*) cl,
TRUE TRUE
); );
} }
static inline static inline
void _signal_emit(const GValue *inst_and_params, guint sig, GValue *ret) { void _signal_emit(const GValue *inst_and_params, guint id, GQuark detail,
return g_signal_emitv( GValue *ret) {
inst_and_params, return g_signal_emitv( inst_and_params, id, detail, ret);
sig,
0,
ret
);
} }
*/ */
import "C" import "C"
@@ -174,9 +170,9 @@ func (o *Object) GetProperty(name string) interface{} {
return v.Get() return v.Get()
} }
func (o *Object) EmitById(sig SignalId, args ...interface{}) interface{} { func (o *Object) EmitById(sid SignalId, detail Quark, args ...interface{}) interface{} {
var sq C.GSignalQuery var sq C.GSignalQuery
C.g_signal_query(C.guint(sig), &sq) C.g_signal_query(C.guint(sid), &sq)
if len(args) != int(sq.n_params) { if len(args) != int(sq.n_params) {
panic(fmt.Sprintf( panic(fmt.Sprintf(
"*Object.EmitById "+ "*Object.EmitById "+
@@ -190,12 +186,13 @@ func (o *Object) EmitById(sig SignalId, args ...interface{}) interface{} {
prms[i+1] = *ValueOf(a) prms[i+1] = *ValueOf(a)
} }
ret := new(Value) ret := new(Value)
C._signal_emit(prms[0].g(), C.guint(sig), ret.g()) C._signal_emit(prms[0].g(), C.guint(sid), C.GQuark(detail), ret.g())
return ret.Get() return ret.Get()
} }
func (o *Object) Emit(sig_name string, args ...interface{}) interface{} { func (o *Object) Emit(sig_name string, args ...interface{}) interface{} {
return o.EmitById(SignalLookup(sig_name, o.Type()), args...) sid, detail := SignalLookup(sig_name, o.Type())
return o.EmitById(sid, detail, args...)
} }
type SigHandlerId C.gulong type SigHandlerId C.gulong
@@ -206,16 +203,18 @@ type sigHandler struct {
var obj_handlers = make(map[uintptr]map[SigHandlerId]*sigHandler) var obj_handlers = make(map[uintptr]map[SigHandlerId]*sigHandler)
func (o *Object) connect(noi bool, sig SignalId, cb_func, param0 interface{}) { func (o *Object) connect(noi bool, sid SignalId, detail Quark, cb_func,
param0 interface{}) {
cb := reflect.ValueOf(cb_func) cb := reflect.ValueOf(cb_func)
if cb.Kind() != reflect.Func { if cb.Kind() != reflect.Func {
panic("cb_func isn't a function") panic("cb_func isn't a function")
} }
// Check that function parameters and return value match to signal // Check that function parameters and return value match to signal
var sq C.GSignalQuery var sq C.GSignalQuery
C.g_signal_query(C.guint(sig), &sq)
C.g_signal_query(C.guint(sid), &sq)
ft := cb.Type() ft := cb.Type()
if ft.NumOut() > 1 || ft.NumOut() == 1 && Type(sq.return_type)== TYPE_NONE { if ft.NumOut() > 1 || ft.NumOut() == 1 && Type(sq.return_type) == TYPE_NONE {
panic("Number of function return values doesn't match signal spec.") panic("Number of function return values doesn't match signal spec.")
} }
poffset := 2 poffset := 2
@@ -238,12 +237,12 @@ func (o *Object) connect(noi bool, sig SignalId, cb_func, param0 interface{}) {
panic("Type of function return value doesn't match signal spec.") panic("Type of function return value doesn't match signal spec.")
} }
if n_params > 0 { if n_params > 0 {
pt := (*[1<<16]Type)(unsafe.Pointer(sq.param_types))[:int(sq.n_params)] pt := (*[1 << 16]Type)(unsafe.Pointer(sq.param_types))[:int(sq.n_params)]
for i := 0; i < n_params; i++ { for i := 0; i < n_params; i++ {
if !pt[i].Match(ft.In(i + poffset)) { if !pt[i].Match(ft.In(i + poffset)) {
panic(fmt.Sprintf( panic(fmt.Sprintf(
"Callback #%d param. type %s doesn't match signal spec %s", "Callback #%d param. type %s doesn't match signal spec %s",
i+1, ft.In(i + poffset), pt[i], i+1, ft.In(i+poffset), pt[i],
)) ))
} }
} }
@@ -266,7 +265,7 @@ func (o *Object) connect(noi bool, sig SignalId, cb_func, param0 interface{}) {
default: default:
panic("Callback parameter #0 isn't a pointer nor nil") panic("Callback parameter #0 isn't a pointer nor nil")
} }
gocl.h_id = C._signal_connect(o.g(), C.guint(sig), gocl) gocl.h_id = C._signal_connect(o.g(), C.guint(sid), C.GQuark(detail), gocl)
oh := obj_handlers[uintptr(o.p)] oh := obj_handlers[uintptr(o.p)]
if oh == nil { if oh == nil {
oh = make(map[SigHandlerId]*sigHandler) oh = make(map[SigHandlerId]*sigHandler)
@@ -276,25 +275,29 @@ func (o *Object) connect(noi bool, sig SignalId, cb_func, param0 interface{}) {
} }
// Connect callback to signal specified by id // Connect callback to signal specified by id
func (o *Object) ConnectSid(sig SignalId, cb_func, param0 interface{}) { func (o *Object) ConnectSid(sid SignalId, detail Quark,
o.connect(false, sig, cb_func, param0) cb_func, param0 interface{}) {
o.connect(false, sid, detail, cb_func, param0)
} }
// Connect callback to signal specified by id. // Connect callback to signal specified by id.
// Doesn't pass o as first parameter to callback. // Doesn't pass o as first parameter to callback.
func (o *Object) ConnectSidNoi(sig SignalId, cb_func, param0 interface{}) { func (o *Object) ConnectSidNoi(sid SignalId, detail Quark,
o.connect(true, sig, cb_func, param0) cb_func, param0 interface{}) {
o.connect(true, sid, detail, cb_func, param0)
} }
// Connect callback to signal specified by name. // Connect callback to signal specified by name.
func (o *Object) Connect(sig_name string, cb_func, param0 interface{}) { func (o *Object) Connect(sig_name string, cb_func, param0 interface{}) {
o.ConnectSid(SignalLookup(sig_name, o.Type()), cb_func, param0) sid, detail := SignalLookup(sig_name, o.Type())
o.connect(false, sid, detail, cb_func, param0)
} }
// Connect callback to signal specified by name. // Connect callback to signal specified by name.
// Doesn't pass o as first parameter to callback. // Doesn't pass o as first parameter to callback.
func (o *Object) ConnectNoi(sig_name string, cb_func, param0 interface{}) { func (o *Object) ConnectNoi(sig_name string, cb_func, param0 interface{}) {
o.ConnectSidNoi(SignalLookup(sig_name, o.Type()), cb_func, param0) sid, detail := SignalLookup(sig_name, o.Type())
o.connect(true, sid, detail, cb_func, param0)
} }
type Params map[string]interface{} type Params map[string]interface{}

View File

@@ -8,6 +8,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"strings"
) )
type SignalFlags C.GSignalFlags type SignalFlags C.GSignalFlags
@@ -49,8 +50,13 @@ func (s SignalId) String() string {
return C.GoString((*C.char)(C.g_signal_name(C.guint(s)))) return C.GoString((*C.char)(C.g_signal_name(C.guint(s))))
} }
func SignalLookup(n string, t Type) SignalId { func SignalLookup(name string, t Type) (sid SignalId, detail Quark) {
s := C.CString(n) st := strings.SplitN(name, "::", 2)
if len(st) == 2 {
detail = QuarkFromString(st[1])
}
s := C.CString(st[0])
sid = SignalId(C.g_signal_lookup((*C.gchar)(s), t.g()))
defer C.free(unsafe.Pointer(s)) defer C.free(unsafe.Pointer(s))
return SignalId(C.g_signal_lookup((*C.gchar)(s), t.g())) return
} }