- int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
- button = e->xbutton.button, state = e->xbutton.state,
- len;
- char buf[40];
- static int ox, oy;
-
- /* from urxvt */
- if (e->xbutton.type == MotionNotify) {
- if (x == ox && y == oy)
- return;
- if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
- return;
- /* MOUSE_MOTION: no reporting if no button is pressed */
- if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
- return;
-
- button = oldbutton + 32;
- ox = x;
- oy = y;
- } else {
- if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
- button = 3;
- } else {
- button -= Button1;
- if (button >= 3)
- button += 64 - 3;
- }
- if (e->xbutton.type == ButtonPress) {
- oldbutton = button;
- ox = x;
- oy = y;
- } else if (e->xbutton.type == ButtonRelease) {
- oldbutton = 3;
- /* MODE_MOUSEX10: no button release reporting */
- if (IS_SET(MODE_MOUSEX10))
- return;
- if (button == 64 || button == 65)
- return;
- }
- }
-
- if (!IS_SET(MODE_MOUSEX10)) {
- button += ((state & ShiftMask ) ? 4 : 0)
- + ((state & Mod4Mask ) ? 8 : 0)
- + ((state & ControlMask) ? 16 : 0);
- }
-
- if (IS_SET(MODE_MOUSESGR)) {
- len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
- button, x+1, y+1,
- e->xbutton.type == ButtonRelease ? 'm' : 'M');
- } else if (x < 223 && y < 223) {
- len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
- 32+button, 32+x+1, 32+y+1);
- } else {
- return;
- }
-
- ttywrite(buf, len);
-}
-
-void
-bpress(XEvent *e)
-{
- struct timespec now;
- MouseShortcut *ms;
-
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
- if (e->xbutton.button == ms->b
- && match(ms->mask, e->xbutton.state)) {
- ttysend(ms->s, strlen(ms->s));
- return;
- }
- }
-
- if (e->xbutton.button == Button1) {
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- /* Clear previous selection, logically and visually. */
- selclear(NULL);
- sel.mode = SEL_EMPTY;
- sel.type = SEL_REGULAR;
- sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
- sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
-
- /*
- * If the user clicks below predefined timeouts specific
- * snapping behaviour is exposed.
- */
- if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
- sel.snap = SNAP_LINE;
- } else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
- sel.snap = SNAP_WORD;
- } else {
- sel.snap = 0;
- }
- selnormalize();
-
- if (sel.snap != 0)
- sel.mode = SEL_READY;
- tsetdirt(sel.nb.y, sel.ne.y);
- sel.tclick2 = sel.tclick1;
- sel.tclick1 = now;
- }
-}
-
-char *
-getsel(void)
-{
- char *str, *ptr;
- int y, bufsize, lastx, linelen;
- Glyph *gp, *last;
-
- if (sel.ob.x == -1)
- return NULL;
-
- bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
- ptr = str = xmalloc(bufsize);
-
- /* append every set & selected glyph to the selection */
- for (y = sel.nb.y; y <= sel.ne.y; y++) {
- if ((linelen = tlinelen(y)) == 0) {
- *ptr++ = '\n';
- continue;
- }
-
- if (sel.type == SEL_RECTANGULAR) {
- gp = &term.line[y][sel.nb.x];
- lastx = sel.ne.x;
- } else {
- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
- lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
- }
- last = &term.line[y][MIN(lastx, linelen-1)];
- while (last >= gp && last->u == ' ')
- --last;
-
- for ( ; gp <= last; ++gp) {
- if (gp->mode & ATTR_WDUMMY)
- continue;
-
- ptr += utf8encode(gp->u, ptr);
- }
-
- /*
- * Copy and pasting of line endings is inconsistent
- * in the inconsistent terminal and GUI world.
- * The best solution seems like to produce '\n' when
- * something is copied from st and convert '\n' to
- * '\r', when something to be pasted is received by
- * st.
- * FIXME: Fix the computer world.
- */
- if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
- *ptr++ = '\n';
- }
- *ptr = 0;
- return str;
-}
-
-void
-selcopy(Time t)
-{
- xsetsel(getsel(), t);
-}
-
-void
-propnotify(XEvent *e)
-{
- XPropertyEvent *xpev;
- Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-
- xpev = &e->xproperty;
- if (xpev->state == PropertyNewValue &&
- (xpev->atom == XA_PRIMARY ||
- xpev->atom == clipboard)) {
- selnotify(e);
- }
-}
-
-void
-selnotify(XEvent *e)
-{
- ulong nitems, ofs, rem;
- int format;
- uchar *data, *last, *repl;
- Atom type, incratom, property;
-
- incratom = XInternAtom(xw.dpy, "INCR", 0);
-
- ofs = 0;
- if (e->type == SelectionNotify) {
- property = e->xselection.property;
- } else if(e->type == PropertyNotify) {
- property = e->xproperty.atom;
- } else {
- return;
- }
- if (property == None)
- return;
-
- do {
- if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
- BUFSIZ/4, False, AnyPropertyType,
- &type, &format, &nitems, &rem,
- &data)) {
- fprintf(stderr, "Clipboard allocation failed\n");
- return;
- }
-
- if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
- /*
- * If there is some PropertyNotify with no data, then
- * this is the signal of the selection owner that all
- * data has been transferred. We won't need to receive
- * PropertyNotify events anymore.
- */
- MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
- &xw.attrs);
- }
-
- if (type == incratom) {
- /*
- * Activate the PropertyNotify events so we receive
- * when the selection owner does send us the next
- * chunk of data.
- */
- MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
- &xw.attrs);
-
- /*
- * Deleting the property is the transfer start signal.
- */
- XDeleteProperty(xw.dpy, xw.win, (int)property);
- continue;
- }
-
- /*
- * As seen in getsel:
- * Line endings are inconsistent in the terminal and GUI world
- * copy and pasting. When receiving some selection data,
- * replace all '\n' with '\r'.
- * FIXME: Fix the computer world.
- */
- repl = data;
- last = data + nitems * format / 8;
- while ((repl = memchr(repl, '\n', last - repl))) {
- *repl++ = '\r';
- }
-
- if (IS_SET(MODE_BRCKTPASTE) && ofs == 0)
- ttywrite("\033[200~", 6);
- ttysend((char *)data, nitems * format / 8);
- if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
- ttywrite("\033[201~", 6);
- XFree(data);
- /* number of 32-bit chunks returned */
- ofs += nitems * format / 32;
- } while (rem > 0);
-
- /*
- * Deleting the property again tells the selection owner to send the
- * next data chunk in the property.
- */
- XDeleteProperty(xw.dpy, xw.win, (int)property);
-}
-
-void
-selpaste(const Arg *dummy)
-{
- XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
- xw.win, CurrentTime);
-}
-
-void
-clipcopy(const Arg *dummy)
-{
- Atom clipboard;
-
- if (sel.clipboard != NULL)
- free(sel.clipboard);
-
- if (sel.primary != NULL) {
- sel.clipboard = xstrdup(sel.primary);
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
- }
-}
-
-void
-clippaste(const Arg *dummy)
-{
- Atom clipboard;
-
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard,
- xw.win, CurrentTime);
-}
-
-void
-selclear(XEvent *e)
-{
- if (sel.ob.x == -1)
- return;
- sel.mode = SEL_IDLE;
- sel.ob.x = -1;
- tsetdirt(sel.nb.y, sel.ne.y);
-}
-
-void
-selrequest(XEvent *e)
-{
- XSelectionRequestEvent *xsre;
- XSelectionEvent xev;
- Atom xa_targets, string, clipboard;
- char *seltext;
-
- xsre = (XSelectionRequestEvent *) e;
- xev.type = SelectionNotify;
- xev.requestor = xsre->requestor;
- xev.selection = xsre->selection;
- xev.target = xsre->target;
- xev.time = xsre->time;
- if (xsre->property == None)
- xsre->property = xsre->target;
-
- /* reject */
- xev.property = None;
-
- xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
- if (xsre->target == xa_targets) {
- /* respond with the supported type */
- string = sel.xtarget;
- XChangeProperty(xsre->display, xsre->requestor, xsre->property,
- XA_ATOM, 32, PropModeReplace,
- (uchar *) &string, 1);
- xev.property = xsre->property;
- } else if (xsre->target == sel.xtarget || xsre->target == XA_STRING) {
- /*
- * xith XA_STRING non ascii characters may be incorrect in the
- * requestor. It is not our problem, use utf8.
- */
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- if (xsre->selection == XA_PRIMARY) {
- seltext = sel.primary;
- } else if (xsre->selection == clipboard) {
- seltext = sel.clipboard;
- } else {
- fprintf(stderr,
- "Unhandled clipboard selection 0x%lx\n",
- xsre->selection);
- return;
- }
- if (seltext != NULL) {
- XChangeProperty(xsre->display, xsre->requestor,
- xsre->property, xsre->target,
- 8, PropModeReplace,
- (uchar *)seltext, strlen(seltext));
- xev.property = xsre->property;
- }
- }
-
- /* all done, send a notification to the listener */
- if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
- fprintf(stderr, "Error sending SelectionNotify event\n");
-}
-
-void
-xsetsel(char *str, Time t)
-{
- free(sel.primary);
- sel.primary = str;
-
- XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
- if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
- selclear(0);
-}
-
-void
-brelease(XEvent *e)
-{
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- if (e->xbutton.button == Button2) {
- selpaste(NULL);
- } else if (e->xbutton.button == Button1) {
- if (sel.mode == SEL_READY) {
- getbuttoninfo(e);
- selcopy(e->xbutton.time);
- } else
- selclear(NULL);
- sel.mode = SEL_IDLE;
- tsetdirt(sel.nb.y, sel.ne.y);
- }
-}
-
-void
-bmotion(XEvent *e)
-{
- int oldey, oldex, oldsby, oldsey;
-
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- if (!sel.mode)
- return;
-
- sel.mode = SEL_READY;
- oldey = sel.oe.y;
- oldex = sel.oe.x;
- oldsby = sel.nb.y;
- oldsey = sel.ne.y;
- getbuttoninfo(e);
-
- if (oldey != sel.oe.y || oldex != sel.oe.x)
- tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
-}
-
-void
-die(const char *errstr, ...)
-{
- va_list ap;