detached c0399be

Merge pull request #7 from bnema/fix/gerror-signal-callbacks

fix(gen): emit *glib.Error instead of uintptr for GError signal params
commit
c0399be2e423f0e56e96461bc8406ded32b2d015
author
bnema · · 2026-03-27 18:22 UTC
committer
GitHub · · 2026-03-27 18:22 UTC
merge of
8b02958 + 68c9308 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
refs
tag: v0.2.1
3 files · +56 -5
M internal/gir/types/template.go +52 -1
@@ -47,6 +47,16 @@ type NullableStringParam struct {
4747 Name string
4848 }
4949
50+// GErrorParam tracks a signal/callback parameter that is a GLib.Error record.
51+// The Pure type stays uintptr (purego ABI), but the API type is *glib.Error
52+// and the signal closure converts via unsafe.Pointer.
53+type GErrorParam struct {
54+ // Index is the position in the Pure args slice.
55+ Index int
56+ // GoType is the qualified Go type for the cast (e.g., "glib.Error" or "Error").
57+ GoType string
58+}
59+
5060 type funcArgsTemplate struct {
5161 // Pure are the arguments as passed directly to PureGo
5262 // The pure Call is a special case that contains the arguments for a callback call
@@ -61,6 +71,10 @@ type funcArgsTemplate struct {
6171 // NullableStrings tracks nullable string parameters that need temporary C strings
6272 NullableStrings []NullableStringParam
6373
74+ // GErrors tracks GError record parameters in signal/callback contexts
75+ // so PuregoSignalCall can emit unsafe.Pointer casts.
76+ GErrors []GErrorParam
77+
6478 // UsesNullableHelper indicates nullable string handling that needs core import.
6579 UsesNullableHelper bool
6680
@@ -86,6 +100,12 @@ func isStringType(t string) bool {
86100 return strings.TrimLeft(t, "*") == "string"
87101 }
88102
103+// isGErrorType reports whether a GIR type name refers to GLib.Error.
104+// Within the GLib namespace the name is just "Error"; elsewhere it is "GLib.Error".
105+func isGErrorType(girName string) bool {
106+ return girName == "GLib.Error" || girName == "Error"
107+}
108+
89109 // NeedsCore reports whether this argument set requires core helpers.
90110 func (f funcArgsTemplate) NeedsCore() bool {
91111 return f.UsesNullableHelper || f.UsesGStrdup
@@ -117,7 +137,8 @@ func (f funcArgsTemplate) PuregoSignalFull() []string {
117137 }
118138
119139 // PuregoSignalCall returns Pure.Call with string variables wrapped in
120-// core.GoString() for C char* → Go string conversion in signal closures.
140+// core.GoString() for C char* → Go string conversion in signal closures,
141+// and GError parameters wrapped in (*glib.Error)(unsafe.Pointer(...)).
121142 func (f funcArgsTemplate) PuregoSignalCall() []string {
122143 out := make([]string, len(f.Pure.Call))
123144 copy(out, f.Pure.Call)
@@ -126,9 +147,18 @@ func (f funcArgsTemplate) PuregoSignalCall() []string {
126147 out[i] = "core.GoString(" + f.Pure.Names[i] + ")"
127148 }
128149 }
150+ for _, ge := range f.GErrors {
151+ out[ge.Index] = "(*" + ge.GoType + ")(unsafe.Pointer(" + f.Pure.Names[ge.Index] + "))"
152+ }
129153 return out
130154 }
131155
156+// HasGErrors reports whether any parameter is a GError that needs
157+// an unsafe.Pointer cast in the signal closure.
158+func (f funcArgsTemplate) HasGErrors() bool {
159+ return len(f.GErrors) > 0
160+}
161+
132162 func qualifyCallbackType(t string, callbackNS string, currentNS string) string {
133163 if t == "" || callbackNS == "" || strings.EqualFold(callbackNS, currentNS) {
134164 return t
@@ -377,6 +407,27 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap
377407 f.AddAPI(goType, varName, kind, ns, p.Nullable, isOut, ctx, transferFull)
378408 f.AddPure(goType, varName, kind, isOut, p.Nullable, ctx, transferFull)
379409
410+ // For GError record parameters in signal/callback contexts (C→Go), the type
411+ // is collapsed to uintptr by Type.Template(). Override the API type to
412+ // *glib.Error so consumers get a proper Go error, and track the Pure index
413+ // so PuregoSignalCall() can emit the unsafe.Pointer cast.
414+ if ctx == ArgsFromCToGo && !isOut && goType == "uintptr" && p.Type != nil && isGErrorType(p.Type.Name) {
415+ gerrorGoType := "glib.Error"
416+ if strings.ToLower(ns) == "glib" {
417+ gerrorGoType = "Error"
418+ }
419+ // Override API type from uintptr to *glib.Error
420+ apiIdx := len(f.API.Types) - 1
421+ f.API.Types[apiIdx] = "*" + gerrorGoType
422+ f.API.Full[apiIdx] = varName + " *" + gerrorGoType
423+ // Pure stays uintptr; record the index for signal call casting
424+ pureIdx := len(f.Pure.Types) - 1
425+ f.GErrors = append(f.GErrors, GErrorParam{
426+ Index: pureIdx,
427+ GoType: gerrorGoType,
428+ })
429+ }
430+
380431 // Upstream purego does not support direct array parameters (reflect.Array kind).
381432 // Fixed-size C arrays like "int fds[2]" are pointer params at the ABI level.
382433 // For non-out fixed-size array params, change the pure signature to *[N]T and
@@ -47,6 +47,16 @@ type NullableStringParam struct {
47 Name string47 Name string
48 }48 }
49 49
50+// GErrorParam tracks a signal/callback parameter that is a GLib.Error record.
51+// The Pure type stays uintptr (purego ABI), but the API type is *glib.Error
52+// and the signal closure converts via unsafe.Pointer.
53+type GErrorParam struct {
54+ // Index is the position in the Pure args slice.
55+ Index int
56+ // GoType is the qualified Go type for the cast (e.g., "glib.Error" or "Error").
57+ GoType string
58+}
59+
50 type funcArgsTemplate struct {60 type funcArgsTemplate struct {
51 // Pure are the arguments as passed directly to PureGo61 // Pure are the arguments as passed directly to PureGo
52 // The pure Call is a special case that contains the arguments for a callback call62 // The pure Call is a special case that contains the arguments for a callback call
@@ -61,6 +71,10 @@ type funcArgsTemplate struct {
61 // NullableStrings tracks nullable string parameters that need temporary C strings71 // NullableStrings tracks nullable string parameters that need temporary C strings
62 NullableStrings []NullableStringParam72 NullableStrings []NullableStringParam
63 73
74+ // GErrors tracks GError record parameters in signal/callback contexts
75+ // so PuregoSignalCall can emit unsafe.Pointer casts.
76+ GErrors []GErrorParam
77+
64 // UsesNullableHelper indicates nullable string handling that needs core import.78 // UsesNullableHelper indicates nullable string handling that needs core import.
65 UsesNullableHelper bool79 UsesNullableHelper bool
66 80
@@ -86,6 +100,12 @@ func isStringType(t string) bool {
86 return strings.TrimLeft(t, "*") == "string"100 return strings.TrimLeft(t, "*") == "string"
87 }101 }
88 102
103+// isGErrorType reports whether a GIR type name refers to GLib.Error.
104+// Within the GLib namespace the name is just "Error"; elsewhere it is "GLib.Error".
105+func isGErrorType(girName string) bool {
106+ return girName == "GLib.Error" || girName == "Error"
107+}
108+
89 // NeedsCore reports whether this argument set requires core helpers.109 // NeedsCore reports whether this argument set requires core helpers.
90 func (f funcArgsTemplate) NeedsCore() bool {110 func (f funcArgsTemplate) NeedsCore() bool {
91 return f.UsesNullableHelper || f.UsesGStrdup111 return f.UsesNullableHelper || f.UsesGStrdup
@@ -117,7 +137,8 @@ func (f funcArgsTemplate) PuregoSignalFull() []string {
117 }137 }
118 138
119 // PuregoSignalCall returns Pure.Call with string variables wrapped in139 // PuregoSignalCall returns Pure.Call with string variables wrapped in
120-// core.GoString() for C char* → Go string conversion in signal closures.140+// core.GoString() for C char* → Go string conversion in signal closures,
141+// and GError parameters wrapped in (*glib.Error)(unsafe.Pointer(...)).
121 func (f funcArgsTemplate) PuregoSignalCall() []string {142 func (f funcArgsTemplate) PuregoSignalCall() []string {
122 out := make([]string, len(f.Pure.Call))143 out := make([]string, len(f.Pure.Call))
123 copy(out, f.Pure.Call)144 copy(out, f.Pure.Call)
@@ -126,9 +147,18 @@ func (f funcArgsTemplate) PuregoSignalCall() []string {
126 out[i] = "core.GoString(" + f.Pure.Names[i] + ")"147 out[i] = "core.GoString(" + f.Pure.Names[i] + ")"
127 }148 }
128 }149 }
150+ for _, ge := range f.GErrors {
151+ out[ge.Index] = "(*" + ge.GoType + ")(unsafe.Pointer(" + f.Pure.Names[ge.Index] + "))"
152+ }
129 return out153 return out
130 }154 }
131 155
156+// HasGErrors reports whether any parameter is a GError that needs
157+// an unsafe.Pointer cast in the signal closure.
158+func (f funcArgsTemplate) HasGErrors() bool {
159+ return len(f.GErrors) > 0
160+}
161+
132 func qualifyCallbackType(t string, callbackNS string, currentNS string) string {162 func qualifyCallbackType(t string, callbackNS string, currentNS string) string {
133 if t == "" || callbackNS == "" || strings.EqualFold(callbackNS, currentNS) {163 if t == "" || callbackNS == "" || strings.EqualFold(callbackNS, currentNS) {
134 return t164 return t
@@ -377,6 +407,27 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap
377 f.AddAPI(goType, varName, kind, ns, p.Nullable, isOut, ctx, transferFull)407 f.AddAPI(goType, varName, kind, ns, p.Nullable, isOut, ctx, transferFull)
378 f.AddPure(goType, varName, kind, isOut, p.Nullable, ctx, transferFull)408 f.AddPure(goType, varName, kind, isOut, p.Nullable, ctx, transferFull)
379 409
410+ // For GError record parameters in signal/callback contexts (C→Go), the type
411+ // is collapsed to uintptr by Type.Template(). Override the API type to
412+ // *glib.Error so consumers get a proper Go error, and track the Pure index
413+ // so PuregoSignalCall() can emit the unsafe.Pointer cast.
414+ if ctx == ArgsFromCToGo && !isOut && goType == "uintptr" && p.Type != nil && isGErrorType(p.Type.Name) {
415+ gerrorGoType := "glib.Error"
416+ if strings.ToLower(ns) == "glib" {
417+ gerrorGoType = "Error"
418+ }
419+ // Override API type from uintptr to *glib.Error
420+ apiIdx := len(f.API.Types) - 1
421+ f.API.Types[apiIdx] = "*" + gerrorGoType
422+ f.API.Full[apiIdx] = varName + " *" + gerrorGoType
423+ // Pure stays uintptr; record the index for signal call casting
424+ pureIdx := len(f.Pure.Types) - 1
425+ f.GErrors = append(f.GErrors, GErrorParam{
426+ Index: pureIdx,
427+ GoType: gerrorGoType,
428+ })
429+ }
430+
380 // Upstream purego does not support direct array parameters (reflect.Array kind).431 // Upstream purego does not support direct array parameters (reflect.Array kind).
381 // Fixed-size C arrays like "int fds[2]" are pointer params at the ABI level.432 // Fixed-size C arrays like "int fds[2]" are pointer params at the ABI level.
382 // For non-out fixed-size array params, change the pure signature to *[N]T and433 // For non-out fixed-size array params, change the pure signature to *[N]T and
M v4/gio/gdbusconnection.go +2 -2
@@ -1841,7 +1841,7 @@ func (x *DBusConnection) GetPropertyUniqueName() string {
18411841 // Upon receiving this signal, you should give up your reference to
18421842 // @connection. You are guaranteed that this signal is emitted only
18431843 // once.
1844-func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, uintptr)) uint {
1844+func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, *glib.Error)) uint {
18451845 cbPtr := uintptr(unsafe.Pointer(cb))
18461846 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {
18471847 handlerID := gobject.SignalConnect(x.GoPointer(), "closed", cbRefPtr)
@@ -1854,7 +1854,7 @@ func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, uintptr))
18541854 fa.Ptr = clsPtr
18551855 cbFn := *cb
18561856
1857- cbFn(fa, RemotePeerVanishedVarp, ErrorVarp)
1857+ cbFn(fa, RemotePeerVanishedVarp, (*glib.Error)(unsafe.Pointer(ErrorVarp)))
18581858
18591859 }
18601860 cbRefPtr := purego.NewCallback(fcb)
@@ -1841,7 +1841,7 @@ func (x *DBusConnection) GetPropertyUniqueName() string {
1841 // Upon receiving this signal, you should give up your reference to1841 // Upon receiving this signal, you should give up your reference to
1842 // @connection. You are guaranteed that this signal is emitted only1842 // @connection. You are guaranteed that this signal is emitted only
1843 // once.1843 // once.
1844-func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, uintptr)) uint {1844+func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, *glib.Error)) uint {
1845 cbPtr := uintptr(unsafe.Pointer(cb))1845 cbPtr := uintptr(unsafe.Pointer(cb))
1846 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {1846 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {
1847 handlerID := gobject.SignalConnect(x.GoPointer(), "closed", cbRefPtr)1847 handlerID := gobject.SignalConnect(x.GoPointer(), "closed", cbRefPtr)
@@ -1854,7 +1854,7 @@ func (x *DBusConnection) ConnectClosed(cb *func(DBusConnection, bool, uintptr))
1854 fa.Ptr = clsPtr1854 fa.Ptr = clsPtr
1855 cbFn := *cb1855 cbFn := *cb
1856 1856
1857- cbFn(fa, RemotePeerVanishedVarp, ErrorVarp)1857+ cbFn(fa, RemotePeerVanishedVarp, (*glib.Error)(unsafe.Pointer(ErrorVarp)))
1858 1858
1859 }1859 }
1860 cbRefPtr := purego.NewCallback(fcb)1860 cbRefPtr := purego.NewCallback(fcb)
M v4/gtk/gtkcssprovider.go +2 -2
@@ -218,7 +218,7 @@ func (c *CssProvider) SetGoPointer(ptr uintptr) {
218218 // Note that this signal may be emitted at any time as the css provider
219219 // may opt to defer parsing parts or all of the input to a later time
220220 // than when a loading function was called.
221-func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, uintptr)) uint {
221+func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, *glib.Error)) uint {
222222 cbPtr := uintptr(unsafe.Pointer(cb))
223223 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {
224224 handlerID := gobject.SignalConnect(x.GoPointer(), "parsing-error", cbRefPtr)
@@ -231,7 +231,7 @@ func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, uintptr
231231 fa.Ptr = clsPtr
232232 cbFn := *cb
233233
234- cbFn(fa, SectionVarp, ErrorVarp)
234+ cbFn(fa, SectionVarp, (*glib.Error)(unsafe.Pointer(ErrorVarp)))
235235
236236 }
237237 cbRefPtr := purego.NewCallback(fcb)
@@ -218,7 +218,7 @@ func (c *CssProvider) SetGoPointer(ptr uintptr) {
218 // Note that this signal may be emitted at any time as the css provider218 // Note that this signal may be emitted at any time as the css provider
219 // may opt to defer parsing parts or all of the input to a later time219 // may opt to defer parsing parts or all of the input to a later time
220 // than when a loading function was called.220 // than when a loading function was called.
221-func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, uintptr)) uint {221+func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, *glib.Error)) uint {
222 cbPtr := uintptr(unsafe.Pointer(cb))222 cbPtr := uintptr(unsafe.Pointer(cb))
223 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {223 if cbRefPtr, ok := glib.GetCallback(cbPtr); ok {
224 handlerID := gobject.SignalConnect(x.GoPointer(), "parsing-error", cbRefPtr)224 handlerID := gobject.SignalConnect(x.GoPointer(), "parsing-error", cbRefPtr)
@@ -231,7 +231,7 @@ func (x *CssProvider) ConnectParsingError(cb *func(CssProvider, uintptr, uintptr
231 fa.Ptr = clsPtr231 fa.Ptr = clsPtr
232 cbFn := *cb232 cbFn := *cb
233 233
234- cbFn(fa, SectionVarp, ErrorVarp)234+ cbFn(fa, SectionVarp, (*glib.Error)(unsafe.Pointer(ErrorVarp)))
235 235
236 }236 }
237 cbRefPtr := purego.NewCallback(fcb)237 cbRefPtr := purego.NewCallback(fcb)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close