1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3
4package objc_test
5
6import (
7 "fmt"
8 "reflect"
9 "testing"
10
11 "github.com/ebitengine/purego"
12 "github.com/ebitengine/purego/objc"
13)
14
15func ExampleAllocateClassPair() {
16 class := objc.AllocateClassPair(objc.GetClass("NSObject"), "FooObject", 0)
17 class.AddMethod(objc.RegisterName("run"), objc.NewIMP(func(self objc.ID, _cmd objc.SEL) {
18 fmt.Println("Hello World!")
19 }), "v@:")
20 class.Register()
21
22 fooObject := objc.ID(class).Send(objc.RegisterName("new"))
23 fooObject.Send(objc.RegisterName("run"))
24 // Output: Hello World!
25}
26
27func ExampleRegisterClass() {
28 var (
29 sel_new = objc.RegisterName("new")
30 sel_init = objc.RegisterName("init")
31 sel_setBar = objc.RegisterName("setBar:")
32 sel_bar = objc.RegisterName("bar")
33
34 BarInit = func(id objc.ID, cmd objc.SEL) objc.ID {
35 return id.SendSuper(cmd)
36 }
37 )
38
39 class, err := objc.RegisterClass(
40 "BarObject",
41 objc.GetClass("NSObject"),
42 []*objc.Protocol{
43 objc.GetProtocol("NSDelegateWindow"),
44 },
45 []objc.FieldDef{
46 {
47 Name: "bar",
48 Type: reflect.TypeOf(int(0)),
49 Attribute: objc.ReadWrite,
50 },
51 {
52 Name: "foo",
53 Type: reflect.TypeOf(false),
54 Attribute: objc.ReadWrite,
55 },
56 },
57 []objc.MethodDef{
58 {
59 Cmd: sel_init,
60 Fn: BarInit,
61 },
62 },
63 )
64 if err != nil {
65 panic(err)
66 }
67
68 object := objc.ID(class).Send(sel_new)
69 object.Send(sel_setBar, 123)
70 bar := int(object.Send(sel_bar))
71 fmt.Println(bar)
72 // Output: 123
73}
74
75func ExampleIMP() {
76 imp := objc.NewIMP(func(self objc.ID, _cmd objc.SEL, a3, a4, a5, a6, a7, a8, a9 int) {
77 fmt.Println("IMP:", self, _cmd, a3, a4, a5, a6, a7, a8, a9)
78 })
79
80 purego.SyscallN(uintptr(imp), 105, 567, 9, 2, 3, ^uintptr(4), 4, 8, 9)
81
82 // Output: IMP: 105 567 9 2 3 -5 4 8 9
83}
84
85func ExampleID_SendSuper() {
86 super := objc.AllocateClassPair(objc.GetClass("NSObject"), "SuperObject", 0)
87 super.AddMethod(objc.RegisterName("doSomething"), objc.NewIMP(func(self objc.ID, _cmd objc.SEL) {
88 fmt.Println("In Super!")
89 }), "v@:")
90 super.Register()
91
92 child := objc.AllocateClassPair(super, "ChildObject", 0)
93 child.AddMethod(objc.RegisterName("doSomething"), objc.NewIMP(func(self objc.ID, _cmd objc.SEL) {
94 fmt.Println("In Child")
95 self.SendSuper(_cmd)
96 }), "v@:")
97 child.Register()
98
99 objc.ID(child).Send(objc.RegisterName("new")).Send(objc.RegisterName("doSomething"))
100
101 // Output: In Child
102 // In Super!
103}
104
105func TestSend(t *testing.T) {
106 // NSNumber comes from Foundation so make sure we have linked to that framework.
107 _, err := purego.Dlopen("Foundation.framework/Foundation", purego.RTLD_GLOBAL)
108 if err != nil {
109 t.Fatal(err)
110 }
111 const double = float64(2.34)
112 // Initialize a NSNumber
113 NSNumber := objc.ID(objc.GetClass("NSNumber")).Send(objc.RegisterName("numberWithDouble:"), double)
114 // Then get that number back using the generic Send function.
115 number := objc.Send[float64](NSNumber, objc.RegisterName("doubleValue"))
116 if double != number {
117 t.Failed()
118 }
119}