| 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 | |
| +} | |
| + | |
| + |