summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <koverstreet@google.com>2013-03-16 15:53:00 -0700
committerKent Overstreet <koverstreet@google.com>2013-03-16 18:14:39 -0700
commitdeb79ca7df3e6ffe01e8d8b8ea264ce9ec0aeac4 (patch)
tree5d54183242c262e7c11ac4b609b63324026d242a
parent83c293e4846acf1830ab5c556d1b45c175b340b7 (diff)
Reorder to kill forward declarations
-rw-r--r--st.c2426
1 files changed, 1170 insertions, 1256 deletions
diff --git a/st.c b/st.c
index f9c594e..ed2f887 100644
--- a/st.c
+++ b/st.c
@@ -294,118 +294,6 @@ typedef struct {
GC gc;
} DC;
-static void die(const char *, ...);
-static void draw(void);
-static void redraw(int);
-static void drawregion(int, int, int, int);
-static void execsh(void);
-static void sigchld(int);
-static void run(void);
-
-static void csidump(void);
-static void csihandle(void);
-static void csiparse(void);
-static void csireset(void);
-static void strdump(void);
-static void strhandle(void);
-static void strparse(void);
-static void strreset(void);
-
-static void tclearregion(int, int, int, int, int);
-static void tcursor(int);
-static void tdeletechar(int);
-static void tdeleteline(int);
-static void tinsertblank(int);
-static void tinsertblankline(int);
-static void tmoveto(int, int);
-static void tmoveato(int x, int y);
-static void tnew(int, int);
-static void tnewline(int);
-static void tputtab(bool);
-static void tputc(char *, int);
-static void treset(void);
-static int tresize(int, int);
-static void tscrollup(int, int);
-static void tscrolldown(int, int);
-static void tsetattr(int *, int);
-static void tsetchar(char *, Glyph *, int, int);
-static void tsetscroll(int, int);
-static void tswapscreen(void);
-static void tsetdirt(int, int);
-static void tsetmode(bool, bool, int *, int);
-static void tfulldirt(void);
-static void techo(char *, int);
-
-static inline bool match(uint, uint);
-static void ttynew(void);
-static void ttyread(void);
-static void ttyresize(void);
-static void ttywrite(const char *, size_t);
-
-static void xdraws(char *, Glyph, int, int, int, int);
-static void xhints(void);
-static void xclear(int, int, int, int);
-static void xdrawcursor(void);
-static void xinit(void);
-static void xloadcols(void);
-static int xsetcolorname(int, const char *);
-static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, int);
-static void xsettitle(char *);
-static void xresettitle(void);
-static void xseturgency(int);
-static void xsetsel(char *);
-static void xtermclear(int, int, int, int);
-static void xunloadfonts(void);
-static void xresize(int, int);
-
-static void expose(XEvent *);
-static void visibility(XEvent *);
-static void unmap(XEvent *);
-static char *kmap(KeySym, uint);
-static void kpress(XEvent *);
-static void cmessage(XEvent *);
-static void cresize(int, int);
-static void resize(XEvent *);
-static void focus(XEvent *);
-static void brelease(XEvent *);
-static void bpress(XEvent *);
-static void bmotion(XEvent *);
-static void selnotify(XEvent *);
-static void selclear(XEvent *);
-static void selrequest(XEvent *);
-
-static void selinit(void);
-static inline bool selected(int, int);
-static void selcopy(void);
-static void selscroll(int, int);
-
-static int utf8decode(char *, long *);
-static int utf8encode(long *, char *);
-static int utf8size(char *);
-static int isfullutf8(char *, int);
-
-static ssize_t xwrite(int, char *, size_t);
-static void *xmalloc(size_t);
-static void *xrealloc(void *, size_t);
-static void *xcalloc(size_t, size_t);
-
-static void (*handler[LASTEvent]) (XEvent *) = {
-[KeyPress] = kpress,
- [ClientMessage] = cmessage,
- [ConfigureNotify] = resize,
- [VisibilityNotify] = visibility,
- [UnmapNotify] = unmap,
- [Expose] = expose,
- [FocusIn] = focus,
- [FocusOut] = focus,
- [MotionNotify] = bmotion,
- [ButtonPress] = bpress,
- [ButtonRelease] = brelease,
- [SelectionClear] = selclear,
- [SelectionNotify] = selnotify,
- [SelectionRequest] = selrequest,};
-
/* Globals */
static DC dc;
static XWindow xw;
@@ -448,7 +336,69 @@ typedef struct {
static Fontcache frc[1024];
static int frccur = -1, frclen = 0;
-ssize_t xwrite(int fd, char *s, size_t len)
+/* Random utility code */
+
+static void die(const char *errstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+static void execsh(void)
+{
+ char **args;
+ char *envshell = getenv("SHELL");
+ const struct passwd *pass = getpwuid(getuid());
+ char buf[sizeof(long) * 8 + 1];
+
+ unsetenv("COLUMNS");
+ unsetenv("LINES");
+ unsetenv("TERMCAP");
+
+ if (pass) {
+ setenv("LOGNAME", pass->pw_name, 1);
+ setenv("USER", pass->pw_name, 1);
+ setenv("SHELL", pass->pw_shell, 0);
+ setenv("HOME", pass->pw_dir, 0);
+ }
+
+ snprintf(buf, sizeof(buf), "%lu", xw.win);
+ setenv("WINDOWID", buf, 1);
+
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGALRM, SIG_DFL);
+
+ DEFAULT(envshell, shell);
+ setenv("TERM", termname, 1);
+ args = opt_cmd ? opt_cmd : (char *[]) {
+ envshell, "-i", NULL};
+ execvp(args[0], args);
+ exit(EXIT_FAILURE);
+}
+
+static void sigchld(int a)
+{
+ int stat = 0;
+
+ if (waitpid(pid, &stat, 0) < 0)
+ die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
+
+ if (WIFEXITED(stat)) {
+ exit(WEXITSTATUS(stat));
+ } else {
+ exit(EXIT_FAILURE);
+ }
+}
+
+static ssize_t xwrite(int fd, char *s, size_t len)
{
size_t aux = len;
@@ -462,7 +412,7 @@ ssize_t xwrite(int fd, char *s, size_t len)
return aux;
}
-void *xmalloc(size_t len)
+static void *xmalloc(size_t len)
{
void *p = malloc(len);
@@ -472,7 +422,7 @@ void *xmalloc(size_t len)
return p;
}
-void *xrealloc(void *p, size_t len)
+static void *xrealloc(void *p, size_t len)
{
if ((p = realloc(p, len)) == NULL)
die("Out of memory\n");
@@ -480,7 +430,7 @@ void *xrealloc(void *p, size_t len)
return p;
}
-void *xcalloc(size_t nmemb, size_t size)
+static void *xcalloc(size_t nmemb, size_t size)
{
void *p = calloc(nmemb, size);
@@ -490,7 +440,7 @@ void *xcalloc(size_t nmemb, size_t size)
return p;
}
-int utf8decode(char *s, long *u)
+static int utf8decode(char *s, long *u)
{
uchar c;
int i, n, rtn;
@@ -534,7 +484,7 @@ int utf8decode(char *s, long *u)
return rtn;
}
-int utf8encode(long *u, char *s)
+static int utf8encode(long *u, char *s)
{
uchar *sp;
ulong uc;
@@ -573,7 +523,7 @@ int utf8encode(long *u, char *s)
/* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode
UTF-8 otherwise return 0 */
-int isfullutf8(char *s, int b)
+static int isfullutf8(char *s, int b)
{
uchar *c1, *c2, *c3;
@@ -597,7 +547,7 @@ int isfullutf8(char *s, int b)
}
}
-int utf8size(char *s)
+static int utf8size(char *s)
{
uchar c = *s;
@@ -612,35 +562,127 @@ int utf8size(char *s)
}
}
-void selinit(void)
+static ushort sixd_to_16bit(int x)
{
- memset(&sel.tclick1, 0, sizeof(sel.tclick1));
- memset(&sel.tclick2, 0, sizeof(sel.tclick2));
- sel.mode = 0;
- sel.bx = -1;
- sel.clip = NULL;
- sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
- if (sel.xtarget == None)
- sel.xtarget = XA_STRING;
+ return x == 0 ? 0 : 0x3737 + 0x2828 * x;
}
-static int x2col(int x)
+/* X utility code */
+
+static bool match(uint mask, uint state)
{
- x -= borderpx;
- x /= xw.cw;
+ state &= ~(ignoremod);
- return LIMIT(x, 0, term.col - 1);
+ if (mask == XK_NO_MOD && state)
+ return false;
+ if (mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
+ return false;
+ if ((state & mask) != state)
+ return false;
+ return true;
}
-static int y2row(int y)
+static int xsetcolorname(int x, const char *name)
{
- y -= borderpx;
- y /= xw.ch;
+ XRenderColor color = {.alpha = 0xffff };
+ Colour colour;
+ if (x < 0 || x > LEN(colorname))
+ return -1;
+ if (!name) {
+ if (16 <= x && x < 16 + 216) {
+ int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b =
+ (x - 16) % 6;
+ color.red = sixd_to_16bit(r);
+ color.green = sixd_to_16bit(g);
+ color.blue = sixd_to_16bit(b);
+ if (!XftColorAllocValue
+ (xw.dpy, xw.vis, xw.cmap, &color, &colour))
+ return 0; /* something went wrong */
+ dc.col[x] = colour;
+ return 1;
+ } else if (16 + 216 <= x && x < 256) {
+ color.red = color.green = color.blue =
+ 0x0808 + 0x0a0a * (x - (16 + 216));
+ if (!XftColorAllocValue
+ (xw.dpy, xw.vis, xw.cmap, &color, &colour))
+ return 0; /* something went wrong */
+ dc.col[x] = colour;
+ return 1;
+ } else {
+ name = colorname[x];
+ }
+ }
+ if (!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
+ return 0;
+ dc.col[x] = colour;
+ return 1;
+}
- return LIMIT(y, 0, term.row - 1);
+static void xsettitle(char *p)
+{
+ XTextProperty prop;
+
+ Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop);
+ XSetWMName(xw.dpy, xw.win, &prop);
+}
+
+static void xresettitle(void)
+{
+ xsettitle(opt_title ? opt_title : "st");
+}
+
+static void xseturgency(int add)
+{
+ XWMHints *h = XGetWMHints(xw.dpy, xw.win);
+
+ h->flags =
+ add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+ XSetWMHints(xw.dpy, xw.win, h);
+ XFree(h);
}
-static inline bool selected(int x, int y)
+static void xsetsel(char *str)
+{
+ /* register the selection for both the clipboard and the primary */
+ Atom clipboard;
+
+ free(sel.clip);
+ sel.clip = str;
+
+ XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
+
+ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+ XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+}
+
+void ttywrite(const char *s, size_t n)
+{
+ if (write(cmdfd, s, n) == -1)
+ die("write error on tty: %s\n", SERRNO);
+}
+
+/* ? */
+
+static void tsetdirt(int top, int bot)
+{
+ int i;
+
+ LIMIT(top, 0, term.row - 1);
+ LIMIT(bot, 0, term.row - 1);
+
+ for (i = top; i <= bot; i++)
+ term.dirty[i] = 1;
+}
+
+static void tfulldirt(void)
+{
+ tsetdirt(0, term.row - 1);
+}
+
+/* Selection code */
+
+static bool selected(int x, int y)
{
int bx, ex;
@@ -666,99 +708,7 @@ static inline bool selected(int x, int y)
};
}
-void getbuttoninfo(XEvent *e)
-{
- int type;
- uint state = e->xbutton.state & ~Button1Mask;
-
- sel.alt = IS_SET(MODE_ALTSCREEN);
-
- sel.ex = x2col(e->xbutton.x);
- sel.ey = y2row(e->xbutton.y);
-
- sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
- sel.b.y = MIN(sel.by, sel.ey);
- sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
- sel.e.y = MAX(sel.by, sel.ey);
-
- sel.type = SEL_REGULAR;
- for (type = 1; type < LEN(selmasks); ++type) {
- if (match(selmasks[type], state)) {
- sel.type = type;
- break;
- }
- }
-}
-
-void mousereport(XEvent *e)
-{
- 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 ob, ox, oy;
-
- /* from urxvt */
- if (e->xbutton.type == MotionNotify) {
- if (!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
- return;
- button = ob + 32;
- ox = x, oy = y;
- } else if (!IS_SET(MODE_MOUSESGR)
- && (e->xbutton.type == ButtonRelease
- || button == AnyButton)) {
- button = 3;
- } else {
- button -= Button1;
- if (button >= 3)
- button += 64 - 3;
- if (e->xbutton.type == ButtonPress) {
- ob = button;
- ox = x, oy = y;
- }
- }
-
- button += (state & ShiftMask ? 4 : 0)
- + (state & Mod4Mask ? 8 : 0)
- + (state & ControlMask ? 16 : 0);
-
- len = 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)
-{
- if (IS_SET(MODE_MOUSE)) {
- mousereport(e);
- } else if (e->xbutton.button == Button1) {
- if (sel.bx != -1) {
- sel.bx = -1;
- tsetdirt(sel.b.y, sel.e.y);
- draw();
- }
- sel.mode = 1;
- sel.type = SEL_REGULAR;
- sel.ex = sel.bx = x2col(e->xbutton.x);
- sel.ey = sel.by = y2row(e->xbutton.y);
- } else if (e->xbutton.button == Button4) {
- ttywrite("\031", 1);
- } else if (e->xbutton.button == Button5) {
- ttywrite("\005", 1);
- }
-}
-
-void selcopy(void)
+static void selcopy(void)
{
char *str, *ptr, *p;
int x, y, bufsize, is_selected = 0, size;
@@ -801,7 +751,7 @@ void selcopy(void)
xsetsel(str);
}
-void selnotify(XEvent *e)
+static void selnotify(XEvent *e)
{
ulong nitems, ofs, rem;
int format;
@@ -824,13 +774,13 @@ void selnotify(XEvent *e)
} while (rem > 0);
}
-void selpaste(const Arg *dummy)
+static void selpaste(const Arg *dummy)
{
XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
xw.win, CurrentTime);
}
-void clippaste(const Arg *dummy)
+static void clippaste(const Arg *dummy)
{
Atom clipboard;
@@ -839,7 +789,7 @@ void clippaste(const Arg *dummy)
xw.win, CurrentTime);
}
-void selclear(XEvent *e)
+static void selclear(XEvent *e)
{
if (sel.bx == -1)
return;
@@ -847,7 +797,7 @@ void selclear(XEvent *e)
tsetdirt(sel.b.y, sel.e.y);
}
-void selrequest(XEvent *e)
+static void selrequest(XEvent *e)
{
XSelectionRequestEvent *xsre;
XSelectionEvent xev;
@@ -884,342 +834,476 @@ void selrequest(XEvent *e)
fprintf(stderr, "Error sending SelectionNotify event\n");
}
-void xsetsel(char *str)
+static void selscroll(int orig, int n)
{
- /* register the selection for both the clipboard and the primary */
- Atom clipboard;
+ if (sel.bx == -1)
+ return;
- free(sel.clip);
- sel.clip = str;
+ if (BETWEEN(sel.by, orig, term.bot)
+ || BETWEEN(sel.ey, orig, term.bot)) {
+ if ((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
+ sel.bx = -1;
+ return;
+ }
+ switch (sel.type) {
+ case SEL_REGULAR:
+ if (sel.by < term.top) {
+ sel.by = term.top;
+ sel.bx = 0;
+ }
+ if (sel.ey > term.bot) {
+ sel.ey = term.bot;
+ sel.ex = term.col;
+ }
+ break;
+ case SEL_RECTANGULAR:
+ if (sel.by < term.top)
+ sel.by = term.top;
+ if (sel.ey > term.bot)
+ sel.ey = term.bot;
+ break;
+ };
+ sel.b.y = sel.by, sel.b.x = sel.bx;
+ sel.e.y = sel.ey, sel.e.x = sel.ex;
+ }
+}
- XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
+/* Screen drawing code */
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+static void xtermclear(int col1, int row1, int col2, int row2)
+{
+ XftDrawRect(xw.draw,
+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+ borderpx + col1 * xw.cw,
+ borderpx + row1 * xw.ch,
+ (col2 - col1 + 1) * xw.cw, (row2 - row1 + 1) * xw.ch);
}
-void brelease(XEvent *e)
+/*
+ * Absolute coordinates.
+ */
+static void xclear(int x1, int y1, int x2, int y2)
{
- struct timeval now;
+ XftDrawRect(xw.draw,
+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+ x1, y1, x2 - x1, y2 - y1);
+}
- if (IS_SET(MODE_MOUSE)) {
- mousereport(e);
- return;
- }
+void xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen)
+{
+ int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
+ width = charlen * xw.cw, xp, i;
+ int frp, frcflags;
+ int u8fl, u8fblen, u8cblen, doesexist;
+ char *u8c, *u8fs;
+ long u8char;
+ Font *font = &dc.font;
+ FcResult fcres;
+ FcPattern *fcpattern, *fontpattern;
+ FcFontSet *fcsets[] = { NULL };
+ FcCharSet *fccharset;
+ Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
+ *temp, revfg, revbg;
+ XRenderColor colfg, colbg;
- if (e->xbutton.button == Button2) {
- selpaste(NULL);
- } else if (e->xbutton.button == Button1) {
- sel.mode = 0;
- getbuttoninfo(e);
- term.dirty[sel.ey] = 1;
- if (sel.bx == sel.ex && sel.by == sel.ey) {
- sel.bx = -1;
- gettimeofday(&now, NULL);
+ frcflags = FRC_NORMAL;
- if (TIMEDIFF(now, sel.tclick2) <=
- tripleclicktimeout) {
- /* triple click on the line */
- sel.b.x = sel.bx = 0;
- sel.e.x = sel.ex = term.col;
- sel.b.y = sel.e.y = sel.ey;
- selcopy();
- } else if (TIMEDIFF(now, sel.tclick1) <=
- doubleclicktimeout) {
- /* double click to select word */
- sel.bx = sel.ex;
- while (sel.bx > 0
- && term.line[sel.ey][sel.bx -
- 1].state &
- GLYPH_SET
- && term.line[sel.ey][sel.bx -
- 1].c[0] !=
- ' ') {
- sel.bx--;
- }
- sel.b.x = sel.bx;
- while (sel.ex < term.col - 1
- && term.line[sel.ey][sel.ex +
- 1].state &
- GLYPH_SET
- && term.line[sel.ey][sel.ex +
- 1].c[0] !=
- ' ') {
- sel.ex++;
- }
- sel.e.x = sel.ex;
- sel.b.y = sel.e.y = sel.ey;
- selcopy();
- }
- } else {
- selcopy();
+ if (base.mode & ATTR_BOLD) {
+ if (BETWEEN(base.fg, 0, 7)) {
+ /* basic system colors */
+ fg = &dc.col[base.fg + 8];
+ } else if (BETWEEN(base.fg, 16, 195)) {
+ /* 256 colors */
+ fg = &dc.col[base.fg + 36];
+ } else if (BETWEEN(base.fg, 232, 251)) {
+ /* greyscale */
+ fg = &dc.col[base.fg + 4];
}
+ /*
+ * Those ranges will not be brightened:
+ * 8 - 15 – bright system colors
+ * 196 - 231 – highest 256 color cube
+ * 252 - 255 – brightest colors in greyscale
+ */
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
}
- memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
- gettimeofday(&sel.tclick1, NULL);
-}
+ if (base.mode & ATTR_ITALIC) {
+ font = &dc.ifont;
+ frcflags = FRC_ITALIC;
+ }
+ if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ }
-void bmotion(XEvent *e)
-{
- int oldey, oldex, oldsby, oldsey;
+ if (IS_SET(MODE_REVERSE)) {
+ if (fg == &dc.col[defaultfg]) {
+ fg = &dc.col[defaultbg];
+ } else {
+ colfg.red = ~fg->color.red;
+ colfg.green = ~fg->color.green;
+ colfg.blue = ~fg->color.blue;
+ colfg.alpha = fg->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
+ &revfg);
+ fg = &revfg;
+ }
- if (IS_SET(MODE_MOUSE)) {
- mousereport(e);
- return;
+ if (bg == &dc.col[defaultbg]) {
+ bg = &dc.col[defaultfg];
+ } else {
+ colbg.red = ~bg->color.red;
+ colbg.green = ~bg->color.green;
+ colbg.blue = ~bg->color.blue;
+ colbg.alpha = bg->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
+ &revbg);
+ bg = &revbg;
+ }
}
- if (!sel.mode)
- return;
-
- oldey = sel.ey;
- oldex = sel.ex;
- oldsby = sel.b.y;
- oldsey = sel.e.y;
- getbuttoninfo(e);
+ if (base.mode & ATTR_REVERSE) {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
- if (oldey != sel.ey || oldex != sel.ex) {
- tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey));
+ /* Intelligent cleaning up of the borders. */
+ if (x == 0) {
+ xclear(0, (y == 0) ? 0 : winy, borderpx,
+ winy + xw.ch + ((y >= term.row - 1) ? xw.h : 0));
}
-}
+ if (x + charlen >= term.col) {
+ xclear(winx + width, (y == 0) ? 0 : winy, xw.w,
+ ((y >= term.row - 1) ? xw.h : (winy + xw.ch)));
+ }
+ if (y == 0)
+ xclear(winx, 0, winx + width, borderpx);
+ if (y == term.row - 1)
+ xclear(winx, winy + xw.ch, winx + width, xw.h);
-void die(const char *errstr, ...)
-{
- va_list ap;
+ /* Clean up the region we want to draw to. */
+ XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
- va_start(ap, errstr);
- vfprintf(stderr, errstr, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
-}
+ fcsets[0] = font->set;
+ for (xp = winx; bytelen > 0;) {
+ /*
+ * Search for the range in the to be printed string of glyphs
+ * that are in the main font. Then print that range. If
+ * some glyph is found that is not in the font, do the
+ * fallback dance.
+ */
+ u8fs = s;
+ u8fblen = 0;
+ u8fl = 0;
+ for (;;) {
+ u8c = s;
+ u8cblen = utf8decode(s, &u8char);
+ s += u8cblen;
+ bytelen -= u8cblen;
-void execsh(void)
-{
- char **args;
- char *envshell = getenv("SHELL");
- const struct passwd *pass = getpwuid(getuid());
- char buf[sizeof(long) * 8 + 1];
+ doesexist =
+ XftCharIndex(xw.dpy, font->match, u8char);
+ if (!doesexist || bytelen <= 0) {
+ if (bytelen <= 0) {
+ if (doesexist) {
+ u8fl++;
+ u8fblen += u8cblen;
+ }
+ }
- unsetenv("COLUMNS");
- unsetenv("LINES");
- unsetenv("TERMCAP");
+ if (u8fl > 0) {
+ XftDrawStringUtf8(xw.draw, fg,
+ font->match, xp,
+ winy +
+ font->ascent,
+ (FcChar8 *) u8fs,
+ u8fblen);
+ xp += font->width * u8fl;
+ }
+ break;
+ }
- if (pass) {
- setenv("LOGNAME", pass->pw_name, 1);
- setenv("USER", pass->pw_name, 1);
- setenv("SHELL", pass->pw_shell, 0);
- setenv("HOME", pass->pw_dir, 0);
- }
+ u8fl++;
+ u8fblen += u8cblen;
+ }
+ if (doesexist)
+ break;
- snprintf(buf, sizeof(buf), "%lu", xw.win);
- setenv("WINDOWID", buf, 1);
+ frp = frccur;
+ /* Search the font cache. */
+ for (i = 0; i < frclen; i++, frp--) {
+ if (frp <= 0)
+ frp = LEN(frc) - 1;
- signal(SIGCHLD, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- signal(SIGINT, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGALRM, SIG_DFL);
+ if (frc[frp].c == u8char
+ && frc[frp].flags == frcflags) {
+ break;
+ }
+ }
- DEFAULT(envshell, shell);
- setenv("TERM", termname, 1);
- args = opt_cmd ? opt_cmd : (char *[]) {
- envshell, "-i", NULL};
- execvp(args[0], args);
- exit(EXIT_FAILURE);
-}
+ /* Nothing was found. */
+ if (i >= frclen) {
+ /*
+ * Nothing was found in the cache. Now use
+ * some dozen of Fontconfig calls to get the
+ * font for one single character.
+ */
+ fcpattern = FcPatternDuplicate(font->pattern);
+ fccharset = FcCharSetCreate();
-void sigchld(int a)
-{
- int stat = 0;
+ FcCharSetAddChar(fccharset, u8char);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET,
+ fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
- if (waitpid(pid, &stat, 0) < 0)
- die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
+ FcConfigSubstitute(0, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
- if (WIFEXITED(stat)) {
- exit(WEXITSTATUS(stat));
- } else {
- exit(EXIT_FAILURE);
- }
-}
+ fontpattern = FcFontSetMatch(0, fcsets,
+ FcTrue, fcpattern,
+ &fcres);
-void ttynew(void)
-{
- int m, s;
- struct winsize w = { term.row, term.col, 0, 0 };
+ /*
+ * Overwrite or create the new cache entry
+ * entry.
+ */
+ frccur++;
+ frclen++;
+ if (frccur >= LEN(frc))
+ frccur = 0;
+ if (frclen > LEN(frc)) {
+ frclen = LEN(frc);
+ XftFontClose(xw.dpy, frc[frccur].font);
+ }
- /* seems to work fine on linux, openbsd and freebsd */
- if (openpty(&m, &s, NULL, NULL, &w) < 0)
- die("openpty failed: %s\n", SERRNO);
+ frc[frccur].font = XftFontOpenPattern(xw.dpy,
+ fontpattern);
+ frc[frccur].c = u8char;
+ frc[frccur].flags = frcflags;
- switch (pid = fork()) {
- case -1:
- die("fork failed\n");
- break;
- case 0:
- setsid(); /* create a new process group */
- dup2(s, STDIN_FILENO);
- dup2(s, STDOUT_FILENO);
- dup2(s, STDERR_FILENO);
- if (ioctl(s, TIOCSCTTY, NULL) < 0)
- die("ioctl TIOCSCTTY failed: %s\n", SERRNO);
- close(s);
- close(m);
- execsh();
- break;
- default:
- close(s);
- cmdfd = m;
- signal(SIGCHLD, sigchld);
- if (opt_io) {
- iofd = (!strcmp(opt_io, "-")) ?
- STDOUT_FILENO :
- open(opt_io, O_WRONLY | O_CREAT, 0666);
- if (iofd < 0) {
- fprintf(stderr, "Error opening %s:%s\n",
- opt_io, strerror(errno));
- }
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
+
+ frp = frccur;
}
+
+ XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
+ xp, winy + frc[frp].font->ascent,
+ (FcChar8 *) u8c, u8cblen);
+
+ xp += font->width;
}
-}
-void dump(char c)
-{
- static int col;
+ /*
+ XftDrawStringUtf8(xw.draw, fg, font->set, winx,
+ winy + font->ascent, (FcChar8 *)s, bytelen);
+ */
- fprintf(stderr, " %02x '%c' ", c, isprint(c) ? c : '.');
- if (++col % 10 == 0)
- fprintf(stderr, "\n");
+ if (base.mode & ATTR_UNDERLINE) {
+ XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
+ width, 1);
+ }
}
-void ttyread(void)
+static void xdrawcursor(void)
{
- static char buf[BUFSIZ];
- static int buflen = 0;
- char *ptr;
- char s[UTF_SIZ];
- int charsize; /* size of utf8 char in bytes */
- long utf8c;
- int ret;
+ static int oldx = 0, oldy = 0;
+ int sl;
+ Glyph g = { {' '}, ATTR_NULL, defaultbg, defaultcs, 0 };
- /* append read bytes to unprocessed bytes */
- if ((ret = read(cmdfd, buf + buflen, LEN(buf) - buflen)) < 0)
- die("Couldn't read from shell: %s\n", SERRNO);
+ LIMIT(oldx, 0, term.col - 1);
+ LIMIT(oldy, 0, term.row - 1);
- /* process every complete utf8 char */
- buflen += ret;
- ptr = buf;
- while (buflen >= UTF_SIZ || isfullutf8(ptr, buflen)) {
- charsize = utf8decode(ptr, &utf8c);
- utf8encode(&utf8c, s);
- tputc(s, charsize);
- ptr += charsize;
- buflen -= charsize;
+ if (term.line[term.c.y][term.c.x].state & GLYPH_SET)
+ memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
+
+ /* remove the old cursor */
+ if (term.line[oldy][oldx].state & GLYPH_SET) {
+ sl = utf8size(term.line[oldy][oldx].c);
+ xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx],
+ oldx, oldy, 1, sl);
+ } else {
+ xtermclear(oldx, oldy, oldx, oldy);
}
- /* keep any uncomplete utf8 char for the next call */
- memmove(buf, ptr, buflen);
-}
+ /* draw the new one */
+ if (!(IS_SET(MODE_HIDE))) {
+ if (!(xw.state & WIN_FOCUSED))
+ g.bg = defaultucs;
-void ttywrite(const char *s, size_t n)
-{
- if (write(cmdfd, s, n) == -1)
- die("write error on tty: %s\n", SERRNO);
+ if (IS_SET(MODE_REVERSE))
+ g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg =
+ defaultfg;
+
+ sl = utf8size(g.c);
+ xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
+ oldx = term.c.x, oldy = term.c.y;
+ }
}
-void ttyresize(void)
+static void drawregion(int x1, int y1, int x2, int y2)
{
- struct winsize w;
+ int ic, ib, x, y, ox, sl;
+ Glyph base, new;
+ char buf[DRAW_BUF_SIZ];
+ bool ena_sel = sel.bx != -1;
- w.ws_row = term.row;
- w.ws_col = term.col;
- w.ws_xpixel = xw.tw;
- w.ws_ypixel = xw.th;
- if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
- fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
-}
+ if (sel.alt ^ IS_SET(MODE_ALTSCREEN))
+ ena_sel = 0;
-void tsetdirt(int top, int bot)
-{
- int i;
+ if (!(xw.state & WIN_VISIBLE))
+ return;
- LIMIT(top, 0, term.row - 1);
- LIMIT(bot, 0, term.row - 1);
+ for (y = y1; y < y2; y++) {
+ if (!term.dirty[y])
+ continue;
- for (i = top; i <= bot; i++)
- term.dirty[i] = 1;
+ xtermclear(0, y, term.col, y);
+ term.dirty[y] = 0;
+ base = term.line[y][0];
+ ic = ib = ox = 0;
+ for (x = x1; x < x2; x++) {
+ new = term.line[y][x];
+ if (ena_sel && *(new.c) && selected(x, y))
+ new.mode ^= ATTR_REVERSE;
+ if (ib > 0 && (!(new.state & GLYPH_SET)
+ || ATTRCMP(base, new)
+ || ib >= DRAW_BUF_SIZ - UTF_SIZ)) {
+ xdraws(buf, base, ox, y, ic, ib);
+ ic = ib = 0;
+ }
+ if (new.state & GLYPH_SET) {
+ if (ib == 0) {
+ ox = x;
+ base = new;
+ }
+
+ sl = utf8size(new.c);
+ memcpy(buf + ib, new.c, sl);
+ ib += sl;
+ ++ic;
+ }
+ }
+ if (ib > 0)
+ xdraws(buf, base, ox, y, ic, ib);
+ }
+ xdrawcursor();
}
-void tfulldirt(void)
+static void draw(void)
{
- tsetdirt(0, term.row - 1);
+ 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 tcursor(int mode)
+static void redraw(int timeout)
{
- static TCursor c;
+ struct timespec tv = { 0, timeout * 1000 };
- if (mode == CURSOR_SAVE) {
- c = term.c;
- } else if (mode == CURSOR_LOAD) {
- term.c = c;
- tmoveto(c.x, c.y);
+ tfulldirt();
+ draw();
+
+ if (timeout > 0) {
+ nanosleep(&tv, NULL);
+ XSync(xw.dpy, False); /* necessary for a good tput flash */
}
}
-void treset(void)
-{
- uint i;
+/* Escape handling */
- term.c = (TCursor) { {
- .mode = ATTR_NULL,.fg = defaultfg,.bg = defaultbg},.x = 0,.y =
- 0,.state = CURSOR_DEFAULT};
+static void csiparse(void)
+{
+ char *p = csiescseq.buf, *np;
+ long int v;
- memset(term.tabs, 0, term.col * sizeof(*term.tabs));
- for (i = tabspaces; i < term.col; i += tabspaces)
- term.tabs[i] = 1;
- term.top = 0;
- term.bot = term.row - 1;
- term.mode = MODE_WRAP;
+ csiescseq.narg = 0;
+ if (*p == '?') {
+ csiescseq.priv = 1;
+ p++;
+ }
- tclearregion(0, 0, term.col - 1, term.row - 1, 0);
- tmoveto(0, 0);
- tcursor(CURSOR_SAVE);
+ csiescseq.buf[csiescseq.len] = '\0';
+ while (p < csiescseq.buf + csiescseq.len) {
+ np = NULL;
+ v = strtol(p, &np, 10);
+ if (np == p)
+ v = 0;
+ if (v == LONG_MAX || v == LONG_MIN)
+ v = -1;
+ csiescseq.arg[csiescseq.narg++] = v;
+ p = np;
+ if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+ break;
+ p++;
+ }
+ csiescseq.mode = *p;
}
-void tnew(int col, int row)
+static void csidump(void)
{
- /* set screen size */
- term.row = row;
- term.col = col;
- term.line = xmalloc(term.row * sizeof(Line));
- term.alt = xmalloc(term.row * sizeof(Line));
- term.dirty = xmalloc(term.row * sizeof(*term.dirty));
- term.tabs = xmalloc(term.col * sizeof(*term.tabs));
+ int i;
+ uint c;
- for (row = 0; row < term.row; row++) {
- term.line[row] = xmalloc(term.col * sizeof(Glyph));
- term.alt[row] = xmalloc(term.col * sizeof(Glyph));
- term.dirty[row] = 0;
+ printf("ESC[");
+ for (i = 0; i < csiescseq.len; i++) {
+ c = csiescseq.buf[i] & 0xff;
+ if (isprint(c)) {
+ putchar(c);
+ } else if (c == '\n') {
+ printf("(\\n)");
+ } else if (c == '\r') {
+ printf("(\\r)");
+ } else if (c == 0x1b) {
+ printf("(\\e)");
+ } else {
+ printf("(%02x)", c);
+ }
}
+ putchar('\n');
+}
- term.numlock = 1;
- memset(term.tabs, 0, term.col * sizeof(*term.tabs));
- /* setup screen */
- treset();
+static void csireset(void)
+{
+ memset(&csiescseq, 0, sizeof(csiescseq));
}
-void tswapscreen(void)
+/* t code */
+
+static void tclearregion(int x1, int y1, int x2, int y2, int bce)
{
- Line *tmp = term.line;
+ int x, y, temp;
- term.line = term.alt;
- term.alt = tmp;
- term.mode ^= MODE_ALTSCREEN;
- tfulldirt();
+ if (x1 > x2)
+ temp = x1, x1 = x2, x2 = temp;
+ if (y1 > y2)
+ temp = y1, y1 = y2, y2 = temp;
+
+ LIMIT(x1, 0, term.col - 1);
+ LIMIT(x2, 0, term.col - 1);
+ LIMIT(y1, 0, term.row - 1);
+ LIMIT(y2, 0, term.row - 1);
+
+ for (y = y1; y <= y2; y++) {
+ term.dirty[y] = 1;
+ for (x = x1; x <= x2; x++) {
+ if (bce) {
+ term.line[y][x] = term.c.attr;
+ memcpy(term.line[y][x].c, " ", 2);
+ term.line[y][x].state |= GLYPH_SET;
+ } else {
+ term.line[y][x].state = 0;
+ }
+ }
+ }
}
-void tscrolldown(int orig, int n)
+static void tscrolldown(int orig, int n)
{
int i;
Line temp;
@@ -1240,7 +1324,7 @@ void tscrolldown(int orig, int n)
selscroll(orig, n);
}
-void tscrollup(int orig, int n)
+static void tscrollup(int orig, int n)
{
int i;
Line temp;
@@ -1260,105 +1344,93 @@ void tscrollup(int orig, int n)
selscroll(orig, -n);
}
-void selscroll(int orig, int n)
+static void tmoveto(int x, int y)
{
- if (sel.bx == -1)
- return;
+ int miny, maxy;
- if (BETWEEN(sel.by, orig, term.bot)
- || BETWEEN(sel.ey, orig, term.bot)) {
- if ((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
- sel.bx = -1;
- return;
- }
- switch (sel.type) {
- case SEL_REGULAR:
- if (sel.by < term.top) {
- sel.by = term.top;
- sel.bx = 0;
- }
- if (sel.ey > term.bot) {
- sel.ey = term.bot;
- sel.ex = term.col;
- }
- break;
- case SEL_RECTANGULAR:
- if (sel.by < term.top)
- sel.by = term.top;
- if (sel.ey > term.bot)
- sel.ey = term.bot;
- break;
- };
- sel.b.y = sel.by, sel.b.x = sel.bx;
- sel.e.y = sel.ey, sel.e.x = sel.ex;
+ if (term.c.state & CURSOR_ORIGIN) {
+ miny = term.top;
+ maxy = term.bot;
+ } else {
+ miny = 0;
+ maxy = term.row - 1;
}
+ LIMIT(x, 0, term.col - 1);
+ LIMIT(y, miny, maxy);
+ term.c.state &= ~CURSOR_WRAPNEXT;
+ term.c.x = x;
+ term.c.y = y;
}
-void tnewline(int first_col)
+/* for absolute user moves, when decom is set */
+static void tmoveato(int x, int y)
{
- int y = term.c.y;
+ tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top : 0));
+}
- if (y == term.bot) {
- tscrollup(term.top, 1);
- } else {
- y++;
+static void tcursor(int mode)
+{
+ static TCursor c;
+
+ if (mode == CURSOR_SAVE) {
+ c = term.c;
+ } else if (mode == CURSOR_LOAD) {
+ term.c = c;
+ tmoveto(c.x, c.y);
}
- tmoveto(first_col ? 0 : term.c.x, y);
}
-void csiparse(void)
+static void treset(void)
{
- char *p = csiescseq.buf, *np;
- long int v;
+ uint i;
- csiescseq.narg = 0;
- if (*p == '?') {
- csiescseq.priv = 1;
- p++;
- }
+ term.c = (TCursor) { {
+ .mode = ATTR_NULL,.fg = defaultfg,.bg = defaultbg},.x = 0,.y =
+ 0,.state = CURSOR_DEFAULT};
- csiescseq.buf[csiescseq.len] = '\0';
- while (p < csiescseq.buf + csiescseq.len) {
- np = NULL;
- v = strtol(p, &np, 10);
- if (np == p)
- v = 0;
- if (v == LONG_MAX || v == LONG_MIN)
- v = -1;
- csiescseq.arg[csiescseq.narg++] = v;
- p = np;
- if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
- break;
- p++;
- }
- csiescseq.mode = *p;
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ for (i = tabspaces; i < term.col; i += tabspaces)
+ term.tabs[i] = 1;
+ term.top = 0;
+ term.bot = term.row - 1;
+ term.mode = MODE_WRAP;
+
+ tclearregion(0, 0, term.col - 1, term.row - 1, 0);
+ tmoveto(0, 0);
+ tcursor(CURSOR_SAVE);
}
-/* for absolute user moves, when decom is set */
-void tmoveato(int x, int y)
+static void tputtab(bool forward)
{
- tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top : 0));
+ uint x = term.c.x;
+
+ if (forward) {
+ if (x == term.col)
+ return;
+ for (++x; x < term.col && !term.tabs[x]; ++x)
+ /* nothing */ ;
+ } else {
+ if (x == 0)
+ return;
+ for (--x; x > 0 && !term.tabs[x]; --x)
+ /* nothing */ ;
+ }
+ tmoveto(x, term.c.y);
}
-void tmoveto(int x, int y)
+static void tnewline(int first_col)
{
- int miny, maxy;
+ int y = term.c.y;
- if (term.c.state & CURSOR_ORIGIN) {
- miny = term.top;
- maxy = term.bot;
+ if (y == term.bot) {
+ tscrollup(term.top, 1);
} else {
- miny = 0;
- maxy = term.row - 1;
+ y++;
}
- LIMIT(x, 0, term.col - 1);
- LIMIT(y, miny, maxy);
- term.c.state &= ~CURSOR_WRAPNEXT;
- term.c.x = x;
- term.c.y = y;
+ tmoveto(first_col ? 0 : term.c.x, y);
}
-void tsetchar(char *c, Glyph *attr, int x, int y)
+static void tsetchar(char *c, Glyph *attr, int x, int y)
{
static char *vt100_0[62] = { /* 0x41 - 0x7e */
"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
@@ -1386,35 +1458,7 @@ void tsetchar(char *c, Glyph *attr, int x, int y)
term.line[y][x].state |= GLYPH_SET;
}
-void tclearregion(int x1, int y1, int x2, int y2, int bce)
-{
- int x, y, temp;
-
- if (x1 > x2)
- temp = x1, x1 = x2, x2 = temp;
- if (y1 > y2)
- temp = y1, y1 = y2, y2 = temp;
-
- LIMIT(x1, 0, term.col - 1);
- LIMIT(x2, 0, term.col - 1);
- LIMIT(y1, 0, term.row - 1);
- LIMIT(y2, 0, term.row - 1);
-
- for (y = y1; y <= y2; y++) {
- term.dirty[y] = 1;
- for (x = x1; x <= x2; x++) {
- if (bce) {
- term.line[y][x] = term.c.attr;
- memcpy(term.line[y][x].c, " ", 2);
- term.line[y][x].state |= GLYPH_SET;
- } else {
- term.line[y][x].state = 0;
- }
- }
- }
-}
-
-void tdeletechar(int n)
+static void tdeletechar(int n)
{
int src = term.c.x + n;
int dst = term.c.x;
@@ -1433,7 +1477,7 @@ void tdeletechar(int n)
tclearregion(term.col - n, term.c.y, term.col - 1, term.c.y, 0);
}
-void tinsertblank(int n)
+static void tinsertblank(int n)
{
int src = term.c.x;
int dst = src + n;
@@ -1452,7 +1496,7 @@ void tinsertblank(int n)
tclearregion(src, term.c.y, dst - 1, term.c.y, 0);
}
-void tinsertblankline(int n)
+static void tinsertblankline(int n)
{
if (term.c.y < term.top || term.c.y > term.bot)
return;
@@ -1460,7 +1504,7 @@ void tinsertblankline(int n)
tscrolldown(term.c.y, n);
}
-void tdeleteline(int n)
+static void tdeleteline(int n)
{
if (term.c.y < term.top || term.c.y > term.bot)
return;
@@ -1468,7 +1512,7 @@ void tdeleteline(int n)
tscrollup(term.c.y, n);
}
-void tsetattr(int *attr, int l)
+static void tsetattr(int *attr, int l)
{
int i;
@@ -1571,7 +1615,7 @@ void tsetattr(int *attr, int l)
}
}
-void tsetscroll(int t, int b)
+static void tsetscroll(int t, int b)
{
int temp;
@@ -1586,10 +1630,19 @@ void tsetscroll(int t, int b)
term.bot = b;
}
-#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+static void tswapscreen(void)
+{
+ Line *tmp = term.line;
-void tsetmode(bool priv, bool set, int *args, int narg)
+ term.line = term.alt;
+ term.alt = tmp;
+ term.mode ^= MODE_ALTSCREEN;
+ tfulldirt();
+}
+
+static void tsetmode(bool priv, bool set, int *args, int narg)
{
+#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
int *lim, mode;
bool alt;
@@ -1686,12 +1739,10 @@ void tsetmode(bool priv, bool set, int *args, int narg)
}
}
}
-}
-
#undef MODBIT
+}
-
-void csihandle(void)
+static void csihandle(void)
{
switch (csiescseq.mode) {
default:
@@ -1865,15 +1916,29 @@ void csihandle(void)
}
}
-void csidump(void)
+/* String escape handling */
+
+static void strparse(void)
+{
+ char *p = strescseq.buf;
+
+ strescseq.narg = 0;
+ strescseq.buf[strescseq.len] = '\0';
+ while (p && strescseq.narg < STR_ARG_SIZ)
+ strescseq.args[strescseq.narg++] = strsep(&p, ";");
+}
+
+static void strdump(void)
{
int i;
uint c;
- printf("ESC[");
- for (i = 0; i < csiescseq.len; i++) {
- c = csiescseq.buf[i] & 0xff;
- if (isprint(c)) {
+ printf("ESC%c", strescseq.type);
+ for (i = 0; i < strescseq.len; i++) {
+ c = strescseq.buf[i] & 0xff;
+ if (c == '\0') {
+ return;
+ } else if (isprint(c)) {
putchar(c);
} else if (c == '\n') {
printf("(\\n)");
@@ -1885,15 +1950,15 @@ void csidump(void)
printf("(%02x)", c);
}
}
- putchar('\n');
+ printf("ESC\\\n");
}
-void csireset(void)
+static void strreset(void)
{
- memset(&csiescseq, 0, sizeof(csiescseq));
+ memset(&strescseq, 0, sizeof(strescseq));
}
-void strhandle(void)
+static void strhandle(void)
{
char *p = NULL;
int i, j, narg;
@@ -1948,87 +2013,9 @@ void strhandle(void)
}
}
-void strparse(void)
-{
- char *p = strescseq.buf;
-
- strescseq.narg = 0;
- strescseq.buf[strescseq.len] = '\0';
- while (p && strescseq.narg < STR_ARG_SIZ)
- strescseq.args[strescseq.narg++] = strsep(&p, ";");
-}
-
-void strdump(void)
-{
- int i;
- uint c;
-
- printf("ESC%c", strescseq.type);
- for (i = 0; i < strescseq.len; i++) {
- c = strescseq.buf[i] & 0xff;
- if (c == '\0') {
- return;
- } else if (isprint(c)) {
- putchar(c);
- } else if (c == '\n') {
- printf("(\\n)");
- } else if (c == '\r') {
- printf("(\\r)");
- } else if (c == 0x1b) {
- printf("(\\e)");
- } else {
- printf("(%02x)", c);
- }
- }
- printf("ESC\\\n");
-}
-
-void strreset(void)
-{
- memset(&strescseq, 0, sizeof(strescseq));
-}
-
-void tputtab(bool forward)
-{
- uint x = term.c.x;
-
- if (forward) {
- if (x == term.col)
- return;
- for (++x; x < term.col && !term.tabs[x]; ++x)
- /* nothing */ ;
- } else {
- if (x == 0)
- return;
- for (--x; x > 0 && !term.tabs[x]; --x)
- /* nothing */ ;
- }
- tmoveto(x, term.c.y);
-}
-
-void techo(char *buf, int len)
-{
- for (; len > 0; buf++, len--) {
- char c = *buf;
-
- if (c == '\033') { /* escape */
- tputc("^", 1);
- tputc("[", 1);
- } else if (c < '\x20') { /* control code */
- if (c != '\n' && c != '\r' && c != '\t') {
- c |= '\x40';
- tputc("^", 1);
- }
- tputc(&c, 1);
- } else {
- break;
- }
- }
- if (len)
- tputc(buf, len);
-}
+/* more random input code */
-void tputc(char *c, int len)
+static void tputc(char *c, int len)
{
uchar ascii = *c;
bool control = ascii < '\x20' || ascii == 0177;
@@ -2290,7 +2277,361 @@ void tputc(char *c, int len)
}
}
-int tresize(int col, int row)
+static void techo(char *buf, int len)
+{
+ for (; len > 0; buf++, len--) {
+ char c = *buf;
+
+ if (c == '\033') { /* escape */
+ tputc("^", 1);
+ tputc("[", 1);
+ } else if (c < '\x20') { /* control code */
+ if (c != '\n' && c != '\r' && c != '\t') {
+ c |= '\x40';
+ tputc("^", 1);
+ }
+ tputc(&c, 1);
+ } else {
+ break;
+ }
+ }
+ if (len)
+ tputc(buf, len);
+}
+
+static char *kmap(KeySym k, uint state)
+{
+ uint mask;
+ 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++) {
+ mask = kp->mask;
+
+ if (kp->k != k)
+ continue;
+
+ if (!match(mask, state))
+ continue;
+
+ if (kp->appkey > 0) {
+ if (!IS_SET(MODE_APPKEYPAD))
+ continue;
+ if (term.numlock && kp->appkey == 2)
+ continue;
+ } else if (kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
+ continue;
+ }
+
+ if ((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
+ (kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR))) {
+ continue;
+ }
+
+ if ((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
+ (kp->crlf > 0 && !IS_SET(MODE_CRLF))) {
+ continue;
+ }
+
+ return kp->s;
+ }
+
+ return NULL;
+}
+
+static void kpress(XEvent *ev)
+{
+ XKeyEvent *e = &ev->xkey;
+ KeySym ksym;
+ char xstr[31], buf[32], *customkey, *cp = buf;
+ int len;
+ Status status;
+ Shortcut *bp;
+
+ if (IS_SET(MODE_KBDLOCK))
+ return;
+
+ len =
+ XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
+ e->state &= ~Mod2Mask;
+ /* 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))) {
+ len = strlen(customkey);
+ memcpy(buf, customkey, len);
+ /* 2. hardcoded (overrides X lookup) */
+ } else {
+ if (len == 0)
+ return;
+
+ if (len == 1 && e->state & Mod1Mask)
+ *cp++ = '\033';
+
+ memcpy(cp, xstr, len);
+ len = cp - buf + len;
+ }
+
+ ttywrite(buf, len);
+ if (IS_SET(MODE_ECHO))
+ techo(buf, len);
+}
+
+static void ttyread(void)
+{
+ static char buf[BUFSIZ];
+ static int buflen = 0;
+ char *ptr;
+ char s[UTF_SIZ];
+ int charsize; /* size of utf8 char in bytes */
+ long utf8c;
+ int ret;
+
+ /* append read bytes to unprocessed bytes */
+ if ((ret = read(cmdfd, buf + buflen, LEN(buf) - buflen)) < 0)
+ die("Couldn't read from shell: %s\n", SERRNO);
+
+ /* process every complete utf8 char */
+ buflen += ret;
+ ptr = buf;
+ while (buflen >= UTF_SIZ || isfullutf8(ptr, buflen)) {
+ charsize = utf8decode(ptr, &utf8c);
+ utf8encode(&utf8c, s);
+ tputc(s, charsize);
+ ptr += charsize;
+ buflen -= charsize;
+ }
+
+ /* keep any uncomplete utf8 char for the next call */
+ memmove(buf, ptr, buflen);
+}
+
+/* Mouse code */
+
+static int x2col(int x)
+{
+ x -= borderpx;
+ x /= xw.cw;
+
+ return LIMIT(x, 0, term.col - 1);
+}
+
+static int y2row(int y)
+{
+ y -= borderpx;
+ y /= xw.ch;
+
+ return LIMIT(y, 0, term.row - 1);
+}
+
+static void getbuttoninfo(XEvent *e)
+{
+ int type;
+ uint state = e->xbutton.state & ~Button1Mask;
+
+ sel.alt = IS_SET(MODE_ALTSCREEN);
+
+ sel.ex = x2col(e->xbutton.x);
+ sel.ey = y2row(e->xbutton.y);
+
+ sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
+ sel.b.y = MIN(sel.by, sel.ey);
+ sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
+ sel.e.y = MAX(sel.by, sel.ey);
+
+ sel.type = SEL_REGULAR;
+ for (type = 1; type < LEN(selmasks); ++type) {
+ if (match(selmasks[type], state)) {
+ sel.type = type;
+ break;
+ }
+ }
+}
+
+static void mousereport(XEvent *e)
+{
+ 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 ob, ox, oy;
+
+ /* from urxvt */
+ if (e->xbutton.type == MotionNotify) {
+ if (!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
+ return;
+ button = ob + 32;
+ ox = x, oy = y;
+ } else if (!IS_SET(MODE_MOUSESGR)
+ && (e->xbutton.type == ButtonRelease
+ || button == AnyButton)) {
+ button = 3;
+ } else {
+ button -= Button1;
+ if (button >= 3)
+ button += 64 - 3;
+ if (e->xbutton.type == ButtonPress) {
+ ob = button;
+ ox = x, oy = y;
+ }
+ }
+
+ button += (state & ShiftMask ? 4 : 0)
+ + (state & Mod4Mask ? 8 : 0)
+ + (state & ControlMask ? 16 : 0);
+
+ len = 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);
+}
+
+static void bpress(XEvent *e)
+{
+ if (IS_SET(MODE_MOUSE)) {
+ mousereport(e);
+ } else if (e->xbutton.button == Button1) {
+ if (sel.bx != -1) {
+ sel.bx = -1;
+ tsetdirt(sel.b.y, sel.e.y);
+ draw();
+ }
+ sel.mode = 1;
+ sel.type = SEL_REGULAR;
+ sel.ex = sel.bx = x2col(e->xbutton.x);
+ sel.ey = sel.by = y2row(e->xbutton.y);
+ } else if (e->xbutton.button == Button4) {
+ ttywrite("\031", 1);
+ } else if (e->xbutton.button == Button5) {
+ ttywrite("\005", 1);
+ }
+}
+
+static void brelease(XEvent *e)
+{
+ struct timeval now;
+
+ if (IS_SET(MODE_MOUSE)) {
+ mousereport(e);
+ return;
+ }
+
+ if (e->xbutton.button == Button2) {
+ selpaste(NULL);
+ } else if (e->xbutton.button == Button1) {
+ sel.mode = 0;
+ getbuttoninfo(e);
+ term.dirty[sel.ey] = 1;
+ if (sel.bx == sel.ex && sel.by == sel.ey) {
+ sel.bx = -1;
+ gettimeofday(&now, NULL);
+
+ if (TIMEDIFF(now, sel.tclick2) <=
+ tripleclicktimeout) {
+ /* triple click on the line */
+ sel.b.x = sel.bx = 0;
+ sel.e.x = sel.ex = term.col;
+ sel.b.y = sel.e.y = sel.ey;
+ selcopy();
+ } else if (TIMEDIFF(now, sel.tclick1) <=
+ doubleclicktimeout) {
+ /* double click to select word */
+ sel.bx = sel.ex;
+ while (sel.bx > 0
+ && term.line[sel.ey][sel.bx -
+ 1].state &
+ GLYPH_SET
+ && term.line[sel.ey][sel.bx -
+ 1].c[0] !=
+ ' ') {
+ sel.bx--;
+ }
+ sel.b.x = sel.bx;
+ while (sel.ex < term.col - 1
+ && term.line[sel.ey][sel.ex +
+ 1].state &
+ GLYPH_SET
+ && term.line[sel.ey][sel.ex +
+ 1].c[0] !=
+ ' ') {
+ sel.ex++;
+ }
+ sel.e.x = sel.ex;
+ sel.b.y = sel.e.y = sel.ey;
+ selcopy();
+ }
+ } else {
+ selcopy();
+ }
+ }
+
+ memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
+ gettimeofday(&sel.tclick1, NULL);
+}
+
+static void bmotion(XEvent *e)
+{
+ int oldey, oldex, oldsby, oldsey;
+
+ if (IS_SET(MODE_MOUSE)) {
+ mousereport(e);
+ return;
+ }
+
+ if (!sel.mode)
+ return;
+
+ oldey = sel.ey;
+ oldex = sel.ex;
+ oldsby = sel.b.y;
+ oldsey = sel.e.y;
+ getbuttoninfo(e);
+
+ if (oldey != sel.ey || oldex != sel.ex) {
+ tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey));
+ }
+}
+
+/* Resizing code */
+
+static void ttyresize(void)
+{
+ struct winsize w;
+
+ w.ws_row = term.row;
+ w.ws_col = term.col;
+ w.ws_xpixel = xw.tw;
+ w.ws_ypixel = xw.th;
+ if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
+ fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
+}
+
+static int tresize(int col, int row)
{
int i, x;
int minrow = MIN(row, term.row);
@@ -2365,7 +2706,7 @@ int tresize(int col, int row)
return (slide > 0);
}
-void xresize(int col, int row)
+static void xresize(int col, int row)
{
xw.tw = MAX(1, col * xw.cw);
xw.th = MAX(1, row * xw.ch);
@@ -2381,12 +2722,108 @@ void xresize(int col, int row)
XftDrawChange(xw.draw, xw.buf);
}
-static inline ushort sixd_to_16bit(int x)
+static void cresize(int width, int height)
{
- return x == 0 ? 0 : 0x3737 + 0x2828 * x;
+ 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 xloadcols(void)
+static void resize(XEvent *e)
+{
+ if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
+ return;
+
+ cresize(e->xconfigure.width, e->xconfigure.height);
+}
+
+/* Start of st */
+
+static void ttynew(void)
+{
+ int m, s;
+ struct winsize w = { term.row, term.col, 0, 0 };
+
+ /* seems to work fine on linux, openbsd and freebsd */
+ if (openpty(&m, &s, NULL, NULL, &w) < 0)
+ die("openpty failed: %s\n", SERRNO);
+
+ switch (pid = fork()) {
+ case -1:
+ die("fork failed\n");
+ break;
+ case 0:
+ setsid(); /* create a new process group */
+ dup2(s, STDIN_FILENO);
+ dup2(s, STDOUT_FILENO);
+ dup2(s, STDERR_FILENO);
+ if (ioctl(s, TIOCSCTTY, NULL) < 0)
+ die("ioctl TIOCSCTTY failed: %s\n", SERRNO);
+ close(s);
+ close(m);
+ execsh();
+ break;
+ default:
+ close(s);
+ cmdfd = m;
+ signal(SIGCHLD, sigchld);
+ if (opt_io) {
+ iofd = (!strcmp(opt_io, "-")) ?
+ STDOUT_FILENO :
+ open(opt_io, O_WRONLY | O_CREAT, 0666);
+ if (iofd < 0) {
+ fprintf(stderr, "Error opening %s:%s\n",
+ opt_io, strerror(errno));
+ }
+ }
+ }
+}
+
+static void tnew(int col, int row)
+{
+ /* set screen size */
+ term.row = row;
+ term.col = col;
+ term.line = xmalloc(term.row * sizeof(Line));
+ term.alt = xmalloc(term.row * sizeof(Line));
+ term.dirty = xmalloc(term.row * sizeof(*term.dirty));
+ term.tabs = xmalloc(term.col * sizeof(*term.tabs));
+
+ for (row = 0; row < term.row; row++) {
+ term.line[row] = xmalloc(term.col * sizeof(Glyph));
+ term.alt[row] = xmalloc(term.col * sizeof(Glyph));
+ term.dirty[row] = 0;
+ }
+
+ term.numlock = 1;
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ /* setup screen */
+ treset();
+}
+
+static void selinit(void)
+{
+ memset(&sel.tclick1, 0, sizeof(sel.tclick1));
+ memset(&sel.tclick2, 0, sizeof(sel.tclick2));
+ sel.mode = 0;
+ sel.bx = -1;
+ sel.clip = NULL;
+ sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+ if (sel.xtarget == None)
+ sel.xtarget = XA_STRING;
+}
+
+static void xloadcols(void)
{
int i, r, g, b;
XRenderColor color = {.alpha = 0xffff };
@@ -2428,62 +2865,7 @@ void xloadcols(void)
}
}
-int xsetcolorname(int x, const char *name)
-{
- XRenderColor color = {.alpha = 0xffff };
- Colour colour;
- if (x < 0 || x > LEN(colorname))
- return -1;
- if (!name) {
- if (16 <= x && x < 16 + 216) {
- int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b =
- (x - 16) % 6;
- color.red = sixd_to_16bit(r);
- color.green = sixd_to_16bit(g);
- color.blue = sixd_to_16bit(b);
- if (!XftColorAllocValue
- (xw.dpy, xw.vis, xw.cmap, &color, &colour))
- return 0; /* something went wrong */
- dc.col[x] = colour;
- return 1;
- } else if (16 + 216 <= x && x < 256) {
- color.red = color.green = color.blue =
- 0x0808 + 0x0a0a * (x - (16 + 216));
- if (!XftColorAllocValue
- (xw.dpy, xw.vis, xw.cmap, &color, &colour))
- return 0; /* something went wrong */
- dc.col[x] = colour;
- return 1;
- } else {
- name = colorname[x];
- }
- }
- if (!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
- return 0;
- dc.col[x] = colour;
- return 1;
-}
-
-void xtermclear(int col1, int row1, int col2, int row2)
-{
- XftDrawRect(xw.draw,
- &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
- borderpx + col1 * xw.cw,
- borderpx + row1 * xw.ch,
- (col2 - col1 + 1) * xw.cw, (row2 - row1 + 1) * xw.ch);
-}
-
-/*
- * Absolute coordinates.
- */
-void xclear(int x1, int y1, int x2, int y2)
-{
- XftDrawRect(xw.draw,
- &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
- x1, y1, x2 - x1, y2 - y1);
-}
-
-void xhints(void)
+static void xhints(void)
{
XClassHint class = { opt_class ? opt_class : termname, termname };
XWMHints wm = {.flags = InputHint,.input = 1 };
@@ -2509,7 +2891,7 @@ void xhints(void)
XFree(sizeh);
}
-int xloadfont(Font *f, FcPattern *pattern)
+static int xloadfont(Font *f, FcPattern *pattern)
{
FcPattern *match;
FcResult result;
@@ -2541,7 +2923,7 @@ int xloadfont(Font *f, FcPattern *pattern)
return 0;
}
-void xloadfonts(char *fontstr, int fontsize)
+static void xloadfonts(char *fontstr, int fontsize)
{
FcPattern *pattern;
FcResult result;
@@ -2605,7 +2987,7 @@ void xloadfonts(char *fontstr, int fontsize)
FcPatternDestroy(pattern);
}
-void xunloadfonts(void)
+static void xunloadfonts(void)
{
int i, ip;
@@ -2635,7 +3017,7 @@ void xunloadfonts(void)
FcFontSetDestroy(dc.ibfont.set);
}
-void xzoom(const Arg *arg)
+static void xzoom(const Arg *arg)
{
xunloadfonts();
xloadfonts(usedfont, usedfontsize + arg->i);
@@ -2643,7 +3025,7 @@ void xzoom(const Arg *arg)
redraw(0);
}
-void xinit(void)
+static void xinit(void)
{
XSetWindowAttributes attrs;
XGCValues gcvalues;
@@ -2752,348 +3134,7 @@ void xinit(void)
XSync(xw.dpy, 0);
}
-void xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen)
-{
- int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
- width = charlen * xw.cw, xp, i;
- int frp, frcflags;
- int u8fl, u8fblen, u8cblen, doesexist;
- char *u8c, *u8fs;
- long u8char;
- Font *font = &dc.font;
- FcResult fcres;
- FcPattern *fcpattern, *fontpattern;
- FcFontSet *fcsets[] = { NULL };
- FcCharSet *fccharset;
- Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
- *temp, revfg, revbg;
- XRenderColor colfg, colbg;
-
- frcflags = FRC_NORMAL;
-
- if (base.mode & ATTR_BOLD) {
- if (BETWEEN(base.fg, 0, 7)) {
- /* basic system colors */
- fg = &dc.col[base.fg + 8];
- } else if (BETWEEN(base.fg, 16, 195)) {
- /* 256 colors */
- fg = &dc.col[base.fg + 36];
- } else if (BETWEEN(base.fg, 232, 251)) {
- /* greyscale */
- fg = &dc.col[base.fg + 4];
- }
- /*
- * Those ranges will not be brightened:
- * 8 - 15 – bright system colors
- * 196 - 231 – highest 256 color cube
- * 252 - 255 – brightest colors in greyscale
- */
- font = &dc.bfont;
- frcflags = FRC_BOLD;
- }
-
- if (base.mode & ATTR_ITALIC) {
- font = &dc.ifont;
- frcflags = FRC_ITALIC;
- }
- if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
- font = &dc.ibfont;
- frcflags = FRC_ITALICBOLD;
- }
-
- if (IS_SET(MODE_REVERSE)) {
- if (fg == &dc.col[defaultfg]) {
- fg = &dc.col[defaultbg];
- } else {
- colfg.red = ~fg->color.red;
- colfg.green = ~fg->color.green;
- colfg.blue = ~fg->color.blue;
- colfg.alpha = fg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
- &revfg);
- fg = &revfg;
- }
-
- if (bg == &dc.col[defaultbg]) {
- bg = &dc.col[defaultfg];
- } else {
- colbg.red = ~bg->color.red;
- colbg.green = ~bg->color.green;
- colbg.blue = ~bg->color.blue;
- colbg.alpha = bg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
- &revbg);
- bg = &revbg;
- }
- }
-
- if (base.mode & ATTR_REVERSE) {
- temp = fg;
- fg = bg;
- bg = temp;
- }
-
- /* Intelligent cleaning up of the borders. */
- if (x == 0) {
- xclear(0, (y == 0) ? 0 : winy, borderpx,
- winy + xw.ch + ((y >= term.row - 1) ? xw.h : 0));
- }
- if (x + charlen >= term.col) {
- xclear(winx + width, (y == 0) ? 0 : winy, xw.w,
- ((y >= term.row - 1) ? xw.h : (winy + xw.ch)));
- }
- if (y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if (y == term.row - 1)
- xclear(winx, winy + xw.ch, winx + width, xw.h);
-
- /* Clean up the region we want to draw to. */
- XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
-
- fcsets[0] = font->set;
- for (xp = winx; bytelen > 0;) {
- /*
- * Search for the range in the to be printed string of glyphs
- * that are in the main font. Then print that range. If
- * some glyph is found that is not in the font, do the
- * fallback dance.
- */
- u8fs = s;
- u8fblen = 0;
- u8fl = 0;
- for (;;) {
- u8c = s;
- u8cblen = utf8decode(s, &u8char);
- s += u8cblen;
- bytelen -= u8cblen;
-
- doesexist =
- XftCharIndex(xw.dpy, font->match, u8char);
- if (!doesexist || bytelen <= 0) {
- if (bytelen <= 0) {
- if (doesexist) {
- u8fl++;
- u8fblen += u8cblen;
- }
- }
-
- if (u8fl > 0) {
- XftDrawStringUtf8(xw.draw, fg,
- font->match, xp,
- winy +
- font->ascent,
- (FcChar8 *) u8fs,
- u8fblen);
- xp += font->width * u8fl;
- }
- break;
- }
-
- u8fl++;
- u8fblen += u8cblen;
- }
- if (doesexist)
- break;
-
- frp = frccur;
- /* Search the font cache. */
- for (i = 0; i < frclen; i++, frp--) {
- if (frp <= 0)
- frp = LEN(frc) - 1;
-
- if (frc[frp].c == u8char
- && frc[frp].flags == frcflags) {
- break;
- }
- }
-
- /* Nothing was found. */
- if (i >= frclen) {
- /*
- * Nothing was found in the cache. Now use
- * some dozen of Fontconfig calls to get the
- * font for one single character.
- */
- fcpattern = FcPatternDuplicate(font->pattern);
- fccharset = FcCharSetCreate();
-
- FcCharSetAddChar(fccharset, u8char);
- FcPatternAddCharSet(fcpattern, FC_CHARSET,
- fccharset);
- FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
-
- FcConfigSubstitute(0, fcpattern, FcMatchPattern);
- FcDefaultSubstitute(fcpattern);
-
- fontpattern = FcFontSetMatch(0, fcsets,
- FcTrue, fcpattern,
- &fcres);
-
- /*
- * Overwrite or create the new cache entry
- * entry.
- */
- frccur++;
- frclen++;
- if (frccur >= LEN(frc))
- frccur = 0;
- if (frclen > LEN(frc)) {
- frclen = LEN(frc);
- XftFontClose(xw.dpy, frc[frccur].font);
- }
-
- frc[frccur].font = XftFontOpenPattern(xw.dpy,
- fontpattern);
- frc[frccur].c = u8char;
- frc[frccur].flags = frcflags;
-
- FcPatternDestroy(fcpattern);
- FcCharSetDestroy(fccharset);
-
- frp = frccur;
- }
-
- XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
- xp, winy + frc[frp].font->ascent,
- (FcChar8 *) u8c, u8cblen);
-
- xp += font->width;
- }
-
- /*
- XftDrawStringUtf8(xw.draw, fg, font->set, winx,
- winy + font->ascent, (FcChar8 *)s, bytelen);
- */
-
- if (base.mode & ATTR_UNDERLINE) {
- XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
- width, 1);
- }
-}
-
-void xdrawcursor(void)
-{
- static int oldx = 0, oldy = 0;
- int sl;
- Glyph g = { {' '}, ATTR_NULL, defaultbg, defaultcs, 0 };
-
- LIMIT(oldx, 0, term.col - 1);
- LIMIT(oldy, 0, term.row - 1);
-
- if (term.line[term.c.y][term.c.x].state & GLYPH_SET)
- memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
-
- /* remove the old cursor */
- if (term.line[oldy][oldx].state & GLYPH_SET) {
- sl = utf8size(term.line[oldy][oldx].c);
- xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx],
- oldx, oldy, 1, sl);
- } else {
- xtermclear(oldx, oldy, oldx, oldy);
- }
-
- /* draw the new one */
- if (!(IS_SET(MODE_HIDE))) {
- if (!(xw.state & WIN_FOCUSED))
- g.bg = defaultucs;
-
- if (IS_SET(MODE_REVERSE))
- g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg =
- defaultfg;
-
- sl = utf8size(g.c);
- xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
- oldx = term.c.x, oldy = term.c.y;
- }
-}
-
-
-void xsettitle(char *p)
-{
- XTextProperty prop;
-
- Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
- &prop);
- XSetWMName(xw.dpy, xw.win, &prop);
-}
-
-void xresettitle(void)
-{
- xsettitle(opt_title ? opt_title : "st");
-}
-
-void redraw(int timeout)
-{
- struct timespec tv = { 0, timeout * 1000 };
-
- tfulldirt();
- draw();
-
- if (timeout > 0) {
- nanosleep(&tv, NULL);
- XSync(xw.dpy, False); /* necessary for a good tput flash */
- }
-}
-
-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 ic, ib, x, y, ox, sl;
- Glyph base, new;
- char buf[DRAW_BUF_SIZ];
- bool ena_sel = sel.bx != -1;
-
- if (sel.alt ^ IS_SET(MODE_ALTSCREEN))
- ena_sel = 0;
-
- 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;
- base = term.line[y][0];
- ic = ib = ox = 0;
- for (x = x1; x < x2; x++) {
- new = term.line[y][x];
- if (ena_sel && *(new.c) && selected(x, y))
- new.mode ^= ATTR_REVERSE;
- if (ib > 0 && (!(new.state & GLYPH_SET)
- || ATTRCMP(base, new)
- || ib >= DRAW_BUF_SIZ - UTF_SIZ)) {
- xdraws(buf, base, ox, y, ic, ib);
- ic = ib = 0;
- }
- if (new.state & GLYPH_SET) {
- if (ib == 0) {
- ox = x;
- base = new;
- }
-
- sl = utf8size(new.c);
- memcpy(buf + ib, new.c, sl);
- ib += sl;
- ++ic;
- }
- }
- if (ib > 0)
- xdraws(buf, base, ox, y, ic, ib);
- }
- xdrawcursor();
-}
-
-void expose(XEvent *ev)
+static void expose(XEvent *ev)
{
XExposeEvent *e = &ev->xexpose;
@@ -3104,7 +3145,7 @@ void expose(XEvent *ev)
redraw(0);
}
-void visibility(XEvent *ev)
+static void visibility(XEvent *ev)
{
XVisibilityEvent *e = &ev->xvisibility;
@@ -3116,22 +3157,12 @@ void visibility(XEvent *ev)
}
}
-void unmap(XEvent *ev)
+static void unmap(XEvent *ev)
{
xw.state &= ~WIN_VISIBLE;
}
-void xseturgency(int add)
-{
- XWMHints *h = XGetWMHints(xw.dpy, xw.win);
-
- h->flags =
- add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
- XSetWMHints(xw.dpy, xw.win, h);
- XFree(h);
-}
-
-void focus(XEvent *ev)
+static void focus(XEvent *ev)
{
XFocusChangeEvent *e = &ev->xfocus;
@@ -3148,120 +3179,12 @@ void focus(XEvent *ev)
}
}
-inline bool match(uint mask, uint state)
-{
- state &= ~(ignoremod);
-
- if (mask == XK_NO_MOD && state)
- return false;
- if (mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
- return false;
- if ((state & mask) != state)
- return false;
- return true;
-}
-
-void numlock(const Arg *dummy)
+static void numlock(const Arg *dummy)
{
term.numlock ^= 1;
}
-char *kmap(KeySym k, uint state)
-{
- uint mask;
- 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++) {
- mask = kp->mask;
-
- if (kp->k != k)
- continue;
-
- if (!match(mask, state))
- continue;
-
- if (kp->appkey > 0) {
- if (!IS_SET(MODE_APPKEYPAD))
- continue;
- if (term.numlock && kp->appkey == 2)
- continue;
- } else if (kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
- continue;
- }
-
- if ((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
- (kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR))) {
- continue;
- }
-
- if ((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
- (kp->crlf > 0 && !IS_SET(MODE_CRLF))) {
- continue;
- }
-
- return kp->s;
- }
-
- return NULL;
-}
-
-void kpress(XEvent *ev)
-{
- XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char xstr[31], buf[32], *customkey, *cp = buf;
- int len;
- Status status;
- Shortcut *bp;
-
- if (IS_SET(MODE_KBDLOCK))
- return;
-
- len =
- XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
- e->state &= ~Mod2Mask;
- /* 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))) {
- len = strlen(customkey);
- memcpy(buf, customkey, len);
- /* 2. hardcoded (overrides X lookup) */
- } else {
- if (len == 0)
- return;
-
- if (len == 1 && e->state & Mod1Mask)
- *cp++ = '\033';
-
- memcpy(cp, xstr, len);
- len = cp - buf + len;
- }
-
- ttywrite(buf, len);
- if (IS_SET(MODE_ECHO))
- techo(buf, len);
-}
-
-
-void cmessage(XEvent *e)
+static void cmessage(XEvent *e)
{
/*
* See xembed specs
@@ -3282,32 +3205,23 @@ void cmessage(XEvent *e)
}
}
-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);
-}
+static void (*handler[LASTEvent]) (XEvent *) = {
+[KeyPress] = kpress,
+ [ClientMessage] = cmessage,
+ [ConfigureNotify] = resize,
+ [VisibilityNotify] = visibility,
+ [UnmapNotify] = unmap,
+ [Expose] = expose,
+ [FocusIn] = focus,
+ [FocusOut] = focus,
+ [MotionNotify] = bmotion,
+ [ButtonPress] = bpress,
+ [ButtonRelease] = brelease,
+ [SelectionClear] = selclear,
+ [SelectionNotify] = selnotify,
+ [SelectionRequest] = selrequest,};
-void run(void)
+static void run(void)
{
XEvent ev;
fd_set rfd;