Skip to content

Commit e82e6e0

Browse files
committed
Generic bind funcs
1 parent ce72802 commit e82e6e0

File tree

5 files changed

+94
-44
lines changed

5 files changed

+94
-44
lines changed

go.work

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
go 1.22.0
2+
3+
use (
4+
.
5+
./pkg
6+
)

pkg/core/glib/bind.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package glib
2+
3+
import (
4+
"reflect"
5+
"sync"
6+
"unsafe"
7+
8+
"github.com/diamondburned/gotk4/pkg/core/gbox"
9+
)
10+
11+
// #include <glib.h>
12+
// #include <glib-object.h>
13+
// #include "glib.go.h"
14+
import "C"
15+
16+
var bindingNames sync.Map // map[reflect.Type]C.GQuark
17+
18+
// Associate value with object
19+
func Bind[T any](obj Objector, value T) {
20+
object := BaseObject(obj)
21+
name := bindingName[T]()
22+
23+
ptr := C.gpointer(gbox.Assign(value))
24+
25+
C.g_object_set_data_full(object.native(), (*C.gchar)(name), ptr, (*[0]byte)(C._gotk4_data_destroy))
26+
}
27+
28+
// Disassociate value from object
29+
func Unbind[T any](obj Objector) {
30+
name := bindingName[T]()
31+
32+
ptr := C.g_object_steal_data(BaseObject(obj).native(), (*C.gchar)(name))
33+
defer gbox.Delete(uintptr(ptr))
34+
}
35+
36+
// Obtain value associated with object
37+
func Bounded[T any](obj Objector) *T {
38+
name := bindingName[T]()
39+
40+
ptr := C.g_object_get_data(BaseObject(obj).native(), name)
41+
42+
value, ok := gbox.Get(uintptr(ptr)).(T)
43+
if !ok {
44+
return nil
45+
}
46+
47+
return &value
48+
}
49+
50+
func bindingName[T any]() *C.gchar {
51+
t := reflect.TypeFor[T]()
52+
53+
if v, ok := bindingNames.Load(t); ok {
54+
quark := v.(C.GQuark)
55+
return C.g_quark_to_string(quark)
56+
}
57+
58+
name := "_gotk4_" + t.String()
59+
60+
nameC := C.CString(name)
61+
defer C.free(unsafe.Pointer(nameC))
62+
63+
quark := C.g_quark_from_string(nameC)
64+
if v, lost := bindingNames.LoadOrStore(t, quark); lost {
65+
quark = v.(C.GQuark)
66+
}
67+
68+
return C.g_quark_to_string(quark)
69+
}
70+
71+
//export _gotk4_data_destroy
72+
func _gotk4_data_destroy(ptr C.gpointer) {
73+
gbox.Delete(uintptr(ptr))
74+
}

pkg/core/glib/glib.go

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -589,9 +589,6 @@ type Objector interface {
589589
NotifyProperty(string, func()) SignalHandle
590590
ObjectProperty(string) interface{}
591591
SetObjectProperty(string, interface{})
592-
ObjectData(string) interface{}
593-
SetObjectData(string, interface{})
594-
StealObjectData(name string) interface{}
595592
FreezeNotify()
596593
ThawNotify()
597594
StopEmission(string)
@@ -871,41 +868,6 @@ func (v *Object) NotifyProperty(property string, f func()) SignalHandle {
871868
)
872869
}
873870

874-
// Gets a named field from the objects table of associations
875-
func (v *Object) ObjectData(name string) interface{} {
876-
cstr := C.CString(name)
877-
defer C.free(unsafe.Pointer(cstr))
878-
879-
ptr := C.g_object_get_data(v.native(), (*C.gchar)(cstr))
880-
runtime.KeepAlive(v)
881-
882-
return gbox.Get(uintptr(ptr))
883-
}
884-
885-
// Each object carries around a table of associations from strings to pointers. This function lets you set an association.
886-
func (v *Object) SetObjectData(name string, value interface{}) {
887-
cstr := C.CString(name)
888-
defer C.free(unsafe.Pointer(cstr))
889-
890-
ptr := C.gpointer(gbox.Assign(value))
891-
892-
C.g_object_set_data(v.native(), (*C.gchar)(cstr), ptr)
893-
runtime.KeepAlive(v)
894-
}
895-
896-
// Remove a specified datum from the object’s data associations
897-
func (v *Object) StealObjectData(name string) interface{} {
898-
cstr := C.CString(name)
899-
defer C.free(unsafe.Pointer(cstr))
900-
901-
ptr := C.g_object_steal_data(v.native(), (*C.gchar)(cstr))
902-
defer gbox.Delete(uintptr(ptr))
903-
904-
runtime.KeepAlive(v)
905-
906-
return gbox.Get(uintptr(ptr))
907-
}
908-
909871
// FreezeNotify increases the freeze count on object. If the freeze count is
910872
// non-zero, the emission of “notify” signals on object is stopped. The signals
911873
// are queued until the freeze count is decreased to zero. Duplicate

pkg/core/glib/glib.go.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,6 @@ static void init_i18n(const char *domain, const char *dir) {
109109

110110
static const char *localize(const char *string) { return _(string); }
111111

112+
extern void _gotk4_data_destroy(gpointer ptr);
113+
112114
#endif

pkg/core/test/glib_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
package test
22

33
import (
4+
"runtime"
45
"testing"
56

6-
"github.com/diamondburned/gotk4/pkg/gtk/v4"
7+
"github.com/diamondburned/gotk4/pkg/core/glib"
8+
"github.com/diamondburned/gotk4/pkg/gio/v2"
79
)
810

911
func TestObjectData(t *testing.T) {
10-
gtk.Init()
12+
testObjectData(t)
1113

12-
label := gtk.NewLabel("label")
14+
runtime.GC()
15+
}
16+
17+
func testObjectData(t *testing.T) {
18+
app := gio.NewApplication("foo.bar", gio.ApplicationFlagsNone)
1319

14-
label.SetObjectData("foo", "bar")
20+
glib.Bind(app, "foo")
1521

16-
if label.ObjectData("foo") != "bar" {
22+
if value := glib.Bounded[string](app); value == nil || *value != "foo" {
1723
t.Fatal("returned data did not match expected data")
1824
}
1925

20-
label.StealObjectData("foo")
26+
glib.Unbind[string](app)
2127
}

0 commit comments

Comments
 (0)