Skip to content

Commit 1d2e38d

Browse files
authored
linux: dynamically load libX11 (#20)
Removing linking of libX11 and replacing it with dlopen to call the functions dynamically. For the future wayland support, the library will not require the libX11 library to be installed on the running system. For compiling it we need it, because of the huge and complicated type definitions, but the compiled binary will run also on a system without libX11. References: #6 Signed-off-by: Vladimír Magyar <[email protected]>
1 parent 076d92f commit 1d2e38d

File tree

2 files changed

+92
-38
lines changed

2 files changed

+92
-38
lines changed

clipboard_linux.c

Lines changed: 91 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,86 @@
1111
#include <stdio.h>
1212
#include <stdint.h>
1313
#include <string.h>
14+
#include <dlfcn.h>
1415
#include <X11/Xlib.h>
1516
#include <X11/Xatom.h>
1617

1718
// syncStatus is a function from the Go side.
1819
extern void syncStatus(uintptr_t handle, int status);
1920

21+
void *libX11;
22+
23+
Display* (*P_XOpenDisplay)(int);
24+
void (*P_XCloseDisplay)(Display*);
25+
Window (*P_XDefaultRootWindow)(Display*);
26+
Window (*P_XCreateSimpleWindow)(Display*, Window, int, int, int, int, int, int, int);
27+
Atom (*P_XInternAtom)(Display*, char*, int);
28+
void (*P_XSetSelectionOwner)(Display*, Atom, Window, unsigned long);
29+
Window (*P_XGetSelectionOwner)(Display*, Atom);
30+
void (*P_XNextEvent)(Display*, XEvent*);
31+
int (*P_XChangeProperty)(Display*, Window, Atom, Atom, int, int, unsigned char*, int);
32+
void (*P_XSendEvent)(Display*, Window, int, long , XEvent*);
33+
int (*P_XGetWindowProperty) (Display*, Window, Atom, long, long, Bool, Atom, Atom*, int*, unsigned long *, unsigned long *, unsigned char **);
34+
void (*P_XFree) (void*);
35+
void (*P_XDeleteProperty) (Display*, Window, Atom);
36+
void (*P_XConvertSelection)(Display*, Atom, Atom, Atom, Window, Time);
37+
38+
int initX11() {
39+
if (libX11) {
40+
return 1;
41+
}
42+
libX11 = dlopen("libX11.so", RTLD_LAZY);
43+
if (!libX11) {
44+
return -1;
45+
}
46+
P_XOpenDisplay = (Display* (*)(int)) dlsym(libX11, "XOpenDisplay");
47+
P_XCloseDisplay = (void (*)(Display*)) dlsym(libX11, "XCloseDisplay");
48+
P_XDefaultRootWindow = (Window (*)(Display*)) dlsym(libX11, "XDefaultRootWindow");
49+
P_XCreateSimpleWindow = (Window (*)(Display*, Window, int, int, int, int, int, int, int)) dlsym(libX11, "XCreateSimpleWindow");
50+
P_XInternAtom = (Atom (*)(Display*, char*, int)) dlsym(libX11, "XInternAtom");
51+
P_XSetSelectionOwner = (void (*)(Display*, Atom, Window, unsigned long)) dlsym(libX11, "XSetSelectionOwner");
52+
P_XGetSelectionOwner = (Window (*)(Display*, Atom)) dlsym(libX11, "XGetSelectionOwner");
53+
P_XNextEvent = (void (*)(Display*, XEvent*)) dlsym(libX11, "XNextEvent");
54+
P_XChangeProperty = (int (*)(Display*, Window, Atom, Atom, int, int, unsigned char*, int)) dlsym(libX11, "XChangeProperty");
55+
P_XSendEvent = (void (*)(Display*, Window, int, long , XEvent*)) dlsym(libX11, "XSendEvent");
56+
P_XGetWindowProperty = (int (*)(Display*, Window, Atom, long, long, Bool, Atom, Atom*, int*, unsigned long *, unsigned long *, unsigned char **)) dlsym(libX11, "XGetWindowProperty");
57+
P_XFree = (void (*)(void*)) dlsym(libX11, "XFree");
58+
P_XDeleteProperty = (void (*)(Display*, Window, Atom)) dlsym(libX11, "XDeleteProperty");
59+
P_XConvertSelection = (void (*)(Display*, Atom, Atom, Atom, Window, Time)) dlsym(libX11, "XConvertSelection");
60+
return 1;
61+
}
62+
2063
int clipboard_test() {
64+
if (!initX11()) {
65+
return -1;
66+
}
67+
2168
Display* d = NULL;
2269
for (int i = 0; i < 42; i++) {
23-
d = XOpenDisplay(0);
70+
d = (*P_XOpenDisplay)(0);
2471
if (d == NULL) {
2572
continue;
2673
}
2774
break;
2875
}
29-
3076
if (d == NULL) {
3177
return -1;
3278
}
33-
XCloseDisplay(d);
79+
(*P_XCloseDisplay)(d);
3480
return 0;
3581
}
3682

3783
// clipboard_write writes the given buf of size n as type typ.
3884
// if start is provided, the value of start will be changed to 1 to indicate
3985
// if the write is availiable for reading.
4086
int clipboard_write(char *typ, unsigned char *buf, size_t n, uintptr_t handle) {
87+
if (!initX11()) {
88+
return -1;
89+
}
90+
4191
Display* d = NULL;
4292
for (int i = 0; i < 42; i++) {
43-
d = XOpenDisplay(0);
93+
d = (*P_XOpenDisplay)(0);
4494
if (d == NULL) {
4595
continue;
4696
}
@@ -50,26 +100,25 @@ int clipboard_write(char *typ, unsigned char *buf, size_t n, uintptr_t handle) {
50100
syncStatus(handle, -1);
51101
return -1;
52102
}
53-
54-
Window w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, 1, 1, 0, 0, 0);
103+
Window w = (*P_XCreateSimpleWindow)(d, (*P_XDefaultRootWindow)(d), 0, 0, 1, 1, 0, 0, 0);
55104

56105
// Use False because these may not available for the first time.
57-
Atom sel = XInternAtom(d, "CLIPBOARD", False);
58-
Atom atomString = XInternAtom(d, "UTF8_STRING", False);
59-
Atom atomImage = XInternAtom(d, "image/png", False);
60-
Atom targetsAtom = XInternAtom(d, "TARGETS", False);
106+
Atom sel = (*P_XInternAtom)(d, "CLIPBOARD", 0);
107+
Atom atomString = (*P_XInternAtom)(d, "UTF8_STRING", 0);
108+
Atom atomImage = (*P_XInternAtom)(d, "image/png", 0);
109+
Atom targetsAtom = (*P_XInternAtom)(d, "TARGETS", 0);
61110

62111
// Use True to makesure the requested type is a valid type.
63-
Atom target = XInternAtom(d, typ, True);
112+
Atom target = (*P_XInternAtom)(d, typ, 1);
64113
if (target == None) {
65-
XCloseDisplay(d);
114+
(*P_XCloseDisplay)(d);
66115
syncStatus(handle, -2);
67116
return -2;
68117
}
69118

70-
XSetSelectionOwner(d, sel, w, CurrentTime);
71-
if (XGetSelectionOwner(d, sel) != w) {
72-
XCloseDisplay(d);
119+
(*P_XSetSelectionOwner)(d, sel, w, CurrentTime);
120+
if ((*P_XGetSelectionOwner)(d, sel) != w) {
121+
(*P_XCloseDisplay)(d);
73122
syncStatus(handle, -3);
74123
return -3;
75124
}
@@ -83,13 +132,13 @@ int clipboard_write(char *typ, unsigned char *buf, size_t n, uintptr_t handle) {
83132
notified = 1;
84133
}
85134

86-
XNextEvent(d, &event);
135+
(*P_XNextEvent)(d, &event);
87136
switch (event.type) {
88137
case SelectionClear:
89138
// For debugging:
90139
// printf("x11write: lost ownership of clipboard selection.\n");
91140
// fflush(stdout);
92-
XCloseDisplay(d);
141+
(*P_XCloseDisplay)(d);
93142
return 0;
94143
case SelectionNotify:
95144
// For debugging:
@@ -114,24 +163,24 @@ int clipboard_write(char *typ, unsigned char *buf, size_t n, uintptr_t handle) {
114163
ev.property = xsr->property;
115164

116165
if (ev.target == atomString && ev.target == target) {
117-
R = XChangeProperty(ev.display, ev.requestor, ev.property,
166+
R = (*P_XChangeProperty)(ev.display, ev.requestor, ev.property,
118167
atomString, 8, PropModeReplace, buf, n);
119168
} else if (ev.target == atomImage && ev.target == target) {
120-
R = XChangeProperty(ev.display, ev.requestor, ev.property,
169+
R = (*P_XChangeProperty)(ev.display, ev.requestor, ev.property,
121170
atomImage, 8, PropModeReplace, buf, n);
122171
} else if (ev.target == targetsAtom) {
123172
// Reply atoms for supported targets, other clients should
124173
// request the clipboard again and obtain the data if their
125174
// implementation is correct.
126175
Atom targets[] = { atomString, atomImage };
127-
R = XChangeProperty(ev.display, ev.requestor, ev.property,
176+
R = (*P_XChangeProperty)(ev.display, ev.requestor, ev.property,
128177
XA_ATOM, 32, PropModeReplace,
129178
(unsigned char *)&targets, sizeof(targets)/sizeof(Atom));
130179
} else {
131180
ev.property = None;
132181
}
133182

134-
if ((R & 2) == 0) XSendEvent(d, ev.requestor, 0, 0, (XEvent *)&ev);
183+
if ((R & 2) == 0) (*P_XSendEvent)(d, ev.requestor, 0, 0, (XEvent *)&ev);
135184
break;
136185
}
137186
}
@@ -140,6 +189,10 @@ int clipboard_write(char *typ, unsigned char *buf, size_t n, uintptr_t handle) {
140189
// read_data reads the property of a selection if the target atom matches
141190
// the actual atom.
142191
unsigned long read_data(XSelectionEvent *sev, Atom sel, Atom prop, Atom target, char **buf) {
192+
if (!initX11()) {
193+
return -1;
194+
}
195+
143196
unsigned char *data;
144197
Atom actual;
145198
int format;
@@ -149,7 +202,7 @@ unsigned long read_data(XSelectionEvent *sev, Atom sel, Atom prop, Atom target,
149202
return 0;
150203
}
151204

152-
int ret = XGetWindowProperty(sev->display, sev->requestor, sev->property,
205+
int ret = (*P_XGetWindowProperty)(sev->display, sev->requestor, sev->property,
153206
0L, (~0L), 0, AnyPropertyType, &actual, &format, &size, &n, &data);
154207
if (ret != Success) {
155208
return 0;
@@ -159,8 +212,8 @@ unsigned long read_data(XSelectionEvent *sev, Atom sel, Atom prop, Atom target,
159212
*buf = (char *)malloc(size * sizeof(char));
160213
memcpy(*buf, data, size*sizeof(char));
161214
}
162-
XFree(data);
163-
XDeleteProperty(sev->display, sev->requestor, sev->property);
215+
(*P_XFree)(data);
216+
(*P_XDeleteProperty)(sev->display, sev->requestor, sev->property);
164217
return size * sizeof(char);
165218
}
166219

@@ -169,9 +222,13 @@ unsigned long read_data(XSelectionEvent *sev, Atom sel, Atom prop, Atom target,
169222
//
170223
// The caller of this function should responsible for the free of the buf.
171224
unsigned long clipboard_read(char* typ, char **buf) {
225+
if (!initX11()) {
226+
return -1;
227+
}
228+
172229
Display* d = NULL;
173230
for (int i = 0; i < 42; i++) {
174-
d = XOpenDisplay(0);
231+
d = (*P_XOpenDisplay)(0);
175232
if (d == NULL) {
176233
continue;
177234
}
@@ -181,27 +238,27 @@ unsigned long clipboard_read(char* typ, char **buf) {
181238
return -1;
182239
}
183240

184-
Window w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, 1, 1, 0, 0, 0);
241+
Window w = (*P_XCreateSimpleWindow)(d, (*P_XDefaultRootWindow)(d), 0, 0, 1, 1, 0, 0, 0);
185242

186243
// Use False because these may not available for the first time.
187-
Atom sel = XInternAtom(d, "CLIPBOARD", False);
188-
Atom prop = XInternAtom(d, "GOLANG_DESIGN_DATA", False);
244+
Atom sel = (*P_XInternAtom)(d, "CLIPBOARD", False);
245+
Atom prop = (*P_XInternAtom)(d, "GOLANG_DESIGN_DATA", False);
189246

190247
// Use True to makesure the requested type is a valid type.
191-
Atom target = XInternAtom(d, typ, True);
248+
Atom target = (*P_XInternAtom)(d, typ, True);
192249
if (target == None) {
193-
XCloseDisplay(d);
250+
(*P_XCloseDisplay)(d);
194251
return -2;
195252
}
196253

197-
XConvertSelection(d, sel, target, prop, w, CurrentTime);
254+
(*P_XConvertSelection)(d, sel, target, prop, w, CurrentTime);
198255
XEvent event;
199256
for (;;) {
200-
XNextEvent(d, &event);
257+
(*P_XNextEvent)(d, &event);
201258
if (event.type != SelectionNotify) continue;
202259
break;
203260
}
204261
unsigned long n = read_data((XSelectionEvent *)&event.xselection, sel, prop, target, buf);
205-
XCloseDisplay(d);
262+
(*P_XCloseDisplay)(d);
206263
return n;
207-
}
264+
}

clipboard_linux.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,11 @@
1010
package clipboard
1111

1212
/*
13-
#cgo LDFLAGS: -lX11
13+
#cgo LDFLAGS: -ldl
1414
#include <stdlib.h>
1515
#include <stdio.h>
1616
#include <stdint.h>
1717
#include <string.h>
18-
#include <X11/Xlib.h>
19-
#include <X11/Xatom.h>
20-
#include <stdatomic.h>
2118
2219
int clipboard_test();
2320
int clipboard_write(

0 commit comments

Comments
 (0)