v0.7.1 ff2c2cc

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	"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("/System/Library/Frameworks/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}
120
121func ExampleSend() {
122	type NSRange struct {
123		Location, Range uint
124	}
125	class_NSString := objc.GetClass("NSString")
126	sel_stringWithUTF8String := objc.RegisterName("stringWithUTF8String:")
127
128	fullString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "Hello, World!\x00")
129	subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")
130
131	r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)
132
133	fmt.Println(r)
134
135	// Output: {3 7}
136}
137
138func ExampleSendSuper() {
139	super := objc.AllocateClassPair(objc.GetClass("NSObject"), "SuperObject2", 0)
140	super.AddMethod(objc.RegisterName("doSomething"), objc.NewIMP(func(self objc.ID, _cmd objc.SEL) int {
141		return 16
142	}), "i@:")
143	super.Register()
144
145	child := objc.AllocateClassPair(super, "ChildObject2", 0)
146	child.AddMethod(objc.RegisterName("doSomething"), objc.NewIMP(func(self objc.ID, _cmd objc.SEL) int {
147		return 24
148	}), "i@:")
149	child.Register()
150
151	res := objc.SendSuper[int](objc.ID(child).Send(objc.RegisterName("new")), objc.RegisterName("doSomething"))
152
153	fmt.Println(res)
154	// Output: 16
155}

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