diff --git a/glib/glib_extra.go b/glib/glib_extra.go new file mode 100644 index 0000000..7a4ed1e --- /dev/null +++ b/glib/glib_extra.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Joan Garcia i Silano - https://github.com/joangs +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package glib + +import ( + "errors" +) + +// Gets the marshaller for a given type +func (t Type) GetMarshaller() (GValueMarshaler, error) { + if f, ok := gValueMarshalers[t]; ok { + return f, nil + } + + return nil, errors.New("missing marshaler for type") +} diff --git a/gtk/gtk.go b/gtk/gtk.go index 53051a5..68dc71a 100644 --- a/gtk/gtk.go +++ b/gtk/gtk.go @@ -1300,6 +1300,7 @@ func (v *Bin) GetChild() (*Widget, error) { // Builder is a representation of GTK's GtkBuilder. type Builder struct { *glib.Object + callbacks []interface{} } // native() returns a pointer to the underlying GtkBuilder. @@ -1314,7 +1315,7 @@ func (b *Builder) native() *C.GtkBuilder { func marshalBuilder(p uintptr) (interface{}, error) { c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p))) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} - return &Builder{obj}, nil + return &Builder{obj, []interface{}{}}, nil } // BuilderNew is a wrapper around gtk_builder_new(). @@ -1324,7 +1325,7 @@ func BuilderNew() (*Builder, error) { return nil, nilPtrErr } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} - b := &Builder{obj} + b := &Builder{obj, []interface{}{}} obj.RefSink() runtime.SetFinalizer(obj, (*glib.Object).Unref) return b, nil diff --git a/gtk/gtkbuilder_bridge.go b/gtk/gtkbuilder_bridge.go new file mode 100644 index 0000000..f7ebe74 --- /dev/null +++ b/gtk/gtkbuilder_bridge.go @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Joan Garcia i Silano - https://github.com/joangs +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +package gtk + +/* +#cgo pkg-config: gtk+-3.0 +#include +#include + +*/ +import "C" +import ( + "github.com/conformal/gotk3/glib" + "log" + "reflect" + "strings" + "unsafe" +) + +//export dispatchEvent +func dispatchEvent(pbuilder unsafe.Pointer, csignal *C.char, rval *C.GValue, nparams C.guint, size C.int, params *C.GValue) { + b := (*Builder)(pbuilder) + signal := C.GoString(csignal) + signal = strings.ToUpper(signal[:1]) + signal[1:] + + values := []reflect.Value{} + + for c := uint64(0); c < (uint64)(nparams); c++ { + addr := uintptr(unsafe.Pointer(params)) + uintptr(c*uint64(size)) + v := (*C.GValue)(unsafe.Pointer(addr)) + + t := glib.Type(v.g_type) + if m, err := t.GetMarshaller(); err != nil { + log.Printf("Error: %s", err.Error()) + return + } else { + if gov, err := m(uintptr(unsafe.Pointer(v))); err != nil { + log.Printf("Error: %s", err.Error()) + return + } else { + values = append(values, reflect.ValueOf(gov)) + } + } + } + + log.Printf("%s(%v) %d", signal, values, nparams) + + for _, iface := range b.callbacks { + v := reflect.ValueOf(iface) + m := v.MethodByName(signal) + + if m.IsValid() { + m.Call(values) + return + } + } + + log.Printf("Warning: Signal '%s' not defined", signal) +} diff --git a/gtk/gtkbuilder_cgo.go b/gtk/gtkbuilder_cgo.go new file mode 100644 index 0000000..136c0f1 --- /dev/null +++ b/gtk/gtkbuilder_cgo.go @@ -0,0 +1,91 @@ +// Copyright (c) 2014 Joan Garcia i Silano - https://github.com/joangs +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +package gtk + +/* +#cgo pkg-config: gtk+-3.0 +#include +#include + + +typedef void (*callbackFunc) (); + +#define BUILDER_DATA(ptr) ((struct gtkbuilder_data *)(ptr)) + +// TODO: Free data when GtkBuilder is freed. +struct gtkbuilder_data { + char *signal; + void *builder; +}; + + +void gtkbuilder_handler(GClosure *closure, + GValue *return_value, + guint nparams, + const GValue *params, + gpointer invocation_hint, + gpointer marshal_data) { + + const GValue **p; + int c; + + p = (const GValue **)malloc(nparams * sizeof(GValue*)); + for (c = 0; c < nparams; c++) { + p[c] = params+c; + } + + dispatchEvent(BUILDER_DATA(marshal_data)->builder, BUILDER_DATA(marshal_data)->signal, return_value, nparams, sizeof(GValue), params); + free(p); +} + +void gtkbuilder_connector(GtkBuilder *builder, + GObject *object, + const gchar *signal_name, + const gchar *handler_name, + GObject *connect_object, + GConnectFlags flags, + gpointer user_data) +{ + struct gtkbuilder_data *data; + GClosure *c; + + if (!(data = (struct gtkbuilder_data *)malloc(sizeof(struct gtkbuilder_data)))) { + fprintf(stderr, "ERROR: Not enough memory.\n"); + return; + } + + data->signal = g_strdup_printf("%s", handler_name); + data->builder = user_data; + printf("Connect '%s' w/ %s\n", signal_name, data->signal); + + c = g_closure_new_simple(sizeof(GClosure), data); + g_closure_set_meta_marshal(c, data, gtkbuilder_handler); + g_signal_connect_closure(object, signal_name, c, FALSE); +} + +*/ +import "C" +import ( + "unsafe" +) + +// Bind callbacks methods using reflection. Callbacks must be exported (first letter in upper case) +func (b *Builder) BindCallbacks(ifaces ...interface{}) { + for _, v := range ifaces { + b.callbacks = append(b.callbacks, v) + } + + C.gtk_builder_connect_signals_full(b.native(), C.callbackFunc(C.gtkbuilder_connector), C.gpointer(unsafe.Pointer(b))) + +}