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) { | |||
| 63 | 63 | for _, inter := range ns.Interfaces { | |
| 64 | 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 | 83 | // 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 repositories | 83 | // 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 { | |||
| 29 | 29 | 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 | 33 | c := n | |
| 34 | 34 | stars := strings.Count(t, "*") | |
| 35 | 35 | gobjectNs := "gobject." | |
| @@ -42,7 +42,11 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string) { | |||
| 42 | 42 | } | |
| 43 | 43 | switch k { | |
| 44 | 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 | 50 | t = "*" + t | |
| 47 | 51 | case ClassesType: | |
| 48 | 52 | if stars == 0 { | |
| @@ -133,7 +137,7 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap | |||
| 133 | 137 | // Get a suitable variable name | |
| 134 | 138 | varName := p.VarName() | |
| 135 | 139 | ||
| 136 | - | f.AddAPI(goType, varName, kind, ns) | |
| 140 | + | f.AddAPI(goType, varName, kind, ns, p.Nullable) | |
| 137 | 141 | f.AddPure(goType, varName, kind) | |
| 138 | 142 | } | |
| 139 | 143 | ||
| @@ -29,7 +29,7 @@ type funcArgsTemplate struct { | |||||
| 29 | API argsTemplate | 29 | 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 := n | 33 | 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 = "*" + t | 50 | 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 name | 137 | // 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 | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "fmt" | |
| 5 | + | "reflect" | |
| 5 | 6 | "sync" | |
| 6 | 7 | ||
| 7 | 8 | "github.com/jwijenbergh/purego" | |
| @@ -46,6 +47,16 @@ func NewCallback(fnPtr interface{}) uintptr { | |||
| 46 | 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 | 60 | func (e *Error) Error() string { | |
| 50 | 61 | return fmt.Sprintf("Gtk reported an error with message: '%s', domain: '%v' and code: '%v'", e.MessageGo(), e.Domain, e.Code) | |
| 51 | 62 | } | |
| @@ -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 | } | ||