detached 15e9011

lib.go RawHistoryFolder

1package server
2
3import (
4	"fmt"
5	"sync"
6	"unsafe"
7
8	"github.com/bnema/purego"
9	"golang.org/x/sys/unix"
10)
11
12// libwayland-server entry points. Only non-varargs functions are bound.
13var (
14	wlDisplayCreate         func() uintptr
15	wlDisplayDestroy        func(display uintptr)
16	wlDisplayDestroyClients func(display uintptr)
17	wlDisplayAddSocketFD    func(display uintptr, fd int32) int32
18	wlDisplayGetEventLoop   func(display uintptr) uintptr
19	wlEventLoopGetFD        func(loop uintptr) int32
20	wlEventLoopAddFD        func(loop uintptr, fd int32, mask uint32, fn, data uintptr) uintptr
21	wlEventSourceRemove     func(source uintptr) int32
22	wlGlobalCreate          func(display, iface uintptr, version int32, data uintptr, bind uintptr) uintptr
23	wlGlobalRemove          func(global uintptr)
24	wlResourcePostError     func(resource uintptr, code uint32, msg uintptr)
25)
26
27var (
28	loadOnce sync.Once
29	loadErr  error
30
31	symDisplayFlushClients, symEventLoopDispatch, symResourceCreate                         uintptr
32	symResourceSetDispatcher, symResourcePostEventArr, symResourceDestroy, symResourceGetID uintptr
33	symClientGetCredentials, symClientGetFD, symClientCreate                                uintptr
34	symClientAddDestroyListener, symListRemove                                              uintptr
35	symErrnoLocation                                                                        uintptr
36	symDisplaySetGlobalFilter, symEventSourceFDUpdate                                       uintptr
37	// wl_fixes support (libwayland 1.26+); zero on older libraries.
38	symFixesAckGlobalRemove uintptr
39
40	// Shared C callbacks. purego callbacks are never freed, so there is one
41	// of each for the whole process.
42	cbDispatcher   uintptr
43	cbDestroy      uintptr
44	cbClientGone   uintptr
45	cbBind         uintptr
46	cbWake         uintptr
47	cbFD           uintptr
48	cbGlobalFilter uintptr
49)
50
51func load() error {
52	loadOnce.Do(func() {
53		lib, err := purego.Dlopen("libwayland-server.so.0", purego.RTLD_NOW|purego.RTLD_GLOBAL)
54		if err != nil {
55			loadErr = fmt.Errorf("purego-libwayland: open libwayland-server.so.0: %w", err)
56			return
57		}
58		defer func() {
59			if r := recover(); r != nil {
60				loadErr = fmt.Errorf("purego-libwayland: %v", r)
61			}
62		}()
63		reg := func(fptr any, name string) { purego.RegisterLibFunc(fptr, lib, name) }
64		reg(&wlDisplayCreate, "wl_display_create")
65		reg(&wlDisplayDestroy, "wl_display_destroy")
66		reg(&wlDisplayDestroyClients, "wl_display_destroy_clients")
67		reg(&wlDisplayAddSocketFD, "wl_display_add_socket_fd")
68		reg(&wlDisplayGetEventLoop, "wl_display_get_event_loop")
69		reg(&wlEventLoopGetFD, "wl_event_loop_get_fd")
70		reg(&wlEventLoopAddFD, "wl_event_loop_add_fd")
71		reg(&wlEventSourceRemove, "wl_event_source_remove")
72		reg(&wlGlobalCreate, "wl_global_create")
73		reg(&wlGlobalRemove, "wl_global_remove")
74		reg(&wlResourcePostError, "wl_resource_post_error")
75		for _, entry := range []struct {
76			name string
77			sym  *uintptr
78		}{
79			{"wl_display_set_global_filter", &symDisplaySetGlobalFilter},
80			{"wl_event_source_fd_update", &symEventSourceFDUpdate},
81			{"wl_display_flush_clients", &symDisplayFlushClients},
82			{"wl_event_loop_dispatch", &symEventLoopDispatch},
83			{"wl_resource_create", &symResourceCreate},
84			{"wl_resource_get_id", &symResourceGetID},
85			{"wl_client_get_credentials", &symClientGetCredentials},
86			{"wl_client_get_fd", &symClientGetFD},
87			{"wl_client_create", &symClientCreate},
88			{"wl_client_add_destroy_listener", &symClientAddDestroyListener},
89			{"wl_list_remove", &symListRemove},
90			{"wl_resource_set_dispatcher", &symResourceSetDispatcher},
91			{"wl_resource_post_event_array", &symResourcePostEventArr},
92			{"wl_resource_destroy", &symResourceDestroy},
93		} {
94			*entry.sym, err = purego.Dlsym(lib, entry.name)
95			if err != nil {
96				loadErr = fmt.Errorf("purego-libwayland: resolve %s: %w", entry.name, err)
97				return
98			}
99		}
100		symFixesAckGlobalRemove, _ = purego.Dlsym(lib, "wl_fixes_handle_ack_global_remove")
101		symErrnoLocation, err = purego.Dlsym(lib, "__errno_location")
102		if err != nil {
103			libc, openErr := purego.Dlopen("libc.so.6", purego.RTLD_NOW|purego.RTLD_GLOBAL)
104			if openErr != nil {
105				loadErr = fmt.Errorf("purego-libwayland: open libc.so.6: %w", openErr)
106				return
107			}
108			symErrnoLocation, err = purego.Dlsym(libc, "__errno_location")
109			if err != nil {
110				loadErr = fmt.Errorf("purego-libwayland: resolve __errno_location: %w", err)
111				return
112			}
113		}
114
115		cbDispatcher = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
116			// C memory owned by libwayland; reinterpret pointer bits without uintptr-to-pointer conversion.
117			msg, args := a.Int(3), a.Int(4)
118			return uintptr(uint32(dispatch(a.Int(0), a.Int(1), uint32(a.Int(2)), *(*unsafe.Pointer)(unsafe.Pointer(&msg)), *(*unsafe.Pointer)(unsafe.Pointer(&args)))))
119		})
120		cbDestroy = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
121			destroyed(a.Int(0))
122			return 0
123		})
124		cbClientGone = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
125			clientGone(a.Int(0))
126			return 0
127		})
128		cbBind = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
129			bind(a.Int(0), a.Int(1), uint32(a.Int(2)), uint32(a.Int(3)))
130			return 0
131		})
132		cbWake = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
133			return uintptr(uint32(wake(int32(a.Int(0)), uint32(a.Int(1)), a.Int(2))))
134		})
135		cbGlobalFilter = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr { return uintptr(globalFilter(a.Int(0), a.Int(1), a.Int(2))) })
136		cbFD = purego.NewCallbackInts(func(a *purego.CallbackArgs) uintptr {
137			return uintptr(uint32(fdReadable(int32(a.Int(0)), uint32(a.Int(1)), a.Int(2))))
138		})
139	})
140	return loadErr
141}
142
143// Integer and pointer-only entry points avoid RegisterLibFunc's reflective call path.
144func wlDisplayFlushClients(display uintptr) {
145	purego.Syscall6(symDisplayFlushClients, display, 0, 0, 0, 0, 0)
146}
147func wlEventLoopDispatch(loop uintptr, timeout int32) int32 {
148	r, _, _ := purego.Syscall6(symEventLoopDispatch, loop, uintptr(timeout), 0, 0, 0, 0)
149	return int32(r)
150}
151func lastErrno() unix.Errno {
152	p, _, _ := purego.Syscall6(symErrnoLocation, 0, 0, 0, 0, 0, 0)
153	// C memory owned by libc; reinterpret pointer bits without uintptr-to-pointer conversion.
154	return unix.Errno(**(**int32)(unsafe.Pointer(&p)))
155}
156func wlResourceCreate(client, iface uintptr, version int32, id uint32) uintptr {
157	r, _, _ := purego.Syscall6(symResourceCreate, client, iface, uintptr(version), uintptr(id), 0, 0)
158	return r
159}
160func wlResourceGetID(resource uintptr) uint32 {
161	r, _, _ := purego.Syscall6(symResourceGetID, resource, 0, 0, 0, 0, 0)
162	return uint32(r)
163}
164func wlResourceSetDispatcher(resource, dispatcher, impl, data, destroy uintptr) {
165	purego.Syscall6(symResourceSetDispatcher, resource, dispatcher, impl, data, destroy, 0)
166}
167func wlResourcePostEventArr(resource uintptr, opcode uint32, args unsafe.Pointer) {
168	purego.Syscall6(symResourcePostEventArr, resource, uintptr(opcode), uintptr(args), 0, 0, 0)
169}
170func wlResourceDestroy(resource uintptr) {
171	purego.Syscall6(symResourceDestroy, resource, 0, 0, 0, 0, 0)
172}
173func wlFixesHandleAckGlobalRemove(fixes, registry uintptr, name uint32) {
174	purego.Syscall6(symFixesAckGlobalRemove, fixes, registry, uintptr(name), 0, 0, 0)
175}
176
177func wlDisplaySetGlobalFilter(display, callback, data uintptr) {
178	purego.Syscall6(symDisplaySetGlobalFilter, display, callback, data, 0, 0, 0)
179}
180func wlEventSourceFDUpdate(source uintptr, mask uint32) int32 {
181	r, _, _ := purego.Syscall6(symEventSourceFDUpdate, source, uintptr(mask), 0, 0, 0, 0)
182	return int32(r)
183}

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 14

↑↓ moveenter openesc close