upstream-v0.10.1 eaff005

objc_runtime_darwin_test.go RawHistoryFolder

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3
4package objc_test
5
6import (
7	"fmt"
8	"log"
9	"reflect"
10	"testing"
11
12	"github.com/ebitengine/purego"
13	"github.com/ebitengine/purego/objc"
14)
15
16func ExampleRegisterClass_helloworld() {
17	class, err := objc.RegisterClass(
18		"FooObject",
19		objc.GetClass("NSObject"),
20		nil,
21		nil,
22		[]objc.MethodDef{
23			{
24				Cmd: objc.RegisterName("run"),
25				Fn: func(self objc.ID, _cmd objc.SEL) {
26					fmt.Println("Hello World!")
27				},
28			},
29		},
30	)
31	if err != nil {
32		panic(err)
33	}
34
35	object := objc.ID(class).Send(objc.RegisterName("new"))
36	object.Send(objc.RegisterName("run"))
37	// Output: Hello World!
38}
39
40func ExampleRegisterClass() {
41	var (
42		sel_new    = objc.RegisterName("new")
43		sel_init   = objc.RegisterName("init")
44		sel_setBar = objc.RegisterName("setBar:")
45		sel_bar    = objc.RegisterName("bar")
46
47		BarInit = func(id objc.ID, cmd objc.SEL) objc.ID {
48			return id.SendSuper(cmd)
49		}
50	)
51
52	class, err := objc.RegisterClass(
53		"BarObject",
54		objc.GetClass("NSObject"),
55		[]*objc.Protocol{
56			objc.GetProtocol("NSDelegateWindow"),
57		},
58		[]objc.FieldDef{
59			{
60				Name:      "bar",
61				Type:      reflect.TypeOf(int(0)),
62				Attribute: objc.ReadWrite,
63			},
64			{
65				Name:      "foo",
66				Type:      reflect.TypeOf(false),
67				Attribute: objc.ReadWrite,
68			},
69		},
70		[]objc.MethodDef{
71			{
72				Cmd: sel_init,
73				Fn:  BarInit,
74			},
75		},
76	)
77	if err != nil {
78		panic(err)
79	}
80
81	object := objc.ID(class).Send(sel_new)
82	object.Send(sel_setBar, 123)
83	bar := int(object.Send(sel_bar))
84	fmt.Println(bar)
85	// Output: 123
86}
87
88func ExampleIMP() {
89	imp := objc.NewIMP(func(self objc.ID, _cmd objc.SEL, a3, a4, a5, a6, a7, a8, a9 int) {
90		fmt.Println("IMP:", self, _cmd, a3, a4, a5, a6, a7, a8, a9)
91	})
92
93	purego.SyscallN(uintptr(imp), 105, 567, 9, 2, 3, ^uintptr(4), 4, 8, 9)
94	// Output: IMP: 105 567 9 2 3 -5 4 8 9
95}
96
97func ExampleID_SendSuper() {
98	super, err := objc.RegisterClass(
99		"SuperObject",
100		objc.GetClass("NSObject"),
101		nil,
102		nil,
103		[]objc.MethodDef{
104			{
105				Cmd: objc.RegisterName("doSomething"),
106				Fn: func(self objc.ID, _cmd objc.SEL) {
107					fmt.Println("In Super!")
108				},
109			},
110		},
111	)
112	if err != nil {
113		panic(err)
114	}
115
116	child, err := objc.RegisterClass(
117		"ChildObject",
118		super,
119		nil,
120		nil,
121		[]objc.MethodDef{
122			{
123				Cmd: objc.RegisterName("doSomething"),
124				Fn: func(self objc.ID, _cmd objc.SEL) {
125					fmt.Println("In Child")
126					self.SendSuper(_cmd)
127				},
128			},
129		},
130	)
131	if err != nil {
132		panic(err)
133	}
134
135	objc.ID(child).Send(objc.RegisterName("new")).Send(objc.RegisterName("doSomething"))
136	// Output: In Child
137	// In Super!
138}
139
140func TestSend(t *testing.T) {
141	// NSNumber comes from Foundation so make sure we have linked to that framework.
142	_, err := purego.Dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", purego.RTLD_GLOBAL|purego.RTLD_NOW)
143	if err != nil {
144		t.Fatal(err)
145	}
146	const double = float64(2.34)
147	// Initialize a NSNumber
148	NSNumber := objc.ID(objc.GetClass("NSNumber")).Send(objc.RegisterName("numberWithDouble:"), double)
149	// Then get that number back using the generic Send function.
150	number := objc.Send[float64](NSNumber, objc.RegisterName("doubleValue"))
151	if double != number {
152		t.Failed()
153	}
154}
155
156func ExampleSend() {
157	type NSRange struct {
158		Location, Range uint
159	}
160	class_NSString := objc.GetClass("NSString")
161	sel_stringWithUTF8String := objc.RegisterName("stringWithUTF8String:")
162
163	fullString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "Hello, World!\x00")
164	subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")
165
166	r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)
167	fmt.Println(r)
168	// Output: {3 7}
169}
170
171func ExampleSendSuper() {
172	super, err := objc.RegisterClass(
173		"SuperObject2",
174		objc.GetClass("NSObject"),
175		nil,
176		nil,
177		[]objc.MethodDef{
178			{
179				Cmd: objc.RegisterName("doSomething"),
180				Fn: func(self objc.ID, _cmd objc.SEL) int {
181					return 16
182				},
183			},
184		},
185	)
186	if err != nil {
187		panic(err)
188	}
189
190	child, err := objc.RegisterClass(
191		"ChildObject2",
192		super,
193		nil,
194		nil,
195		[]objc.MethodDef{
196			{
197				Cmd: objc.RegisterName("doSomething"),
198				Fn: func(self objc.ID, _cmd objc.SEL) int {
199					return 24
200				},
201			},
202		},
203	)
204	if err != nil {
205		panic(err)
206	}
207
208	res := objc.SendSuper[int](objc.ID(child).Send(objc.RegisterName("new")), objc.RegisterName("doSomething"))
209	fmt.Println(res)
210	// Output: 16
211}
212
213func ExampleAllocateProtocol() {
214	var p *objc.Protocol
215	if p = objc.AllocateProtocol("MyCustomProtocol"); p != nil {
216		p.AddMethodDescription(objc.RegisterName("isFoo"), "B16@0:8", true, true)
217		var adoptedProtocol *objc.Protocol
218		adoptedProtocol = objc.GetProtocol("NSObject")
219		if adoptedProtocol == nil {
220			log.Fatalln("protocol 'NSObject' does not exist")
221		}
222		p.AddProtocol(adoptedProtocol)
223		p.AddProperty("accessibilityElement", []objc.PropertyAttribute{
224			{Name: &[]byte("T\x00")[0], Value: &[]byte("B\x00")[0]},
225			{Name: &[]byte("G\x00")[0], Value: &[]byte("isBar\x00")[0]},
226		}, true, true)
227		p.Register()
228	}
229
230	p = objc.GetProtocol("MyCustomProtocol")
231
232	for _, protocol := range p.CopyProtocolList() {
233		fmt.Println(protocol.Name())
234	}
235	for _, property := range p.CopyPropertyList(true, true) {
236		fmt.Println(property.Name(), property.Attributes())
237	}
238	for _, method := range p.CopyMethodDescriptionList(true, true) {
239		fmt.Println(method.Name(), method.Types())
240	}
241
242	// Output:
243	// NSObject
244	// accessibilityElement TB,GisBar
245	// isFoo B16@0:8
246}

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