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 ExampleRegisterClass_helloworld() {
16 class, err := objc.RegisterClass(
17 "FooObject",
18 objc.GetClass("NSObject"),
19 nil,
20 nil,
21 []objc.MethodDef{
22 {
23 Cmd: objc.RegisterName("run"),
24 Fn: func(self objc.ID, _cmd objc.SEL) {
25 fmt.Println("Hello World!")
26 },
27 },
28 },
29 )
30 if err != nil {
31 panic(err)
32 }
33
34 object := objc.ID(class).Send(objc.RegisterName("new"))
35 object.Send(objc.RegisterName("run"))
36 // Output: Hello World!
37}
38
39func ExampleRegisterClass() {
40 var (
41 sel_new = objc.RegisterName("new")
42 sel_init = objc.RegisterName("init")
43 sel_setBar = objc.RegisterName("setBar:")
44 sel_bar = objc.RegisterName("bar")
45
46 BarInit = func(id objc.ID, cmd objc.SEL) objc.ID {
47 return id.SendSuper(cmd)
48 }
49 )
50
51 class, err := objc.RegisterClass(
52 "BarObject",
53 objc.GetClass("NSObject"),
54 []*objc.Protocol{
55 objc.GetProtocol("NSDelegateWindow"),
56 },
57 []objc.FieldDef{
58 {
59 Name: "bar",
60 Type: reflect.TypeOf(int(0)),
61 Attribute: objc.ReadWrite,
62 },
63 {
64 Name: "foo",
65 Type: reflect.TypeOf(false),
66 Attribute: objc.ReadWrite,
67 },
68 },
69 []objc.MethodDef{
70 {
71 Cmd: sel_init,
72 Fn: BarInit,
73 },
74 },
75 )
76 if err != nil {
77 panic(err)
78 }
79
80 object := objc.ID(class).Send(sel_new)
81 object.Send(sel_setBar, 123)
82 bar := int(object.Send(sel_bar))
83 fmt.Println(bar)
84 // Output: 123
85}
86
87func ExampleIMP() {
88 imp := objc.NewIMP(func(self objc.ID, _cmd objc.SEL, a3, a4, a5, a6, a7, a8, a9 int) {
89 fmt.Println("IMP:", self, _cmd, a3, a4, a5, a6, a7, a8, a9)
90 })
91
92 purego.SyscallN(uintptr(imp), 105, 567, 9, 2, 3, ^uintptr(4), 4, 8, 9)
93 // Output: IMP: 105 567 9 2 3 -5 4 8 9
94}
95
96func ExampleID_SendSuper() {
97 super, err := objc.RegisterClass(
98 "SuperObject",
99 objc.GetClass("NSObject"),
100 nil,
101 nil,
102 []objc.MethodDef{
103 {
104 Cmd: objc.RegisterName("doSomething"),
105 Fn: func(self objc.ID, _cmd objc.SEL) {
106 fmt.Println("In Super!")
107 },
108 },
109 },
110 )
111 if err != nil {
112 panic(err)
113 }
114
115 child, err := objc.RegisterClass(
116 "ChildObject",
117 super,
118 nil,
119 nil,
120 []objc.MethodDef{
121 {
122 Cmd: objc.RegisterName("doSomething"),
123 Fn: func(self objc.ID, _cmd objc.SEL) {
124 fmt.Println("In Child")
125 self.SendSuper(_cmd)
126 },
127 },
128 },
129 )
130 if err != nil {
131 panic(err)
132 }
133
134 objc.ID(child).Send(objc.RegisterName("new")).Send(objc.RegisterName("doSomething"))
135 // Output: In Child
136 // In Super!
137}
138
139func TestSend(t *testing.T) {
140 // NSNumber comes from Foundation so make sure we have linked to that framework.
141 _, err := purego.Dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", purego.RTLD_GLOBAL)
142 if err != nil {
143 t.Fatal(err)
144 }
145 const double = float64(2.34)
146 // Initialize a NSNumber
147 NSNumber := objc.ID(objc.GetClass("NSNumber")).Send(objc.RegisterName("numberWithDouble:"), double)
148 // Then get that number back using the generic Send function.
149 number := objc.Send[float64](NSNumber, objc.RegisterName("doubleValue"))
150 if double != number {
151 t.Failed()
152 }
153}
154
155func ExampleSend() {
156 type NSRange struct {
157 Location, Range uint
158 }
159 class_NSString := objc.GetClass("NSString")
160 sel_stringWithUTF8String := objc.RegisterName("stringWithUTF8String:")
161
162 fullString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "Hello, World!\x00")
163 subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")
164
165 r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)
166 fmt.Println(r)
167 // Output: {3 7}
168}
169
170func ExampleSendSuper() {
171 super, err := objc.RegisterClass(
172 "SuperObject2",
173 objc.GetClass("NSObject"),
174 nil,
175 nil,
176 []objc.MethodDef{
177 {
178 Cmd: objc.RegisterName("doSomething"),
179 Fn: func(self objc.ID, _cmd objc.SEL) int {
180 return 16
181 },
182 },
183 },
184 )
185 if err != nil {
186 panic(err)
187 }
188
189 child, err := objc.RegisterClass(
190 "ChildObject2",
191 super,
192 nil,
193 nil,
194 []objc.MethodDef{
195 {
196 Cmd: objc.RegisterName("doSomething"),
197 Fn: func(self objc.ID, _cmd objc.SEL) int {
198 return 24
199 },
200 },
201 },
202 )
203 if err != nil {
204 panic(err)
205 }
206
207 res := objc.SendSuper[int](objc.ID(child).Send(objc.RegisterName("new")), objc.RegisterName("doSomething"))
208 fmt.Println(res)
209 // Output: 16
210}