Blame


1 bb3b0aeb 2006-03-03 devnull /*
2 bb3b0aeb 2006-03-03 devnull * This program is only intended for OS X, but the
3 bb3b0aeb 2006-03-03 devnull * ifdef __APPLE__ below lets us build it on all systems.
4 bb3b0aeb 2006-03-03 devnull * On non-OS X systems, you can use it to hold the snarf
5 bb3b0aeb 2006-03-03 devnull * buffer around after a program exits.
6 bb3b0aeb 2006-03-03 devnull */
7 bb3b0aeb 2006-03-03 devnull
8 bb3b0aeb 2006-03-03 devnull #include <u.h>
9 bb3b0aeb 2006-03-03 devnull #define Colormap XColormap
10 bb3b0aeb 2006-03-03 devnull #define Cursor XCursor
11 bb3b0aeb 2006-03-03 devnull #define Display XDisplay
12 bb3b0aeb 2006-03-03 devnull #define Drawable XDrawable
13 bb3b0aeb 2006-03-03 devnull #define Font XFont
14 bb3b0aeb 2006-03-03 devnull #define GC XGC
15 bb3b0aeb 2006-03-03 devnull #define Point XPoint
16 bb3b0aeb 2006-03-03 devnull #define Rectangle XRectangle
17 bb3b0aeb 2006-03-03 devnull #define Screen XScreen
18 bb3b0aeb 2006-03-03 devnull #define Visual XVisual
19 bb3b0aeb 2006-03-03 devnull #define Window XWindow
20 bb3b0aeb 2006-03-03 devnull #include <X11/Xlib.h>
21 bb3b0aeb 2006-03-03 devnull #include <X11/Xatom.h>
22 bb3b0aeb 2006-03-03 devnull #include <X11/Xutil.h>
23 bb3b0aeb 2006-03-03 devnull #include <X11/keysym.h>
24 bb3b0aeb 2006-03-03 devnull #include <X11/IntrinsicP.h>
25 bb3b0aeb 2006-03-03 devnull #include <X11/StringDefs.h>
26 bb3b0aeb 2006-03-03 devnull #undef Colormap
27 bb3b0aeb 2006-03-03 devnull #undef Cursor
28 bb3b0aeb 2006-03-03 devnull #undef Display
29 bb3b0aeb 2006-03-03 devnull #undef Drawable
30 bb3b0aeb 2006-03-03 devnull #undef Font
31 bb3b0aeb 2006-03-03 devnull #undef GC
32 bb3b0aeb 2006-03-03 devnull #undef Point
33 bb3b0aeb 2006-03-03 devnull #undef Rectangle
34 bb3b0aeb 2006-03-03 devnull #undef Screen
35 bb3b0aeb 2006-03-03 devnull #undef Visual
36 bb3b0aeb 2006-03-03 devnull #undef Window
37 a7415518 2007-02-22 devnull AUTOLIB(X11);
38 bb3b0aeb 2006-03-03 devnull #ifdef __APPLE__
39 bb3b0aeb 2006-03-03 devnull #define APPLESNARF
40 bb3b0aeb 2006-03-03 devnull #define Boolean AppleBoolean
41 bb3b0aeb 2006-03-03 devnull #define Rect AppleRect
42 bb3b0aeb 2006-03-03 devnull #define EventMask AppleEventMask
43 bb3b0aeb 2006-03-03 devnull #define Point ApplePoint
44 bb3b0aeb 2006-03-03 devnull #define Cursor AppleCursor
45 bb3b0aeb 2006-03-03 devnull #include <Carbon/Carbon.h>
46 bb3b0aeb 2006-03-03 devnull AUTOFRAMEWORK(Carbon)
47 bb3b0aeb 2006-03-03 devnull #undef Boolean
48 bb3b0aeb 2006-03-03 devnull #undef Rect
49 bb3b0aeb 2006-03-03 devnull #undef EventMask
50 bb3b0aeb 2006-03-03 devnull #undef Point
51 bb3b0aeb 2006-03-03 devnull #undef Cursor
52 bb3b0aeb 2006-03-03 devnull #endif
53 bb3b0aeb 2006-03-03 devnull #include <libc.h>
54 bb3b0aeb 2006-03-03 devnull #undef time
55 bb3b0aeb 2006-03-03 devnull AUTOLIB(draw) /* to cause link of X11 */
56 bb3b0aeb 2006-03-03 devnull
57 bb3b0aeb 2006-03-03 devnull enum {
58 cbeb0b26 2006-04-01 devnull SnarfSize = 65536
59 bb3b0aeb 2006-03-03 devnull };
60 bb3b0aeb 2006-03-03 devnull char snarf[3*SnarfSize+1];
61 bb3b0aeb 2006-03-03 devnull Rune rsnarf[SnarfSize+1];
62 bb3b0aeb 2006-03-03 devnull XDisplay *xdisplay;
63 bb3b0aeb 2006-03-03 devnull XWindow drawable;
64 bb3b0aeb 2006-03-03 devnull Atom xclipboard;
65 bb3b0aeb 2006-03-03 devnull Atom xutf8string;
66 bb3b0aeb 2006-03-03 devnull Atom xtargets;
67 bb3b0aeb 2006-03-03 devnull Atom xtext;
68 bb3b0aeb 2006-03-03 devnull Atom xcompoundtext;
69 bb3b0aeb 2006-03-03 devnull
70 bb3b0aeb 2006-03-03 devnull void xselectionrequest(XEvent*);
71 bb3b0aeb 2006-03-03 devnull char *xgetsnarf(void);
72 bb3b0aeb 2006-03-03 devnull void appleputsnarf(void);
73 bb3b0aeb 2006-03-03 devnull void xputsnarf(void);
74 bb3b0aeb 2006-03-03 devnull
75 bb3b0aeb 2006-03-03 devnull int verbose;
76 bb3b0aeb 2006-03-03 devnull
77 bb3b0aeb 2006-03-03 devnull #ifdef __APPLE__
78 bb3b0aeb 2006-03-03 devnull PasteboardRef appleclip;
79 bb3b0aeb 2006-03-03 devnull #endif
80 bb3b0aeb 2006-03-03 devnull
81 bb3b0aeb 2006-03-03 devnull void
82 bb3b0aeb 2006-03-03 devnull usage(void)
83 bb3b0aeb 2006-03-03 devnull {
84 bb3b0aeb 2006-03-03 devnull fprint(2, "usage: snarfer [-v]\n");
85 bb3b0aeb 2006-03-03 devnull exits("usage");
86 bb3b0aeb 2006-03-03 devnull }
87 bb3b0aeb 2006-03-03 devnull
88 bb3b0aeb 2006-03-03 devnull void
89 bb3b0aeb 2006-03-03 devnull main(int argc, char **argv)
90 bb3b0aeb 2006-03-03 devnull {
91 bb3b0aeb 2006-03-03 devnull XEvent xevent;
92 fa325e9b 2020-01-10 cross
93 bb3b0aeb 2006-03-03 devnull ARGBEGIN{
94 bb3b0aeb 2006-03-03 devnull default:
95 bb3b0aeb 2006-03-03 devnull usage();
96 bb3b0aeb 2006-03-03 devnull case 'v':
97 bb3b0aeb 2006-03-03 devnull verbose = 1;
98 bb3b0aeb 2006-03-03 devnull break;
99 bb3b0aeb 2006-03-03 devnull }ARGEND
100 bb3b0aeb 2006-03-03 devnull
101 bb3b0aeb 2006-03-03 devnull if((xdisplay = XOpenDisplay(nil)) == nil)
102 bb3b0aeb 2006-03-03 devnull sysfatal("XOpenDisplay: %r");
103 fa325e9b 2020-01-10 cross drawable = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay),
104 fa325e9b 2020-01-10 cross 0, 0, 1, 1, 0, 0,
105 fa325e9b 2020-01-10 cross InputOutput, DefaultVisual(xdisplay, DefaultScreen(xdisplay)),
106 bb3b0aeb 2006-03-03 devnull 0, 0);
107 bb3b0aeb 2006-03-03 devnull if(drawable == None)
108 bb3b0aeb 2006-03-03 devnull sysfatal("XCreateWindow: %r");
109 bb3b0aeb 2006-03-03 devnull XFlush(xdisplay);
110 fa325e9b 2020-01-10 cross
111 bb3b0aeb 2006-03-03 devnull xclipboard = XInternAtom(xdisplay, "CLIPBOARD", False);
112 bb3b0aeb 2006-03-03 devnull xutf8string = XInternAtom(xdisplay, "UTF8_STRING", False);
113 bb3b0aeb 2006-03-03 devnull xtargets = XInternAtom(xdisplay, "TARGETS", False);
114 bb3b0aeb 2006-03-03 devnull xtext = XInternAtom(xdisplay, "TEXT", False);
115 bb3b0aeb 2006-03-03 devnull xcompoundtext = XInternAtom(xdisplay, "COMPOUND_TEXT", False);
116 bb3b0aeb 2006-03-03 devnull
117 bb3b0aeb 2006-03-03 devnull #ifdef __APPLE__
118 bb3b0aeb 2006-03-03 devnull if(PasteboardCreate(kPasteboardClipboard, &appleclip) != noErr)
119 bb3b0aeb 2006-03-03 devnull sysfatal("pasteboard create failed");
120 bb3b0aeb 2006-03-03 devnull #endif
121 bb3b0aeb 2006-03-03 devnull
122 bb3b0aeb 2006-03-03 devnull xgetsnarf();
123 bb3b0aeb 2006-03-03 devnull appleputsnarf();
124 bb3b0aeb 2006-03-03 devnull xputsnarf();
125 fa325e9b 2020-01-10 cross
126 bb3b0aeb 2006-03-03 devnull for(;;){
127 bb3b0aeb 2006-03-03 devnull XNextEvent(xdisplay, &xevent);
128 bb3b0aeb 2006-03-03 devnull switch(xevent.type){
129 bb3b0aeb 2006-03-03 devnull case DestroyNotify:
130 bb3b0aeb 2006-03-03 devnull exits(0);
131 bb3b0aeb 2006-03-03 devnull case SelectionClear:
132 bb3b0aeb 2006-03-03 devnull xgetsnarf();
133 bb3b0aeb 2006-03-03 devnull appleputsnarf();
134 bb3b0aeb 2006-03-03 devnull xputsnarf();
135 bb3b0aeb 2006-03-03 devnull if(verbose)
136 bb3b0aeb 2006-03-03 devnull print("snarf{%s}\n", snarf);
137 bb3b0aeb 2006-03-03 devnull break;
138 bb3b0aeb 2006-03-03 devnull case SelectionRequest:
139 bb3b0aeb 2006-03-03 devnull xselectionrequest(&xevent);
140 bb3b0aeb 2006-03-03 devnull break;
141 bb3b0aeb 2006-03-03 devnull }
142 bb3b0aeb 2006-03-03 devnull }
143 bb3b0aeb 2006-03-03 devnull }
144 bb3b0aeb 2006-03-03 devnull
145 bb3b0aeb 2006-03-03 devnull void
146 bb3b0aeb 2006-03-03 devnull xselectionrequest(XEvent *e)
147 bb3b0aeb 2006-03-03 devnull {
148 bb3b0aeb 2006-03-03 devnull char *name;
149 bb3b0aeb 2006-03-03 devnull Atom a[4];
150 bb3b0aeb 2006-03-03 devnull XEvent r;
151 bb3b0aeb 2006-03-03 devnull XSelectionRequestEvent *xe;
152 bb3b0aeb 2006-03-03 devnull XDisplay *xd;
153 fa325e9b 2020-01-10 cross
154 bb3b0aeb 2006-03-03 devnull xd = xdisplay;
155 fa325e9b 2020-01-10 cross
156 bb3b0aeb 2006-03-03 devnull memset(&r, 0, sizeof r);
157 bb3b0aeb 2006-03-03 devnull xe = (XSelectionRequestEvent*)e;
158 bb3b0aeb 2006-03-03 devnull if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",
159 bb3b0aeb 2006-03-03 devnull xe->target, xe->requestor, xe->property, xe->selection);
160 bb3b0aeb 2006-03-03 devnull r.xselection.property = xe->property;
161 bb3b0aeb 2006-03-03 devnull if(xe->target == xtargets){
162 bb3b0aeb 2006-03-03 devnull a[0] = XA_STRING;
163 bb3b0aeb 2006-03-03 devnull a[1] = xutf8string;
164 bb3b0aeb 2006-03-03 devnull a[2] = xtext;
165 bb3b0aeb 2006-03-03 devnull a[3] = xcompoundtext;
166 bb3b0aeb 2006-03-03 devnull
167 bb3b0aeb 2006-03-03 devnull XChangeProperty(xd, xe->requestor, xe->property, xe->target,
168 bb3b0aeb 2006-03-03 devnull 8, PropModeReplace, (uchar*)a, sizeof a);
169 bb3b0aeb 2006-03-03 devnull }else if(xe->target == XA_STRING || xe->target == xutf8string || xe->target == xtext || xe->target == xcompoundtext){
170 bb3b0aeb 2006-03-03 devnull /* if the target is STRING we're supposed to reply with Latin1 XXX */
171 bb3b0aeb 2006-03-03 devnull XChangeProperty(xd, xe->requestor, xe->property, xe->target,
172 bb3b0aeb 2006-03-03 devnull 8, PropModeReplace, (uchar*)snarf, strlen(snarf));
173 bb3b0aeb 2006-03-03 devnull }else{
174 bb3b0aeb 2006-03-03 devnull name = XGetAtomName(xd, xe->target);
175 bb3b0aeb 2006-03-03 devnull if(strcmp(name, "TIMESTAMP") != 0)
176 bb3b0aeb 2006-03-03 devnull fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
177 bb3b0aeb 2006-03-03 devnull r.xselection.property = None;
178 bb3b0aeb 2006-03-03 devnull }
179 bb3b0aeb 2006-03-03 devnull
180 bb3b0aeb 2006-03-03 devnull r.xselection.display = xe->display;
181 bb3b0aeb 2006-03-03 devnull /* r.xselection.property filled above */
182 bb3b0aeb 2006-03-03 devnull r.xselection.target = xe->target;
183 bb3b0aeb 2006-03-03 devnull r.xselection.type = SelectionNotify;
184 bb3b0aeb 2006-03-03 devnull r.xselection.requestor = xe->requestor;
185 bb3b0aeb 2006-03-03 devnull r.xselection.time = xe->time;
186 bb3b0aeb 2006-03-03 devnull r.xselection.send_event = True;
187 bb3b0aeb 2006-03-03 devnull r.xselection.selection = xe->selection;
188 bb3b0aeb 2006-03-03 devnull XSendEvent(xd, xe->requestor, False, 0, &r);
189 bb3b0aeb 2006-03-03 devnull XFlush(xd);
190 bb3b0aeb 2006-03-03 devnull }
191 bb3b0aeb 2006-03-03 devnull
192 bb3b0aeb 2006-03-03 devnull char*
193 bb3b0aeb 2006-03-03 devnull xgetsnarf(void)
194 bb3b0aeb 2006-03-03 devnull {
195 bb3b0aeb 2006-03-03 devnull uchar *data, *xdata;
196 bb3b0aeb 2006-03-03 devnull Atom clipboard, type, prop;
197 bb3b0aeb 2006-03-03 devnull ulong len, lastlen, dummy;
198 bb3b0aeb 2006-03-03 devnull int fmt, i;
199 bb3b0aeb 2006-03-03 devnull XWindow w;
200 bb3b0aeb 2006-03-03 devnull XDisplay *xd;
201 fa325e9b 2020-01-10 cross
202 bb3b0aeb 2006-03-03 devnull xd = xdisplay;
203 bb3b0aeb 2006-03-03 devnull
204 94bd4b6c 2006-03-23 devnull w = None;
205 94bd4b6c 2006-03-23 devnull clipboard = None;
206 94bd4b6c 2006-03-23 devnull
207 bb3b0aeb 2006-03-03 devnull /*
208 bb3b0aeb 2006-03-03 devnull * Is there a primary selection (highlighted text in an xterm)?
209 bb3b0aeb 2006-03-03 devnull */
210 94bd4b6c 2006-03-23 devnull if(0){
211 94bd4b6c 2006-03-23 devnull clipboard = XA_PRIMARY;
212 94bd4b6c 2006-03-23 devnull w = XGetSelectionOwner(xd, XA_PRIMARY);
213 94bd4b6c 2006-03-23 devnull if(w == drawable)
214 94bd4b6c 2006-03-23 devnull return snarf;
215 94bd4b6c 2006-03-23 devnull }
216 bb3b0aeb 2006-03-03 devnull
217 bb3b0aeb 2006-03-03 devnull /*
218 bb3b0aeb 2006-03-03 devnull * If not, is there a clipboard selection?
219 bb3b0aeb 2006-03-03 devnull */
220 bb3b0aeb 2006-03-03 devnull if(w == None && xclipboard != None){
221 bb3b0aeb 2006-03-03 devnull clipboard = xclipboard;
222 bb3b0aeb 2006-03-03 devnull w = XGetSelectionOwner(xd, xclipboard);
223 bb3b0aeb 2006-03-03 devnull if(w == drawable)
224 bb3b0aeb 2006-03-03 devnull return snarf;
225 bb3b0aeb 2006-03-03 devnull }
226 bb3b0aeb 2006-03-03 devnull
227 bb3b0aeb 2006-03-03 devnull /*
228 bb3b0aeb 2006-03-03 devnull * If not, give up.
229 bb3b0aeb 2006-03-03 devnull */
230 bb3b0aeb 2006-03-03 devnull if(w == None)
231 bb3b0aeb 2006-03-03 devnull return nil;
232 fa325e9b 2020-01-10 cross
233 bb3b0aeb 2006-03-03 devnull /*
234 bb3b0aeb 2006-03-03 devnull * We should be waiting for SelectionNotify here, but it might never
235 bb3b0aeb 2006-03-03 devnull * come, and we have no way to time out. Instead, we will clear
236 bb3b0aeb 2006-03-03 devnull * local property #1, request our buddy to fill it in for us, and poll
237 bb3b0aeb 2006-03-03 devnull * until he's done or we get tired of waiting.
238 bb3b0aeb 2006-03-03 devnull *
239 bb3b0aeb 2006-03-03 devnull * We should try to go for _x.utf8string instead of XA_STRING,
240 bb3b0aeb 2006-03-03 devnull * but that would add to the polling.
241 bb3b0aeb 2006-03-03 devnull */
242 bb3b0aeb 2006-03-03 devnull prop = 1;
243 bb3b0aeb 2006-03-03 devnull XChangeProperty(xd, drawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
244 bb3b0aeb 2006-03-03 devnull XConvertSelection(xd, clipboard, XA_STRING, prop, drawable, CurrentTime);
245 bb3b0aeb 2006-03-03 devnull XFlush(xd);
246 bb3b0aeb 2006-03-03 devnull lastlen = 0;
247 bb3b0aeb 2006-03-03 devnull for(i=0; i<10 || (lastlen!=0 && i<30); i++){
248 bb3b0aeb 2006-03-03 devnull sleep(100);
249 bb3b0aeb 2006-03-03 devnull XGetWindowProperty(xd, drawable, prop, 0, 0, 0, AnyPropertyType,
250 bb3b0aeb 2006-03-03 devnull &type, &fmt, &dummy, &len, &data);
251 bb3b0aeb 2006-03-03 devnull if(lastlen == len && len > 0)
252 bb3b0aeb 2006-03-03 devnull break;
253 bb3b0aeb 2006-03-03 devnull lastlen = len;
254 bb3b0aeb 2006-03-03 devnull }
255 bb3b0aeb 2006-03-03 devnull if(i == 10)
256 bb3b0aeb 2006-03-03 devnull return nil;
257 bb3b0aeb 2006-03-03 devnull /* get the property */
258 bb3b0aeb 2006-03-03 devnull data = nil;
259 fa325e9b 2020-01-10 cross XGetWindowProperty(xd, drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
260 bb3b0aeb 2006-03-03 devnull AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
261 bb3b0aeb 2006-03-03 devnull if(xdata == nil || (type != XA_STRING && type != xutf8string) || len == 0){
262 bb3b0aeb 2006-03-03 devnull if(xdata)
263 bb3b0aeb 2006-03-03 devnull XFree(xdata);
264 bb3b0aeb 2006-03-03 devnull return nil;
265 bb3b0aeb 2006-03-03 devnull }
266 bb3b0aeb 2006-03-03 devnull if(strlen((char*)xdata) >= SnarfSize){
267 bb3b0aeb 2006-03-03 devnull XFree(xdata);
268 bb3b0aeb 2006-03-03 devnull return nil;
269 bb3b0aeb 2006-03-03 devnull }
270 bb3b0aeb 2006-03-03 devnull strcpy(snarf, (char*)xdata);
271 bb3b0aeb 2006-03-03 devnull return snarf;
272 bb3b0aeb 2006-03-03 devnull }
273 bb3b0aeb 2006-03-03 devnull
274 bb3b0aeb 2006-03-03 devnull void
275 bb3b0aeb 2006-03-03 devnull xputsnarf(void)
276 bb3b0aeb 2006-03-03 devnull {
277 38612281 2006-04-02 devnull if(0) XSetSelectionOwner(xdisplay, XA_PRIMARY, drawable, CurrentTime);
278 bb3b0aeb 2006-03-03 devnull if(xclipboard != None)
279 bb3b0aeb 2006-03-03 devnull XSetSelectionOwner(xdisplay, xclipboard, drawable, CurrentTime);
280 bb3b0aeb 2006-03-03 devnull XFlush(xdisplay);
281 bb3b0aeb 2006-03-03 devnull }
282 bb3b0aeb 2006-03-03 devnull
283 bb3b0aeb 2006-03-03 devnull void
284 bb3b0aeb 2006-03-03 devnull appleputsnarf(void)
285 bb3b0aeb 2006-03-03 devnull {
286 bb3b0aeb 2006-03-03 devnull #ifdef __APPLE__
287 bb3b0aeb 2006-03-03 devnull CFDataRef cfdata;
288 bb3b0aeb 2006-03-03 devnull PasteboardSyncFlags flags;
289 bb3b0aeb 2006-03-03 devnull
290 bb3b0aeb 2006-03-03 devnull runesnprint(rsnarf, nelem(rsnarf), "%s", snarf);
291 bb3b0aeb 2006-03-03 devnull if(PasteboardClear(appleclip) != noErr){
292 bb3b0aeb 2006-03-03 devnull fprint(2, "apple pasteboard clear failed\n");
293 bb3b0aeb 2006-03-03 devnull return;
294 bb3b0aeb 2006-03-03 devnull }
295 bb3b0aeb 2006-03-03 devnull flags = PasteboardSynchronize(appleclip);
296 bb3b0aeb 2006-03-03 devnull if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
297 bb3b0aeb 2006-03-03 devnull fprint(2, "apple pasteboard cannot assert ownership\n");
298 bb3b0aeb 2006-03-03 devnull return;
299 bb3b0aeb 2006-03-03 devnull }
300 fa325e9b 2020-01-10 cross cfdata = CFDataCreate(kCFAllocatorDefault,
301 bb3b0aeb 2006-03-03 devnull (uchar*)rsnarf, runestrlen(rsnarf)*2);
302 bb3b0aeb 2006-03-03 devnull if(cfdata == nil){
303 bb3b0aeb 2006-03-03 devnull fprint(2, "apple pasteboard cfdatacreate failed\n");
304 bb3b0aeb 2006-03-03 devnull return;
305 bb3b0aeb 2006-03-03 devnull }
306 bb3b0aeb 2006-03-03 devnull if(PasteboardPutItemFlavor(appleclip, (PasteboardItemID)1,
307 bb3b0aeb 2006-03-03 devnull CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
308 bb3b0aeb 2006-03-03 devnull fprint(2, "apple pasteboard putitem failed\n");
309 bb3b0aeb 2006-03-03 devnull CFRelease(cfdata);
310 bb3b0aeb 2006-03-03 devnull return;
311 bb3b0aeb 2006-03-03 devnull }
312 bb3b0aeb 2006-03-03 devnull CFRelease(cfdata);
313 bb3b0aeb 2006-03-03 devnull #endif
314 bb3b0aeb 2006-03-03 devnull }