X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=x.c;h=c5826cf813f33f2d061c737a3a40abfb0c0ddc8b;hb=05c66cb37d9ff278a3e0c45682c4b5e7945deb42;hp=cb8c351d54e5a89b6fae0dcedccd6d5669a4b5b2;hpb=65976c1a29f2945c3cfb6af74cd6440cf193021d;p=st.git diff --git a/x.c b/x.c index cb8c351..c5826cf 100644 --- a/x.c +++ b/x.c @@ -20,9 +20,38 @@ static char *argv0; #include "st.h" #include "win.h" +/* types used in config.h */ +typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + uint b; + uint mask; + char *s; +} MouseShortcut; + +typedef struct { + KeySym k; + uint mask; + char *s; + /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ +} Key; + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) + /* function definitions used in config.h */ static void clipcopy(const Arg *); static void clippaste(const Arg *); +static void numlock(const Arg *); static void selpaste(const Arg *); static void zoom(const Arg *); static void zoomabs(const Arg *); @@ -31,19 +60,12 @@ static void zoomreset(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" -/* config.h array lengths */ -size_t colornamelen = LEN(colorname); -size_t mshortcutslen = LEN(mshortcuts); -size_t shortcutslen = LEN(shortcuts); -size_t selmaskslen = LEN(selmasks); -size_t keyslen = LEN(key); -size_t mappedkeyslen = LEN(mappedkeys); - /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 /* macros */ +#define IS_SET(flag) ((win.mode & (flag)) != 0) #define TRUERED(x) (((x) & 0xff0000) >> 8) #define TRUEGREEN(x) (((x) & 0xff00)) #define TRUEBLUE(x) (((x) & 0xff) << 8) @@ -73,6 +95,9 @@ typedef struct { typedef struct { Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; } XSelection; /* Font structure */ @@ -132,8 +157,8 @@ static void propnotify(XEvent *); static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); -static void selcopy(Time); -static void getbuttoninfo(XEvent *); +static void setsel(char *, Time); +static void mousesel(XEvent *, int); static void mousereport(XEvent *); static char *kmap(KeySym, uint); static int match(uint, uint); @@ -171,11 +196,7 @@ static void (*handler[LASTEvent])(XEvent *) = { static DC dc; static XWindow xw; static XSelection xsel; - -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; +static TermWindow win; /* Font Ring Cache */ enum { @@ -210,19 +231,39 @@ static char *opt_title = NULL; void clipcopy(const Arg *dummy) { - xclipcopy(); + Atom clipboard; + + if (xsel.clipboard != NULL) + free(xsel.clipboard); + + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } } void clippaste(const Arg *dummy) { - xclippaste(); + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); } void selpaste(const Arg *dummy) { - xselpaste(); + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; } void @@ -240,7 +281,6 @@ zoomabs(const Arg *arg) xunloadfonts(); xloadfonts(usedfont, arg->f); cresize(0, 0); - ttyresize(win.tw, win.th); redraw(); xhints(); } @@ -275,24 +315,20 @@ y2row(int y) } void -getbuttoninfo(XEvent *e) +mousesel(XEvent *e, int done) { - int type; + int type, seltype = SEL_REGULAR; uint state = e->xbutton.state & ~(Button1Mask | forceselmod); - sel.alt = IS_SET(MODE_ALTSCREEN); - - sel.oe.x = x2col(e->xbutton.x); - sel.oe.y = y2row(e->xbutton.y); - selnormalize(); - - sel.type = SEL_REGULAR; - for (type = 1; type < selmaskslen; ++type) { + for (type = 1; type < LEN(selmasks); ++type) { if (match(selmasks[type], state)) { - sel.type = type; + seltype = type; break; } } + selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); } void @@ -356,7 +392,7 @@ mousereport(XEvent *e) return; } - ttywrite(buf, len); + ttywrite(buf, len, 0); } void @@ -364,57 +400,41 @@ bpress(XEvent *e) { struct timespec now; MouseShortcut *ms; + int snap; if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); return; } - for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) { + 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)); + ttywrite(ms->s, strlen(ms->s), 1); 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; + clock_gettime(CLOCK_MONOTONIC, &now); + if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { + snap = SNAP_LINE; + } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { + snap = SNAP_WORD; } else { - sel.snap = 0; + snap = 0; } - selnormalize(); + xsel.tclick2 = xsel.tclick1; + xsel.tclick1 = now; - if (sel.snap != 0) - sel.mode = SEL_READY; - tsetdirt(sel.nb.y, sel.ne.y); - sel.tclick2 = sel.tclick1; - sel.tclick1 = now; + selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap); } } -void -selcopy(Time t) -{ - xsetsel(getsel(), t); -} - void propnotify(XEvent *e) { @@ -502,10 +522,10 @@ selnotify(XEvent *e) } if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) - ttywrite("\033[200~", 6); - ttysend((char *)data, nitems * format / 8); + ttywrite("\033[200~", 6, 0); + ttywrite((char *)data, nitems * format / 8, 1); if (IS_SET(MODE_BRCKTPASTE) && rem == 0) - ttywrite("\033[201~", 6); + ttywrite("\033[201~", 6, 0); XFree(data); /* number of 32-bit chunks returned */ ofs += nitems * format / 32; @@ -518,36 +538,10 @@ selnotify(XEvent *e) XDeleteProperty(xw.dpy, xw.win, (int)property); } -void -xselpaste(void) -{ - XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, - xw.win, CurrentTime); -} - void xclipcopy(void) { - 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 -xclippaste(void) -{ - Atom clipboard; - - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, - xw.win, CurrentTime); + clipcopy(NULL); } void @@ -591,9 +585,9 @@ selrequest(XEvent *e) */ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); if (xsre->selection == XA_PRIMARY) { - seltext = sel.primary; + seltext = xsel.primary; } else if (xsre->selection == clipboard) { - seltext = sel.clipboard; + seltext = xsel.clipboard; } else { fprintf(stderr, "Unhandled clipboard selection 0x%lx\n", @@ -615,16 +609,22 @@ selrequest(XEvent *e) } void -xsetsel(char *str, Time t) +setsel(char *str, Time t) { - free(sel.primary); - sel.primary = str; + free(xsel.primary); + xsel.primary = str; XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear_(NULL); } +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); +} + void brelease(XEvent *e) { @@ -633,41 +633,21 @@ brelease(XEvent *e) return; } - if (e->xbutton.button == Button2) { - xselpaste(); - } 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); - } + if (e->xbutton.button == Button2) + selpaste(NULL); + else if (e->xbutton.button == Button1) + mousesel(e, 1); } 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)); + mousesel(e, 0); } void @@ -685,6 +665,7 @@ cresize(int width, int height) tresize(col, row); xresize(col, row); + ttyresize(win.tw, win.th); } void @@ -740,7 +721,7 @@ xloadcols(void) static int loaded; Color *cp; - dc.collen = MAX(colornamelen, 256); + dc.collen = MAX(LEN(colorname), 256); dc.col = xmalloc(dc.collen * sizeof(Color)); if (loaded) { @@ -1112,11 +1093,16 @@ xinit(void) XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, PropModeReplace, (uchar *)&thispid, 1); + win.mode = MODE_NUMLOCK; resettitle(); XMapWindow(xw.dpy, xw.win); xhints(); XSync(xw.dpy, False); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); + xsel.primary = NULL; + xsel.clipboard = NULL; xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); if (xsel.xtarget == None) xsel.xtarget = XA_STRING; @@ -1337,14 +1323,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i fg = &revfg; } - if (base.mode & ATTR_REVERSE) { temp = fg; fg = bg; bg = temp; } - if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK) + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) fg = bg; if (base.mode & ATTR_INVISIBLE) @@ -1408,7 +1393,6 @@ xdrawcursor(void) static int oldx = 0, oldy = 0; int curx; Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; - int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); Color drawcol; LIMIT(oldx, 0, term.col-1); @@ -1424,7 +1408,7 @@ xdrawcursor(void) /* remove the old cursor */ og = term.line[oldy][oldx]; - if (ena_sel && selected(oldx, oldy)) + if (selected(oldx, oldy)) og.mode ^= ATTR_REVERSE; xdrawglyph(og, oldx, oldy); @@ -1438,7 +1422,7 @@ xdrawcursor(void) if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; g.bg = defaultfg; - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultcs]; g.fg = defaultrcs; } else { @@ -1446,7 +1430,7 @@ xdrawcursor(void) g.fg = defaultcs; } } else { - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; @@ -1459,7 +1443,7 @@ xdrawcursor(void) return; /* draw the new one */ - if (win.state & WIN_FOCUSED) { + if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { case 7: /* st extension: snowman */ utf8decode("☃", &g.u, UTF_SIZ); @@ -1545,9 +1529,8 @@ drawregion(int x1, int y1, int x2, int y2) int i, x, y, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs; - int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - if (!(win.state & WIN_VISIBLE)) + if (!(IS_SET(MODE_VISIBLE))) return; for (y = y1; y < y2; y++) { @@ -1564,7 +1547,7 @@ drawregion(int x1, int y1, int x2, int y2) new = term.line[y][x]; if (new.mode == ATTR_WDUMMY) continue; - if (ena_sel && selected(x, y)) + if (selected(x, y)) new.mode ^= ATTR_REVERSE; if (i > 0 && ATTRCMP(base, new)) { xdrawglyphfontspecs(specs, base, i, ox, y); @@ -1595,13 +1578,13 @@ visibility(XEvent *ev) { XVisibilityEvent *e = &ev->xvisibility; - MODBIT(win.state, e->state != VisibilityFullyObscured, WIN_VISIBLE); + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); } void unmap(XEvent *ev) { - win.state &= ~WIN_VISIBLE; + win.mode &= ~MODE_VISIBLE; } void @@ -1611,6 +1594,25 @@ xsetpointermotion(int set) XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); } +void +xsetmode(int set, unsigned int flags) +{ + int mode = win.mode; + MODBIT(win.mode, set, flags); + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); +} + +int +xsetcursor(int cursor) +{ + DEFAULT(cursor, 1); + if (!BETWEEN(cursor, 0, 6)) + return 1; + win.cursor = cursor; + return 0; +} + void xseturgency(int add) { @@ -1624,7 +1626,7 @@ xseturgency(int add) void xbell(void) { - if (!(win.state & WIN_FOCUSED)) + if (!(IS_SET(MODE_FOCUSED))) xseturgency(1); if (bellvolume) XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); @@ -1640,15 +1642,15 @@ focus(XEvent *ev) if (ev->type == FocusIn) { XSetICFocus(xw.xic); - win.state |= WIN_FOCUSED; + win.mode |= MODE_FOCUSED; xseturgency(0); if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3); + ttywrite("\033[I", 3, 0); } else { XUnsetICFocus(xw.xic); - win.state &= ~WIN_FOCUSED; + win.mode &= ~MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3); + ttywrite("\033[O", 3, 0); } } @@ -1665,16 +1667,16 @@ kmap(KeySym k, uint state) int i; /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < mappedkeyslen; i++) { + for (i = 0; i < LEN(mappedkeys); i++) { if (mappedkeys[i] == k) break; } - if (i == mappedkeyslen) { + if (i == LEN(mappedkeys)) { if ((k & 0xFFFF) < 0xFD00) return NULL; } - for (kp = key; kp < key + keyslen; kp++) { + for (kp = key; kp < key + LEN(key); kp++) { if (kp->k != k) continue; @@ -1683,15 +1685,12 @@ kmap(KeySym k, uint state) if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) continue; - if (term.numlock && kp->appkey == 2) + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) continue; if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) continue; - if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0) - continue; - return kp->s; } @@ -1714,7 +1713,7 @@ kpress(XEvent *ev) len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); /* 1. shortcuts */ - for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, e->state)) { bp->func(&(bp->arg)); return; @@ -1723,7 +1722,7 @@ kpress(XEvent *ev) /* 2. custom keys from config.h */ if ((customkey = kmap(ksym, e->state))) { - ttysend(customkey, strlen(customkey)); + ttywrite(customkey, strlen(customkey), 1); return; } @@ -1742,7 +1741,7 @@ kpress(XEvent *ev) len = 2; } } - ttysend(buf, len); + ttywrite(buf, len, 1); } @@ -1755,10 +1754,10 @@ cmessage(XEvent *e) */ if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { - win.state |= WIN_FOCUSED; + win.mode |= MODE_FOCUSED; xseturgency(0); } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { - win.state &= ~WIN_FOCUSED; + win.mode &= ~MODE_FOCUSED; } } else if (e->xclient.data.l[0] == xw.wmdeletewin) { /* Send SIGHUP to shell */ @@ -1774,7 +1773,6 @@ resize(XEvent *e) return; cresize(e->xconfigure.width, e->xconfigure.height); - ttyresize(win.tw, win.th); } void @@ -1803,9 +1801,8 @@ run(void) } } while (ev.type != MapNotify); - cresize(w, h); ttynew(opt_line, opt_io, opt_cmd); - ttyresize(win.tw, win.th); + cresize(w, h); clock_gettime(CLOCK_MONOTONIC, &last); lastblink = last; @@ -1825,7 +1822,7 @@ run(void) if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); if (!blinkset) - MODBIT(term.mode, 0, MODE_BLINK); + MODBIT(win.mode, 0, MODE_BLINK); } } @@ -1840,7 +1837,7 @@ run(void) dodraw = 0; if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { tsetdirtattr(ATTR_BLINK); - term.mode ^= MODE_BLINK; + win.mode ^= MODE_BLINK; lastblink = now; dodraw = 1; }