# HG changeset patch # User fl # Date 1286656688 10800 # Node ID 3be141f80d5ac30dd786dafc3769964c62d2e887 # Parent 96c41df08c947e720ad46ca4adadd5f4e59a0108 xclipboard support diff -r 96c41df08c94 -r 3be141f80d5a st.c --- a/st.c Tue Sep 21 16:04:13 2010 +0200 +++ b/st.c Sat Oct 09 17:38:08 2010 -0300 @@ -18,6 +18,7 @@ #include #include #include +#include #include #if defined(__linux) @@ -199,6 +200,8 @@ static void brelease(XEvent *); static void bpress(XEvent *); static void bmotion(XEvent *); +static void selsend(XEvent *); +static void selclear(XEvent *); static void (*handler[LASTEvent])(XEvent *) = { @@ -212,6 +215,8 @@ [MotionNotify] = bmotion, [ButtonPress] = bpress, [ButtonRelease] = brelease, + [SelectionRequest] = selsend, + [SelectionClear] = selclear, }; /* Globals */ @@ -277,15 +282,119 @@ return str; } -/* TODO: use X11 clipboard */ +/* use X11 clipboard */ static void selcopy(char *str) { + static Atom xa_clipboard = None; + free(sel.clip); sel.clip = str; + + /* own selection from now */ + XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime); + + /* Ctrl-V request support */ + if (xa_clipboard == None) /* avoid Xmu */ + xa_clipboard = XInternAtom(xw.dis, "CLIPBOARD", False); + XSetSelectionOwner(xw.dis, xa_clipboard, xw.win, CurrentTime); +} + +static Bool seltest(Display *dpy, XEvent *ev, char *arg) { + return (ev->type == SelectionNotify); } static void selpaste() { - if(sel.clip) + Window w; + Atom prop; + unsigned long nread, bytes_after, nitems; + unsigned char *data; + Atom actual_type; + int actual_fmt; + XEvent xev; + + w = XGetSelectionOwner(xw.dis, XA_PRIMARY); + if (w == None) + return; + /* st is the owner, directly write sel.clip */ + if (w == xw.win && sel.clip) { ttywrite(sel.clip, strlen(sel.clip)); + return; + } + + /* use X11 selection (Will be pasted when receiving + SelectionNotify event) */ + prop = XInternAtom(xw.dis, "VT_SELECTION", False); + XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, + prop, xw.win, CurrentTime); + + /* XXX: add timeout too if the target application + is not well educated */ + XIfEvent(xw.dis, &xev, seltest, NULL); + + w = xev.xselection.requestor; + prop = xev.xselection.property; + + nread = 0; + for(;;) { + if ((XGetWindowProperty(xw.dis, w, prop, nread/4, 4096, + True, AnyPropertyType, &actual_type, &actual_fmt, + &nitems, &bytes_after, &data) != Success) + || (actual_type != XA_STRING)) { + XFree (data); + break; + } + + ttywrite((char*) data, nitems); + + nread += nitems; + XFree (data); + } +} + +/* send selection to requestor */ +static void selsend(XEvent *xev) +{ + static Atom xa_targets = None; + XSelectionRequestEvent *rq = (XSelectionRequestEvent *) xev; + XEvent ev; + + if (xa_targets == None) + xa_targets = XInternAtom (xw.dis, "TARGETS", False); + + ev.xselection.type = SelectionNotify; + ev.xselection.property = None; + ev.xselection.display = rq->display; + ev.xselection.requestor = rq->requestor; + ev.xselection.selection = rq->selection; + ev.xselection.target = rq->target; + ev.xselection.time = rq->time; + + if (rq->target == xa_targets) { + unsigned int target_list[2]; + + /* indicate which are supported types */ + target_list[0] = xa_targets; + target_list[1] = XA_STRING; + + XChangeProperty (xw.dis, rq->requestor, rq->property, + xa_targets, 8 * sizeof(target_list[0]), PropModeReplace, + (unsigned char *) target_list, + sizeof(target_list) / sizeof(target_list[0])); + } else if (rq->target == XA_STRING) { + /* get selection buffer */ + + if (!sel.clip) + return; + + XChangeProperty (xw.dis, rq->requestor, rq->property, + XA_STRING, 8, PropModeReplace, + (unsigned char *)sel.clip, strlen(sel.clip)); + } + ev.xselection.property = rq->property; + XSendEvent (xw.dis, rq->requestor, False, 0, &ev); +} + +static void selclear(XEvent *e) { + /* TODO */ } /* TODO: doubleclick to select word */