detached 0fb486e

GIR: Add support for nullable callbacks by return null pointers where GIR files mark them as nullable

Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
commit
0fb486ea8fe6a2e255cf9e2f369286424a74be71
author
Felicitas Pojtinger · · 2025-09-28 23:06 UTC
committer
Jeroen Wijenbergh · · 2025-10-13 08:11 UTC
parent
7203178
signature
unsigned
3 files · +33 -3
M internal/gir/pass/pass.go +15 -0
@@ -63,6 +63,21 @@ func (p *Pass) collectTypes(r types.Repository) {
6363 for _, inter := range ns.Interfaces {
6464 p.Types.Add(ns.Name, inter.Name, types.InterfacesType, inter)
6565 }
66+ for _, alias := range ns.Aliases {
67+ // Check what the alias points to and use the same type
68+ aliasTarget := alias.Type.Name
69+ if aliasTarget != "" {
70+ targetKind := p.Types.Kind(ns.Name, aliasTarget)
71+ if targetKind != types.UnknownType {
72+ p.Types.Add(ns.Name, alias.Name, targetKind, alias)
73+ } else {
74+ // If we don't know the target type yet, default to alias type
75+ p.Types.Add(ns.Name, alias.Name, types.AliasType, alias)
76+ }
77+ } else {
78+ p.Types.Add(ns.Name, alias.Name, types.AliasType, alias)
79+ }
80+ }
6681 }
6782
6883 // First does a "first pass" meaning it collects basic type information for all the repositories
@@ -63,6 +63,21 @@ func (p *Pass) collectTypes(r types.Repository) {
63 for _, inter := range ns.Interfaces {63 for _, inter := range ns.Interfaces {
64 p.Types.Add(ns.Name, inter.Name, types.InterfacesType, inter)64 p.Types.Add(ns.Name, inter.Name, types.InterfacesType, inter)
65 }65 }
66+ for _, alias := range ns.Aliases {
67+ // Check what the alias points to and use the same type
68+ aliasTarget := alias.Type.Name
69+ if aliasTarget != "" {
70+ targetKind := p.Types.Kind(ns.Name, aliasTarget)
71+ if targetKind != types.UnknownType {
72+ p.Types.Add(ns.Name, alias.Name, targetKind, alias)
73+ } else {
74+ // If we don't know the target type yet, default to alias type
75+ p.Types.Add(ns.Name, alias.Name, types.AliasType, alias)
76+ }
77+ } else {
78+ p.Types.Add(ns.Name, alias.Name, types.AliasType, alias)
79+ }
80+ }
66 }81 }
67 82
68 // First does a "first pass" meaning it collects basic type information for all the repositories83 // First does a "first pass" meaning it collects basic type information for all the repositories
M internal/gir/types/template.go +7 -3
@@ -29,7 +29,7 @@ type funcArgsTemplate struct {
2929 API argsTemplate
3030 }
3131
32-func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string) {
32+func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool) {
3333 c := n
3434 stars := strings.Count(t, "*")
3535 gobjectNs := "gobject."
@@ -42,7 +42,11 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string) {
4242 }
4343 switch k {
4444 case CallbackType:
45- c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n)
45+ if nullable {
46+ c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n)
47+ } else {
48+ c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n)
49+ }
4650 t = "*" + t
4751 case ClassesType:
4852 if stars == 0 {
@@ -133,7 +137,7 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap
133137 // Get a suitable variable name
134138 varName := p.VarName()
135139
136- f.AddAPI(goType, varName, kind, ns)
140+ f.AddAPI(goType, varName, kind, ns, p.Nullable)
137141 f.AddPure(goType, varName, kind)
138142 }
139143
@@ -29,7 +29,7 @@ type funcArgsTemplate struct {
29 API argsTemplate29 API argsTemplate
30 }30 }
31 31
32-func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string) {32+func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool) {
33 c := n33 c := n
34 stars := strings.Count(t, "*")34 stars := strings.Count(t, "*")
35 gobjectNs := "gobject."35 gobjectNs := "gobject."
@@ -42,7 +42,11 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string) {
42 }42 }
43 switch k {43 switch k {
44 case CallbackType:44 case CallbackType:
45- c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n)45+ if nullable {
46+ c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n)
47+ } else {
48+ c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n)
49+ }
46 t = "*" + t50 t = "*" + t
47 case ClassesType:51 case ClassesType:
48 if stars == 0 {52 if stars == 0 {
@@ -133,7 +137,7 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap
133 // Get a suitable variable name137 // Get a suitable variable name
134 varName := p.VarName()138 varName := p.VarName()
135 139
136- f.AddAPI(goType, varName, kind, ns)140+ f.AddAPI(goType, varName, kind, ns, p.Nullable)
137 f.AddPure(goType, varName, kind)141 f.AddPure(goType, varName, kind)
138 }142 }
139 143
M templates/glib +11 -0
@@ -2,6 +2,7 @@ package glib
22
33 import (
44 "fmt"
5+ "reflect"
56 "sync"
67
78 "github.com/jwijenbergh/purego"
@@ -46,6 +47,16 @@ func NewCallback(fnPtr interface{}) uintptr {
4647 return purego.NewCallbackFnPtr(fnPtr)
4748 }
4849
50+// NewCallbackNullable is an alias to purego.NewCallback that returns a null pointer for null functions
51+func NewCallbackNullable(fn interface{}) uintptr {
52+ val := reflect.ValueOf(fn)
53+ if val.IsNil() {
54+ return 0
55+ }
56+
57+ return NewCallback(fn)
58+}
59+
4960 func (e *Error) Error() string {
5061 return fmt.Sprintf("Gtk reported an error with message: '%s', domain: '%v' and code: '%v'", e.MessageGo(), e.Domain, e.Code)
5162 }
@@ -2,6 +2,7 @@ package glib
2 2
3 import (3 import (
4 "fmt"4 "fmt"
5+ "reflect"
5 "sync"6 "sync"
6 7
7 "github.com/jwijenbergh/purego"8 "github.com/jwijenbergh/purego"
@@ -46,6 +47,16 @@ func NewCallback(fnPtr interface{}) uintptr {
46 return purego.NewCallbackFnPtr(fnPtr)47 return purego.NewCallbackFnPtr(fnPtr)
47 }48 }
48 49
50+// NewCallbackNullable is an alias to purego.NewCallback that returns a null pointer for null functions
51+func NewCallbackNullable(fn interface{}) uintptr {
52+ val := reflect.ValueOf(fn)
53+ if val.IsNil() {
54+ return 0
55+ }
56+
57+ return NewCallback(fn)
58+}
59+
49 func (e *Error) Error() string {60 func (e *Error) Error() string {
50 return fmt.Sprintf("Gtk reported an error with message: '%s', domain: '%v' and code: '%v'", e.MessageGo(), e.Domain, e.Code)61 return fmt.Sprintf("Gtk reported an error with message: '%s', domain: '%v' and code: '%v'", e.MessageGo(), e.Domain, e.Code)
51 }62 }

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