tmove snarfer to use X includes - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit bb3b0aeb9c29e8dc21d8e48390ae4ce410563e3c | |
parent 5db07ba9422804c9de1e8fbda5486722cb731e03 | |
Author: rsc <devnull@localhost> | |
Date: Fri, 3 Mar 2006 01:42:25 +0000 | |
move snarfer to use X includes | |
Diffstat: | |
A src/cmd/snarfer/mkfile | 9 +++++++++ | |
A src/cmd/snarfer/snarfer.c | 310 +++++++++++++++++++++++++++++… | |
2 files changed, 319 insertions(+), 0 deletions(-) | |
--- | |
diff --git a/src/cmd/snarfer/mkfile b/src/cmd/snarfer/mkfile | |
t@@ -0,0 +1,9 @@ | |
+<$PLAN9/src/mkhdr | |
+ | |
+TARG=snarfer | |
+OFILES= | |
+HFILES= | |
+ | |
+<|sh ../../libdraw/mkwsysrules.sh | |
+<$PLAN9/src/mkmany | |
+ | |
diff --git a/src/cmd/snarfer/snarfer.c b/src/cmd/snarfer/snarfer.c | |
t@@ -0,0 +1,310 @@ | |
+/* | |
+ * This program is only intended for OS X, but the | |
+ * ifdef __APPLE__ below lets us build it on all systems. | |
+ * On non-OS X systems, you can use it to hold the snarf | |
+ * buffer around after a program exits. | |
+ */ | |
+ | |
+#include <u.h> | |
+#define Colormap XColormap | |
+#define Cursor XCursor | |
+#define Display XDisplay | |
+#define Drawable XDrawable | |
+#define Font XFont | |
+#define GC XGC | |
+#define Point XPoint | |
+#define Rectangle XRectangle | |
+#define Screen XScreen | |
+#define Visual XVisual | |
+#define Window XWindow | |
+#include <X11/Xlib.h> | |
+#include <X11/Xatom.h> | |
+#include <X11/Xutil.h> | |
+#include <X11/keysym.h> | |
+#include <X11/IntrinsicP.h> | |
+#include <X11/StringDefs.h> | |
+#undef Colormap | |
+#undef Cursor | |
+#undef Display | |
+#undef Drawable | |
+#undef Font | |
+#undef GC | |
+#undef Point | |
+#undef Rectangle | |
+#undef Screen | |
+#undef Visual | |
+#undef Window | |
+#ifdef __APPLE__ | |
+#define APPLESNARF | |
+#define Boolean AppleBoolean | |
+#define Rect AppleRect | |
+#define EventMask AppleEventMask | |
+#define Point ApplePoint | |
+#define Cursor AppleCursor | |
+#include <Carbon/Carbon.h> | |
+AUTOFRAMEWORK(Carbon) | |
+#undef Boolean | |
+#undef Rect | |
+#undef EventMask | |
+#undef Point | |
+#undef Cursor | |
+#endif | |
+#include <libc.h> | |
+#undef time | |
+AUTOLIB(draw) /* to cause link of X11 */ | |
+ | |
+enum { | |
+ SnarfSize = 65536, | |
+}; | |
+char snarf[3*SnarfSize+1]; | |
+Rune rsnarf[SnarfSize+1]; | |
+XDisplay *xdisplay; | |
+XWindow drawable; | |
+Atom xclipboard; | |
+Atom xutf8string; | |
+Atom xtargets; | |
+Atom xtext; | |
+Atom xcompoundtext; | |
+ | |
+void xselectionrequest(XEvent*); | |
+char *xgetsnarf(void); | |
+void appleputsnarf(void); | |
+void xputsnarf(void); | |
+ | |
+int verbose; | |
+ | |
+#ifdef __APPLE__ | |
+PasteboardRef appleclip; | |
+#endif | |
+ | |
+void | |
+usage(void) | |
+{ | |
+ fprint(2, "usage: snarfer [-v]\n"); | |
+ exits("usage"); | |
+} | |
+ | |
+void | |
+main(int argc, char **argv) | |
+{ | |
+ XEvent xevent; | |
+ | |
+ ARGBEGIN{ | |
+ default: | |
+ usage(); | |
+ case 'v': | |
+ verbose = 1; | |
+ break; | |
+ }ARGEND | |
+ | |
+ if((xdisplay = XOpenDisplay(nil)) == nil) | |
+ sysfatal("XOpenDisplay: %r"); | |
+ drawable = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay), | |
+ 0, 0, 1, 1, 0, 0, | |
+ InputOutput, DefaultVisual(xdisplay, DefaultScreen(xdisplay)), | |
+ 0, 0); | |
+ if(drawable == None) | |
+ sysfatal("XCreateWindow: %r"); | |
+ XFlush(xdisplay); | |
+ | |
+ xclipboard = XInternAtom(xdisplay, "CLIPBOARD", False); | |
+ xutf8string = XInternAtom(xdisplay, "UTF8_STRING", False); | |
+ xtargets = XInternAtom(xdisplay, "TARGETS", False); | |
+ xtext = XInternAtom(xdisplay, "TEXT", False); | |
+ xcompoundtext = XInternAtom(xdisplay, "COMPOUND_TEXT", False); | |
+ | |
+#ifdef __APPLE__ | |
+ if(PasteboardCreate(kPasteboardClipboard, &appleclip) != noErr) | |
+ sysfatal("pasteboard create failed"); | |
+#endif | |
+ | |
+ xgetsnarf(); | |
+ appleputsnarf(); | |
+ xputsnarf(); | |
+ | |
+ for(;;){ | |
+ XNextEvent(xdisplay, &xevent); | |
+ switch(xevent.type){ | |
+ case DestroyNotify: | |
+ exits(0); | |
+ case SelectionClear: | |
+ xgetsnarf(); | |
+ appleputsnarf(); | |
+ xputsnarf(); | |
+ if(verbose) | |
+ print("snarf{%s}\n", snarf); | |
+ break; | |
+ case SelectionRequest: | |
+ xselectionrequest(&xevent); | |
+ break; | |
+ } | |
+ } | |
+} | |
+ | |
+void | |
+xselectionrequest(XEvent *e) | |
+{ | |
+ char *name; | |
+ Atom a[4]; | |
+ XEvent r; | |
+ XSelectionRequestEvent *xe; | |
+ XDisplay *xd; | |
+ | |
+ xd = xdisplay; | |
+ | |
+ memset(&r, 0, sizeof r); | |
+ xe = (XSelectionRequestEvent*)e; | |
+if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n", | |
+ xe->target, xe->requestor, xe->property, xe->selection); | |
+ r.xselection.property = xe->property; | |
+ if(xe->target == xtargets){ | |
+ a[0] = XA_STRING; | |
+ a[1] = xutf8string; | |
+ a[2] = xtext; | |
+ a[3] = xcompoundtext; | |
+ | |
+ XChangeProperty(xd, xe->requestor, xe->property, xe->target, | |
+ 8, PropModeReplace, (uchar*)a, sizeof a); | |
+ }else if(xe->target == XA_STRING || xe->target == xutf8string || xe->t… | |
+ /* if the target is STRING we're supposed to reply with Latin1… | |
+ XChangeProperty(xd, xe->requestor, xe->property, xe->target, | |
+ 8, PropModeReplace, (uchar*)snarf, strlen(snarf)); | |
+ }else{ | |
+ name = XGetAtomName(xd, xe->target); | |
+ if(strcmp(name, "TIMESTAMP") != 0) | |
+ fprint(2, "%s: cannot handle selection request for '%s… | |
+ r.xselection.property = None; | |
+ } | |
+ | |
+ r.xselection.display = xe->display; | |
+ /* r.xselection.property filled above */ | |
+ r.xselection.target = xe->target; | |
+ r.xselection.type = SelectionNotify; | |
+ r.xselection.requestor = xe->requestor; | |
+ r.xselection.time = xe->time; | |
+ r.xselection.send_event = True; | |
+ r.xselection.selection = xe->selection; | |
+ XSendEvent(xd, xe->requestor, False, 0, &r); | |
+ XFlush(xd); | |
+} | |
+ | |
+char* | |
+xgetsnarf(void) | |
+{ | |
+ uchar *data, *xdata; | |
+ Atom clipboard, type, prop; | |
+ ulong len, lastlen, dummy; | |
+ int fmt, i; | |
+ XWindow w; | |
+ XDisplay *xd; | |
+ | |
+ xd = xdisplay; | |
+ | |
+ /* | |
+ * Is there a primary selection (highlighted text in an xterm)? | |
+ */ | |
+ clipboard = XA_PRIMARY; | |
+ w = XGetSelectionOwner(xd, XA_PRIMARY); | |
+ if(w == drawable) | |
+ return snarf; | |
+ | |
+ /* | |
+ * If not, is there a clipboard selection? | |
+ */ | |
+ if(w == None && xclipboard != None){ | |
+ clipboard = xclipboard; | |
+ w = XGetSelectionOwner(xd, xclipboard); | |
+ if(w == drawable) | |
+ return snarf; | |
+ } | |
+ | |
+ /* | |
+ * If not, give up. | |
+ */ | |
+ if(w == None) | |
+ return nil; | |
+ | |
+ /* | |
+ * We should be waiting for SelectionNotify here, but it might never | |
+ * come, and we have no way to time out. Instead, we will clear | |
+ * local property #1, request our buddy to fill it in for us, and poll | |
+ * until he's done or we get tired of waiting. | |
+ * | |
+ * We should try to go for _x.utf8string instead of XA_STRING, | |
+ * but that would add to the polling. | |
+ */ | |
+ prop = 1; | |
+ XChangeProperty(xd, drawable, prop, XA_STRING, 8, PropModeReplace, (uc… | |
+ XConvertSelection(xd, clipboard, XA_STRING, prop, drawable, CurrentTim… | |
+ XFlush(xd); | |
+ lastlen = 0; | |
+ for(i=0; i<10 || (lastlen!=0 && i<30); i++){ | |
+ sleep(100); | |
+ XGetWindowProperty(xd, drawable, prop, 0, 0, 0, AnyPropertyTyp… | |
+ &type, &fmt, &dummy, &len, &data); | |
+ if(lastlen == len && len > 0) | |
+ break; | |
+ lastlen = len; | |
+ } | |
+ if(i == 10) | |
+ return nil; | |
+ /* get the property */ | |
+ data = nil; | |
+ XGetWindowProperty(xd, drawable, prop, 0, SnarfSize/sizeof(ulong), 0, | |
+ AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); | |
+ if(xdata == nil || (type != XA_STRING && type != xutf8string) || len =… | |
+ if(xdata) | |
+ XFree(xdata); | |
+ return nil; | |
+ } | |
+ if(strlen((char*)xdata) >= SnarfSize){ | |
+ XFree(xdata); | |
+ return nil; | |
+ } | |
+ strcpy(snarf, (char*)xdata); | |
+ return snarf; | |
+} | |
+ | |
+void | |
+xputsnarf(void) | |
+{ | |
+ XSetSelectionOwner(xdisplay, XA_PRIMARY, drawable, CurrentTime); | |
+ if(xclipboard != None) | |
+ XSetSelectionOwner(xdisplay, xclipboard, drawable, CurrentTime… | |
+ XFlush(xdisplay); | |
+} | |
+ | |
+void | |
+appleputsnarf(void) | |
+{ | |
+#ifdef __APPLE__ | |
+ CFDataRef cfdata; | |
+ PasteboardSyncFlags flags; | |
+ | |
+ runesnprint(rsnarf, nelem(rsnarf), "%s", snarf); | |
+ if(PasteboardClear(appleclip) != noErr){ | |
+ fprint(2, "apple pasteboard clear failed\n"); | |
+ return; | |
+ } | |
+ flags = PasteboardSynchronize(appleclip); | |
+ if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ | |
+ fprint(2, "apple pasteboard cannot assert ownership\n"); | |
+ return; | |
+ } | |
+ cfdata = CFDataCreate(kCFAllocatorDefault, | |
+ (uchar*)rsnarf, runestrlen(rsnarf)*2); | |
+ if(cfdata == nil){ | |
+ fprint(2, "apple pasteboard cfdatacreate failed\n"); | |
+ return; | |
+ } | |
+ if(PasteboardPutItemFlavor(appleclip, (PasteboardItemID)1, | |
+ CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){ | |
+ fprint(2, "apple pasteboard putitem failed\n"); | |
+ CFRelease(cfdata); | |
+ return; | |
+ } | |
+ CFRelease(cfdata); | |
+#endif | |
+} | |
+ | |
+ |