-
-void
-draw(void) {
- drawregion(0, 0, term.col, term.row);
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
- xw.h, 0, 0);
- XSetForeground(xw.dpy, dc.gc,
- dc.col[IS_SET(MODE_REVERSE)?
- defaultfg : defaultbg].pixel);
-}
-
-void
-drawregion(int x1, int y1, int x2, int y2) {
- int i, x, y, ox, numspecs;
- Glyph base, new;
- XftGlyphFontSpec* specs;
- bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-
- if(!(xw.state & WIN_VISIBLE))
- return;
-
- for(y = y1; y < y2; y++) {
- if(!term.dirty[y])
- continue;
-
- xtermclear(0, y, term.col, y);
- term.dirty[y] = 0;
-
- specs = term.specbuf;
- numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
-
- i = ox = 0;
- for(x = x1; x < x2 && i < numspecs; x++) {
- new = term.line[y][x];
- if(new.mode == ATTR_WDUMMY)
- continue;
- if(ena_sel && selected(x, y))
- new.mode ^= ATTR_REVERSE;
- if(i > 0 && ATTRCMP(base, new)) {
- xdrawglyphfontspecs(specs, base, i, ox, y);
- specs += i;
- numspecs -= i;
- i = 0;
- }
- if(i == 0) {
- ox = x;
- base = new;
- }
- i++;
- }
- if(i > 0)
- xdrawglyphfontspecs(specs, base, i, ox, y);
- }
- xdrawcursor();
-}
-
-void
-expose(XEvent *ev) {
- redraw();
-}
-
-void
-visibility(XEvent *ev) {
- XVisibilityEvent *e = &ev->xvisibility;
-
- MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
-}
-
-void
-unmap(XEvent *ev) {
- xw.state &= ~WIN_VISIBLE;
-}
-
-void
-xsetpointermotion(int set) {
- MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
-}
-
-void
-xseturgency(int add) {
- XWMHints *h = XGetWMHints(xw.dpy, xw.win);
-
- MODBIT(h->flags, add, XUrgencyHint);
- XSetWMHints(xw.dpy, xw.win, h);
- XFree(h);
-}
-
-void
-focus(XEvent *ev) {
- XFocusChangeEvent *e = &ev->xfocus;
-
- if(e->mode == NotifyGrab)
- return;
-
- if(ev->type == FocusIn) {
- XSetICFocus(xw.xic);
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- if(IS_SET(MODE_FOCUS))
- ttywrite("\033[I", 3);
- } else {
- XUnsetICFocus(xw.xic);
- xw.state &= ~WIN_FOCUSED;
- if(IS_SET(MODE_FOCUS))
- ttywrite("\033[O", 3);
- }
-}
-
-bool
-match(uint mask, uint state) {
- return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
-}
-
-void
-numlock(const Arg *dummy) {
- term.numlock ^= 1;
-}
-
-char*
-kmap(KeySym k, uint state) {
- Key *kp;
- int i;
-
- /* Check for mapped keys out of X11 function keys. */
- for(i = 0; i < LEN(mappedkeys); i++) {
- if(mappedkeys[i] == k)
- break;
- }
- if(i == LEN(mappedkeys)) {
- if((k & 0xFFFF) < 0xFD00)
- return NULL;
- }
-
- for(kp = key; kp < key + LEN(key); kp++) {
- if(kp->k != k)
- continue;
-
- if(!match(kp->mask, state))
- continue;
-
- if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
- continue;
- if(term.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;
- }
-
- return NULL;
-}
-
-void
-kpress(XEvent *ev) {
- XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char buf[32], *customkey;
- int len;
- Rune c;
- Status status;
- Shortcut *bp;
-
- if(IS_SET(MODE_KBDLOCK))
- return;
-
- len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
- /* 1. shortcuts */
- for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
- if(ksym == bp->keysym && match(bp->mod, e->state)) {
- bp->func(&(bp->arg));
- return;
- }
- }
-
- /* 2. custom keys from config.h */
- if((customkey = kmap(ksym, e->state))) {
- ttysend(customkey, strlen(customkey));
- return;
- }
-
- /* 3. composed string from input method */
- if(len == 0)
- return;
- if(len == 1 && e->state & Mod1Mask) {
- if(IS_SET(MODE_8BIT)) {
- if(*buf < 0177) {
- c = *buf | 0x80;
- len = utf8encode(c, buf);
- }
- } else {
- buf[1] = buf[0];
- buf[0] = '\033';
- len = 2;
- }
- }
- ttysend(buf, len);
-}
-
-
-void
-cmessage(XEvent *e) {
- /*
- * See xembed specs
- * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
- */
- if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
- if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- } else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
- xw.state &= ~WIN_FOCUSED;
- }
- } else if(e->xclient.data.l[0] == xw.wmdeletewin) {
- /* Send SIGHUP to shell */
- kill(pid, SIGHUP);
- exit(EXIT_SUCCESS);
- }
-}
-
-void
-cresize(int width, int height) {
- int col, row;
-
- if(width != 0)
- xw.w = width;
- if(height != 0)
- xw.h = height;
-
- col = (xw.w - 2 * borderpx) / xw.cw;
- row = (xw.h - 2 * borderpx) / xw.ch;
-
- tresize(col, row);
- xresize(col, row);
- ttyresize();
-}
-
-void
-resize(XEvent *e) {
- if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
- return;
-
- cresize(e->xconfigure.width, e->xconfigure.height);
-}
-
-void
-run(void) {
- XEvent ev;
- int w = xw.w, h = xw.h;
- fd_set rfd;
- int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
- struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
- long deltatime;
-
- /* Waiting for window mapping */
- do {
- XNextEvent(xw.dpy, &ev);
- if(ev.type == ConfigureNotify) {
- w = ev.xconfigure.width;
- h = ev.xconfigure.height;
- }
- } while(ev.type != MapNotify);
-
- ttynew();
- cresize(w, h);
-
- clock_gettime(CLOCK_MONOTONIC, &last);
- lastblink = last;
-
- for(xev = actionfps;;) {
- FD_ZERO(&rfd);
- FD_SET(cmdfd, &rfd);
- FD_SET(xfd, &rfd);
-
- if(pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
- if(errno == EINTR)
- continue;
- die("select failed: %s\n", strerror(errno));
- }
- if(FD_ISSET(cmdfd, &rfd)) {
- ttyread();
- if(blinktimeout) {
- blinkset = tattrset(ATTR_BLINK);
- if(!blinkset)
- MODBIT(term.mode, 0, MODE_BLINK);
- }
- }
-
- if(FD_ISSET(xfd, &rfd))
- xev = actionfps;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- drawtimeout.tv_sec = 0;
- drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
- tv = &drawtimeout;
-
- dodraw = 0;
- if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
- tsetdirtattr(ATTR_BLINK);
- term.mode ^= MODE_BLINK;
- lastblink = now;
- dodraw = 1;
- }
- deltatime = TIMEDIFF(now, last);
- if(deltatime > 1000 / (xev ? xfps : actionfps)) {
- dodraw = 1;
- last = now;
- }
-
- if(dodraw) {
- while(XPending(xw.dpy)) {
- XNextEvent(xw.dpy, &ev);
- if(XFilterEvent(&ev, None))
- continue;
- if(handler[ev.type])
- (handler[ev.type])(&ev);
- }
-
- draw();
- XFlush(xw.dpy);
-
- if(xev && !FD_ISSET(xfd, &rfd))
- xev--;
- if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
- if(blinkset) {
- if(TIMEDIFF(now, lastblink) \
- > blinktimeout) {
- drawtimeout.tv_nsec = 1000;
- } else {
- drawtimeout.tv_nsec = (1E6 * \
- (blinktimeout - \
- TIMEDIFF(now,
- lastblink)));
- }
- drawtimeout.tv_sec = \
- drawtimeout.tv_nsec / 1E9;
- drawtimeout.tv_nsec %= (long)1E9;
- } else {
- tv = NULL;
- }
- }
- }
- }
-}
-
-void
-usage(void) {
- die("%s " VERSION " (c) 2010-2015 st engineers\n"
- "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
- " [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
- " st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
- " [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
- argv0);
-}
-
-int
-main(int argc, char *argv[]) {
- uint cols = 80, rows = 24;
-
- xw.l = xw.t = 0;
- xw.isfixed = False;
- xw.cursor = 0;
-
- ARGBEGIN {
- case 'a':
- allowaltscreen = false;
- break;
- case 'c':
- opt_class = EARGF(usage());
- break;
- case 'e':
- if(argc > 0)
- --argc, ++argv;
- goto run;
- case 'f':
- opt_font = EARGF(usage());
- break;
- case 'g':
- xw.gm = XParseGeometry(EARGF(usage()),
- &xw.l, &xw.t, &cols, &rows);
- break;
- case 'i':
- xw.isfixed = True;
- break;
- case 'o':
- opt_io = EARGF(usage());
- break;
- case 'l':
- opt_line = EARGF(usage());
- break;
- case 't':
- opt_title = EARGF(usage());
- break;
- case 'w':
- opt_embed = EARGF(usage());
- break;
- case 'v':
- default:
- usage();
- } ARGEND;
-
-run:
- if(argc > 0) {
- /* eat all remaining arguments */
- opt_cmd = argv;
- if(!opt_title && !opt_line)
- opt_title = basename(xstrdup(argv[0]));
- }
- setlocale(LC_CTYPE, "");
- XSetLocaleModifiers("");
- tnew(MAX(cols, 1), MAX(rows, 1));
- xinit();
- selinit();
- run();
-
- return 0;
-}
-