code:
/* See LICENSE for license details. */
#ifndef st_H
#define st_H

#include <stdint.h>
#include <sys/types.h>
#include <X11/keysym.h>
#include <X11/X.h>

#include <wchar.h>

#include "xevent.h"

/* macros */

#define ATTRCMP(a, b)                                                          \
  ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)

// get pointer to a line.
//
// todo: rewrite the whole history buffer.
// concept:
// 	drop t->line and t->hist
// 	use t->buf instead.
// 	pos from 0 to UINT_MAX.
// 		-> only 2 pointers needed: current pos, and scrolled pos.
// 		fetch and write buffer by limiting to &(HISTSIZE-1).
// 		when scrolling, obviously limit to currentpos & (HISTSIZE-1).
// 		funny enough, overflowing UINT_MAX won't be a problem.
// 	use absolute values in TLINE(line) ( add pos + scroll to line, &(HISTSIZE-1) )
// 	use negative - no, positive, since we need in theory scroll up to UINT_NAX lines -
// 	values for scroll to scroll. scrolling to 0 = pos.

//#define TLINETOBUF( _y ) ( _y+ term->linebufpos &

// get the pointer to a line, depending on scroll
#define TLINE(y)                                                               \
  ((y) < term->scr                                                              \
       ? term->hist[( (y) + term->histindex - term->scr +1 ) & (term->histsize) ]  : term->line[ (y) - term->scr ])
       //? term->hist[( (y) + term->histindex - term->scr +1 ) & (HISTSIZE-1) ]  : term->line[ (y) - term->scr ])

       //? term->hist[(((y) + term->histindex - term->scr + HISTSIZE +1 ) ^ HISTSIZE ) & (HISTSIZE-1) ]  : term->line[(y)-term->scr])

#define ISDELIM(u) (u && wcschr(worddelimiters, u))

// inputmode. switchable via lessmode_toggle
//extern int inputmode;

enum term_mode {
  MODE_WRAP = 1 << 0,
  MODE_INSERT = 1 << 1,
  MODE_ALTSCREEN = 1 << 2,
  MODE_CRLF = 1 << 3,
  MODE_ECHO = 1 << 4,
  MODE_PRINT = 1 << 5,
#ifdef UTF8
  MODE_UTF8 = 1 << 6,
#else
	MODE_UTF8 = 0,
#endif
  MODE_SIXEL = 1 << 7,
	TMODE_HELP = 1 << 8,
};

#ifndef HISTSIZEBITS
// Should be set in config.h
#define HISTSIZEBITS 11
#endif

#if (HISTSIZEBITS>20)
#error You most possibly do not want a history with a length > 1.000.000
#error Either change HISTSIZEBITS accordingly, or edit the sources
#endif

#define HISTSIZE (1<<HISTSIZEBITS)

#define IMODE_HELP 0x04

enum glyph_attribute {
  ATTR_NULL = 0,
  ATTR_BOLD = 1 << 0,
  ATTR_FAINT = 1 << 1,
  ATTR_ITALIC = 1 << 2,
  ATTR_UNDERLINE = 1 << 3,
  ATTR_BLINK = 1 << 4,
  ATTR_REVERSE = 1 << 5,
#ifndef UTF8
  ATTR_WRAP = 1 << 6, // NHIST : usable also at the first column, is not tested.
							 // attr_wrap might be not used neccessarily
  ATTR_STRUCK = 1<<7,
  //ATTR_STRUCK = 0,
 // ATTR_GREEK = 1<<7, // betacode
  ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,

  ATTR_INVISIBLE = 0,

#else
	ATTR_INVISIBLE  = 1 << 6,
  ATTR_STRUCK     = 1 << 7,
  ATTR_WRAP       = 1 << 8,
  ATTR_WIDE       = 1 << 9,
  ATTR_WDUMMY     = 1 << 10,
  ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
#endif
};

enum cursor_movement { CURSOR_SAVE, CURSOR_LOAD };

enum cursor_state {
  CURSOR_DEFAULT = 0,
  CURSOR_WRAPNEXT = 1,
  CURSOR_ORIGIN = 2
};

enum charset {
  CS_GRAPHIC0,
  CS_GRAPHIC1,
  CS_UK,
  CS_USA,
  CS_MULTI,
  CS_GER,
  CS_FIN
};

#ifdef UTF8
typedef uint_least32_t Rune;
#else
typedef unsigned char Rune;
#endif

void tty_send_unicode(const Arg *arg);

#define Glyph _Glyph
typedef struct {
#ifndef UTF8
		union {
				struct {
						unsigned char fg; /* foreground  */
						unsigned char bg; /* background  */
						unsigned char mode; /* attribute flags */ //store newline bit here NHIST
						Rune u;             /* character code */
						// reorder. lowest byte is best
						// to access
				};
				uint32_t intG;
		};
#else
  Rune u;             /* character code */
  ushort mode;      /* attribute flags */
  uint32_t fg;      /* foreground  */
  uint32_t bg;      /* background  */
#endif
} Glyph;

typedef Glyph *Line;

void redraw(void);
void draw(void);

void printscreen(const Arg *);
void printsel(const Arg *);
void toggleprinter(const Arg *);
void showhelp(const Arg *);
void quithelp(const Arg *);
void inverse_screen();

int tisaltscr(void);
void tnew(int, int, uint );
void tresize(int, int);
void ttyhangup(void);
int ttynew(char *, char *, char *, char **);
size_t ttyread(void);
void set_notifmode(int type, KeySym ksym);

int tlinelen(int);

void resettitle(void);

size_t utf8encode(Rune, char *);

/* config.h globals */
extern char *utmp;
extern char *stty_args;
extern char *vtiden;
extern wchar_t *worddelimiters;
extern int allowaltscreen;
extern char *termname;
extern unsigned int tabspaces;

#ifndef UTFXXX
extern unsigned char defaultfg;
extern unsigned char defaultbg;
#else
extern unsigned int defaultfg;
extern unsigned int defaultbg;
#endif

extern int borderpx;
extern int borderperc;

void drawregion(int, int, int, int);

#endif


code:
#include "includes.h"

#include "termdraw.h"
#include "utf8.h"
#include "term.h"

/* macros */

// exclusively in drawregion the real drawing( line per line, with xdrawline )
// of the terminal (buffer) contents (without cursor) is done.
void drawregion(int x1, int y1, int x2, int y2) {
		int y;
		for (y = y1; y < y2; y++) {
				if (!term->dirty[y]) {
						continue;
				}
				term->dirty[y] = 0;
				xdrawline(TLINE(y), x1, y, x2);
		}
				// statusline
		if ( y==term->rows && statusvisible ){
				xdrawline(statusbar, x1, y-1, x2);
		}
}

void draw(void) {
		int cx = term->cursor.x;

		if (!xstartdraw()) {
				return;
		}

		/* adjust cursor position */
		LIMIT(term->ocx, 0, term->cols - 1);
		LIMIT(term->ocy, 0, term->rows - 1);

#ifdef UTF8
		if (term->line[term->ocy][term->ocx].mode & ATTR_WDUMMY) {
				term->ocx--;
		}
		if (term->line[term->cursor.y][cx].mode & ATTR_WDUMMY) {
				cx--;
		}
#endif

		drawregion(0, 0, term->cols, term->rows);
		if (term->scr == 0) {
				xdrawcursor(cx, term->cursor.y, term->line[term->cursor.y][cx], term->ocx, term->ocy,
								term->line[term->ocy][term->ocx]);
		}
		term->ocx = cx, term->ocy = term->cursor.y;
		xfinishdraw();
		xximspot(term->ocx, term->ocy);
}

void redraw(void) {
		tfulldirt();
		draw();
}

int twrite(const utfchar *buf, int buflen, int show_ctrl) {
		Rune u;
		int n;

		dbg("twrite0 buflen: %d buf[0]: %c  show_ctrl: %d", buflen, buf[0], show_ctrl);

#ifdef UTF8
		int charsize = 0;
		for (n = 0; n < buflen; n += charsize) { // misc dfq
				if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
						// process a complete utf8 char
						charsize = utf8decode(buf + n, &u, buflen - n);
						if (charsize == 0)
								break;
				} else  {
						u = buf[n] & 0xFF;
						charsize = 1;
				}
#else
		for (n = 0; n < buflen; n++ ) { // misc dfq
					u = buf[n];
#endif
				dbg("twrite1 %d %c", u, u);
				if (show_ctrl && ISCONTROL(u)) {
						dbg("twrite ISCONTROL %d %c", u, u);
						if (u & 0x80) {
								u &= 0x7f;
								tputc('^');
								tputc('[');
						} else if (u != '\n' && u != '\r' && u != '\t') {
								u ^= 0x40;
								tputc('^');
						}
				}
				tputc(u);
		}
		dbg("ok\n");
		return n;
}

void tputtab(int n) {
		uint x = term->cursor.x;

		if (n > 0) {
				while (x < term->cols && n--) {
						for (++x; x < term->cols && !term->tabs[x]; ++x) {
								/* nothing */
						}
				}
		} else if (n < 0) {
				while (x > 0 && n++) {
						for (--x; x > 0 && !term->tabs[x]; --x) {
								/* nothing */
						}
				}
		}
		term->cursor.x = LIMIT(x, 0, term->cols - 1);
}

void tputc(Rune u) {
		char c[UTF_SIZ];
		int width, len;
		Glyph *gp;
//	if ( u>=0x80 )
//		printf("r: %x\n",u);

		//control = 0; // display binary
#ifndef UTF8
		c[0] = u;
		width = len = 1;
#else
		int control;
		if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
				c[0] = u;
				width = len = 1;
		} else {
				len = utf8encode(u, c);
				control = ISCONTROL(u);
				if (!control && (width = wcwidth(u)) == -1) {
						memcpy(c, "\357\277\275", 4); // UTF_INVALID
						width = 1;
				}
		}
#endif

		if (IS_SET(MODE_PRINT)) {
				tprinter(c, len);
		}

		/*
		 * STR sequence must be checked before anything else
		 * because it uses all following characters until it
		 * receives a ESC, a SUB, a ST or any other C1 control
		 * character.
		 */
		if ( handle_controlchars( u,len,c ) )
			return;

		if (sel.ob.x != -1 && BETWEEN(term->cursor.y, sel.ob.y, sel.oe.y)) {
				selclear();
		}

		gp = &term->line[term->cursor.y][term->cursor.x];
		if (IS_SET(MODE_WRAP) && (term->cursor.state & CURSOR_WRAPNEXT)) {
				gp->mode |= ATTR_WRAP; //misc wrapping here NHIST
				tnewline(1);
				gp = &term->line[term->cursor.y][term->cursor.x];
		}

		if (IS_SET(MODE_INSERT) && term->cursor.x + width < term->cols) {
				memmove(gp + width, gp, (term->cols - term->cursor.x - width) * sizeof(Glyph));
		}

		if (term->cursor.x + width > term->cols ) {
				tnewline(1);  // NHIST
				gp = &term->line[term->cursor.y][term->cursor.x];
		}

//	if ( u>=0x80 )
//		printf("set r: %x\n",u);

		// NHIST
		tsetchar(u, &term->cursor.attr, term->cursor.x, term->cursor.y);

#ifdef UTF8
		if (width == 2) {
				dbg2("tputchar width2: %x %c", gp[0].u, gp[0].u );
				gp->mode |= ATTR_WIDE;
				if (term->cursor.x + 1 < term->cols ) {
						gp[1].u = '\0';
						gp[1].mode = ATTR_WDUMMY;
				}
		}
#endif

		if (term->cursor.x + width < term->cols ) {
				tmoveto(term->cursor.x + width, term->cursor.y);
		} else {
				term->cursor.state |= CURSOR_WRAPNEXT;
		}
}
#if 0
void histputc(utfchar c){
		gp = &term->line[term->cursor.y][term->cursor.x];
		if (IS_SET(MODE_WRAP) && (term->cursor.state & CURSOR_WRAPNEXT)) {
				gp->mode |= ATTR_WRAP;
				tnewline(1);
				gp = &term->line[term->cursor.y][term->cursor.x];
		}

		if (IS_SET(MODE_INSERT) && term->cursor.x + width < term->cols ) {
				memmove(gp + width, gp, (term->cols - term->cursor.x - width) * sizeof(Glyph));
		}

		if (term->cursor.x + width > term->cols ) {
				tnewline(1);
				gp = &term->line[term->cursor.y][term->cursor.x];
		}

		tsetchar(u, &term->cursor.attr, term->cursor.x, term->cursor.y);

#ifdef UTF8
		if (width == 2) {
				dbg2("tputchar width2: %x %c", gp[0].u, gp[0].u );
				gp->mode |= ATTR_WIDE;
				if (term->cursor.x + 1 < term->cols ) {
						gp[1].u = '\0';
						gp[1].mode = ATTR_WDUMMY;
				}
		}
#endif

		if (term->cursor.x + width < term->cols ) {
				tmoveto(term->cursor.x + width, term->cursor.y);
		} else {
				term->cursor.state |= CURSOR_WRAPNEXT;
		}
}
#endif

// put a char onto screen
void tsetchar(Rune u, Glyph *attr, int x, int y) {
#ifndef UTF8
	//if ( u>=0x80 )
	//	printf("r: %x\n",u);
		//printf("tsetchar %d %d %x %x\n",x,y,attr->u,u);
		if ( term->line[y] == 0 ){ // xxx
			fprintf(stderr,"WARNING, NULL %d %d\n",x,y); // shouldn't get here
			return;
		}
		term->dirty[y] = 1;
		term->line[y][x] = *attr;
		term->line[y][x].u = u;
		return;
#else
		static char *vt100_0[62] = {
				/* 0x41 - 0x7e */
				"↑", "↓", "→", "←", "█", "▚", "☃",      /* A - G */
				0,   0,   0,   0,   0,   0,   0,   0,   /* H - O */
				0,   0,   0,   0,   0,   0,   0,   0,   /* P - W */
				0,   0,   0,   0,   0,   0,   0,   " ", /* X - _ */
				"◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */
				"␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */
				"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
				"│", "≤", "≥", "π", "≠", "£", "·",      /* x - ~ */
		};

		/*
		 * The table is proudly stolen from rxvt.
		 */
		if (term->trantbl[term->charset] == CS_GRAPHIC0 &&
						BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
				utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);

		if (term->line[y][x].mode & ATTR_WIDE) {
				dbg2("Attr_wide: %c\n",term->line[y][x].u);
				if (x + 1 < term->cols ) {
						term->line[y][x + 1].u = ' ';
						term->line[y][x + 1].mode &= ~ATTR_WDUMMY;
				}
		} else if (term->line[y][x].mode & ATTR_WDUMMY) {
				dbg2("Attr_dummy: %c\n",term->line[y][x].u);
				term->line[y][x - 1].u = ' ';
				term->line[y][x - 1].mode &= ~ATTR_WIDE;
		}
		term->dirty[y] = 1;
		term->line[y][x] = *attr; //misc optimize here
		term->line[y][x].u = u;
#endif
}

void tclearregion(int x1, int y1, int x2, int y2) {
		int y;

		if (x1 > x2) {
				SWAPint(x1,x2);
		}
		if (y1 > y2) {
				SWAPint(y1,y2);
		}

		LIMIT(x1, 0, term->cols - 1);
		LIMIT(x2, 0, term->cols - 1);
		LIMIT(y1, 0, term->rows - 1);
		LIMIT(y2, 0, term->rows - 1);

		DBG("tclearregion, %d %d %d %d\n",x1,x2,y1,y2);
		selclear(); // only call once.
		//term->cursor.attr.u=' ';

		for (y = y1; y <= y2; y++) {
				DBG("y: %d\n",y);
				term->dirty[y] = 1;
				DBG("y: %d\n",y);
#if 1
//#ifndef UTF8
				//printf("x: %d %p\n", 0, &term->line[y][0] );
				DBG("y: %d, x1: %d, x2: %d\n", y, x1, x2);
				memset32( &term->line[y][x1].intG, term->cursor.attr.intG, (x2-x1) +1 ); // memset64 or comp
				DBG("ok\n");
#else
		Glyph *gp;
		int x;
				//printf("y: %d, x1: %d, x2: %d\n", y, x1, x2); // xxx
				for (x = x1; x <= x2; x++) { //misc copy longs (64bit)or,better: memset. mmx/sse?
						//if (selected(x, y)) { // room for optimization. only ask once, when no selection
						//		selclear();
						//}
					//printf("x: %d %p\n", x, &term->line[y][x] );
						gp = &term->line[y][x];
						if ( !gp ) break; // xxx
						gp->fg = term->cursor.attr.fg;
						gp->bg = term->cursor.attr.bg;
						gp->mode = 0;
						gp->u = ' ';

				}
#endif
		}
}

void tdeletechar(int n) {
		int dst, src, size;
		Glyph *line;

		LIMIT(n, 0, term->cols - term->cursor.x);

		dst = term->cursor.x;
		src = term->cursor.x + n;
		size = term->cols - src;
		line = term->line[term->cursor.y];

		memmove(&line[dst], &line[src], size * sizeof(Glyph));
		tclearregion(term->cols - n, term->cursor.y, term->cols - 1, term->cursor.y);
}

void tinsertblank(int n) {
		int dst, src, size;
		Glyph *line;

		LIMIT(n, 0, term->cols - term->cursor.x);

		dst = term->cursor.x + n;
		src = term->cursor.x;
		size = term->cols - dst;
		line = term->line[term->cursor.y];

		memmove(&line[dst], &line[src], size * sizeof(Glyph));
		tclearregion(src, term->cursor.y, dst - 1, term->cursor.y);
}

void tinsertblankline(int n) {
		if (BETWEEN(term->cursor.y, term->top, term->bot)) {
				tscrolldown(term->cursor.y, n, 0);
		}
}

void tdeleteline(int n) {
		if (BETWEEN(term->cursor.y, term->top, term->bot)) {
				tscrollup(term->cursor.y, n, 0);
		}
}

void tfulldirt(void) { tsetdirt(0, term->rows - 1); }

void tsetdirtattr(int attr) {
		int i, j;

		for (i = 0; i < term->rows - 1; i++) {
				for (j = 0; j < term->cols - 1; j++) {
						if (term->line[i][j].mode & attr) {
								tsetdirt(i, i);
								break;
						}
				}
		}
}

int tattrset(int attr) {
		int i, j;

		for (i = 0; i < term->rows - 1; i++) {
				for (j = 0; j < term->cols - 1; j++) {
					if ( term->line[i] == 0 ){ // xxx
						fprintf(stderr,"WARNING: tattrset NULL: %d %d\n",i,j);
						return ( 0 );
					}
						if (term->line[i][j].mode & attr) {
								return 1;
						}
				}
		}

		return 0;
}

void tsetdirt(int top, int bot) {
		int i;

		LIMIT(top, 0, term->rows - 1);
		LIMIT(bot, 0, term->rows - 1);

		for (i = top; i <= bot; i++) {
				term->dirty[i] = 1;
		}
}

int32_t tdefcolor(int *attr, int *npar, int l) {
		int32_t idx = -1;
		uint r, g, b;

		switch (attr[*npar + 1]) {
				case 2: /* direct color in RGB space */
						if (*npar + 4 >= l) {
								fprintf(stderr, "erresc(38): Incorrect number of parameters (%d)\n",
												*npar);
								break;
						}
						r = attr[*npar + 2];
						g = attr[*npar + 3];
						b = attr[*npar + 4];
						*npar += 4;
						if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) {
								fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", r, g, b);
						} else {
								idx = TRUECOLOR(r, g, b);
						}
						break;
				case 5: /* indexed color */
						if (*npar + 2 >= l) {
								fprintf(stderr, "erresc(38): Incorrect number of parameters (%d)\n",
												*npar);
								break;
						}
						*npar += 2;
						if (!BETWEEN(attr[*npar], 0, 255)) {
								fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]);
						} else {
						//	fprintf(stderr,"color: %d\n",attr[*npar]); //D
								idx = attr[*npar];
						//		printf("idx: %x\n",idx); //D
						}
						break;
				case 0: /* implemented defined (only foreground) */
				case 1: /* transparent */
				case 3: /* direct color in CMY space */
				case 4: /* direct color in CMYK space */
				default:
						fprintf(stderr, "erresc(38): gfx attr %d unknown\n", attr[*npar]);
						break;
		}

		return idx;
}

void tsetattr(int *attr, int l) {
		int i;
		int32_t idx;

		for (i = 0; i < l; i++) {
				switch (attr[i]) {
						case 0:
								term->cursor.attr.mode &=
										~(ATTR_BOLD | ATTR_FAINT | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_BLINK |
														ATTR_REVERSE | ATTR_INVISIBLE | ATTR_STRUCK);
								term->cursor.attr.fg = defaultfg;
								term->cursor.attr.bg = defaultbg;
								break;
						case 1:
								term->cursor.attr.mode |= ATTR_BOLD;
								break;
						case 2:
								term->cursor.attr.mode |= ATTR_FAINT;
								break;
						case 3:
								term->cursor.attr.mode |= ATTR_ITALIC;
								break;
						case 4:
								term->cursor.attr.mode |= ATTR_UNDERLINE;
								break;
						case 5: /* slow blink */
								/* FALLTHROUGH */
						case 6: /* rapid blink */
								term->cursor.attr.mode |= ATTR_BLINK;
								break;
						case 7:
								term->cursor.attr.mode |= ATTR_REVERSE;
								break;
						case 8:
								term->cursor.attr.mode |= ATTR_INVISIBLE;
								break;
						case 9:
								term->cursor.attr.mode |= ATTR_STRUCK;
								break;
						case 21: // double underline
								term->cursor.attr.mode |= ATTR_STRUCK | ATTR_UNDERLINE;
								break;
						case 22:
								term->cursor.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
								break;
						case 23:
								term->cursor.attr.mode &= ~ATTR_ITALIC;
								break;
						case 24:
								term->cursor.attr.mode &= ~ATTR_UNDERLINE;
								break;
						case 25:
								term->cursor.attr.mode &= ~ATTR_BLINK;
								break;
						case 27:
								term->cursor.attr.mode &= ~ATTR_REVERSE;
								break;
						case 28:
								term->cursor.attr.mode &= ~ATTR_INVISIBLE;
								break;
						case 29:
								term->cursor.attr.mode &= ~ATTR_STRUCK;
								break;
						case 38:
								if ((idx = tdefcolor(attr, &i, l)) >= 0) {
										term->cursor.attr.fg = idx;
								}
								break;
						case 39:
								term->cursor.attr.fg = defaultfg;
								break;
						case 48:
								if ((idx = tdefcolor(attr, &i, l)) >= 0) {
										term->cursor.attr.bg = idx;
								}
								break;
						case 49:
								term->cursor.attr.bg = defaultbg;
								break;
						default:
								if (BETWEEN(attr[i], 30, 37)) {
										term->cursor.attr.fg = attr[i] - 30;
								} else if (BETWEEN(attr[i], 40, 47)) {
										term->cursor.attr.bg = attr[i] - 40;
								} else if (BETWEEN(attr[i], 90, 97)) {
										term->cursor.attr.fg = attr[i] - 90 + 8;
								} else if (BETWEEN(attr[i], 100, 107)) {
										term->cursor.attr.bg = attr[i] - 100 + 8;
								} else {
										fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]);
										csidump();
								}
								break;
				}
		}
}

void printscreen(const Arg *arg) { tdump(); }

void toggleprinter(const Arg *arg) { term->mode ^= MODE_PRINT; }

void tdumpline(int n) {
		char buf[UTF_SIZ];
		Glyph *bp, *end;

		bp = &term->line[n][0];
		end = &bp[MIN(tlinelen(n), term->cols ) - 1];
		if (bp != end || bp->u != ' ') {
				for (; bp <= end; ++bp) {
						tprinter(buf, utf8encode(bp->u, buf));
				}
		}
		tprinter("\n", 1);
}

void tdump(void) {
		int i;

		for (i = 0; i < term->rows; ++i) {
				tdumpline(i);
		}
}

repo_name: misc/slterm

license: mit


code:
#ifndef termdraw_h
#define termdraw_h

void ttywrite(const utfchar *, size_t, int);
void tsetdirtattr(int);
int tattrset(int);
int twrite(const utfchar *, int, int);
void tsetdirt(int, int);

void tdeletechar(int);
void tdeleteline(int);
void tinsertblank(int);
void tinsertblankline(int);
void tdumpline(int);
void tdump(void);

void tclearregion(int, int, int, int);

void tfulldirt(void);

void tputtab(int);
void tputc(Rune);
void tsetattr(int *, int);
void tsetchar(Rune, Glyph *, int, int);

#endif


code:
// tty control
//
//

#include "includes.h"
#include "system.h"
#include "scroll.h"
#include "term.h"
#include "tty.h"
#include "debug.h"
#include "termdraw.h"
#include "xevent.h"
#include "xwindow.h"

int iofd = 1;
int cmdfd;

void ttyhangup() {
	/* Send SIGHUP to shell */
	kill(shellpid, SIGHUP);
}

void sendbreak(const Arg *arg) {
	if (tcsendbreak(cmdfd, 0)) {
		perror("Error sending break");
	}
}

void tprinter(char *s, size_t len) {
		if (iofd != -1 && xwrite(iofd, s, len) < 0) {
				perror("Error writing to output file");
				close(iofd);
				iofd = -1;
		}
}

void ttyresize(int tw, int th) {
	struct winsize w;

	w.ws_row = term->rows;
	w.ws_col = term->cols;
	w.ws_xpixel = tw;
	w.ws_ypixel = th;
	if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) {
		fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
	}
}

void stty(char **args) {
	char cmd[_POSIX_ARG_MAX], **p, *q, *s;
	size_t n, siz;

	if ((n = strlen(stty_args)) > sizeof(cmd) - 1) {
		die("incorrect stty parameters\n");
	}
	memcpy(cmd, stty_args, n);
	q = cmd + n;
	siz = sizeof(cmd) - n;
	for (p = args; p && (s = *p); ++p) {
		if ((n = strlen(s)) > siz - 1) {
			die("stty parameter length too long\n");
		}
		*q++ = ' ';
		memcpy(q, s, n);
		q += n;
		siz -= n + 1;
	}
	*q = '\0';
	if (system(cmd) != 0) {
		perror("Couldn't call stty");
	}
}

int ttynew(char *line, char *cmd, char *out, char **args) {
	int m, s;

	if (out) {
		term->mode |= MODE_PRINT;
		iofd = (!strcmp(out, "-")) ? 1 : open(out, O_WRONLY | O_CREAT, 0666);
		if (iofd < 0) {
			fprintf(stderr, "Error opening %s:%s\n", out, strerror(errno));
		}
	}

	if (line) {
		if ((cmdfd = open(line, O_RDWR)) < 0) {
			die("open line '%s' failed: %s\n", line, strerror(errno));
		}
		dup2(cmdfd, 0);
		stty(args);
		return cmdfd;
	}

	/* seems to work fine on linux, openbsd and freebsd */
	if (openpty(&m, &s, NULL, NULL, NULL) < 0) {
		die("openpty failed: %s\n", strerror(errno));
	}

	switch (shellpid = fork()) {
		case -1:
			die("fork failed: %s\n", strerror(errno));
			break;
		case 0:
			close(iofd);
			setsid(); /* create a new process group */
			dup2(s, 0);
			dup2(s, 1);
			dup2(s, 2);
			if (ioctl(s, TIOCSCTTY, NULL) < 0) {
				die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
			}
			close(s);
			close(m);
#ifdef __OpenBSD__
			if (pledge("stdio getpw proc exec", NULL) == -1) {
				die("pledge\n");
			}
#endif
			execsh(cmd, args);
			break;
		default:
#ifdef __OpenBSD__
			if (pledge("stdio rpath tty proc", NULL) == -1) {
				die("pledge\n");
			}
#endif
			close(s);
			cmdfd = m;
			signal(SIGCHLD, sigchld);
			break;
	}
	return cmdfd;
}

size_t ttyread(void) {
	static utfchar buf[BUFSIZ];
	static int buflen = 0;
	int written;
	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", strerror(errno));
	}
	buflen += ret;

	dbg("ttyread, ret: %d, buflen: %d, buf[0] %c", ret, buflen, buf[0]);

	written = twrite(buf, buflen, 0);
	buflen -= written;
	/* keep any uncomplete utf8 char for the next call */
	if (buflen > 0) {
		memmove(buf, buf + written, buflen);
	}

	return ret;
}

// writes to the terminal / shell
void ttywrite(const utfchar *s, size_t n, int may_echo) {
	const utfchar *next;
	Arg arg = (Arg){.i = term->scr};

	// don't scroll on new output, when in lessmode.
	if ( !(inputmode & MODE_LESS) )
		kscrolldown(&arg);

	dbg("ttywrite %d %x %c", n, s[0], s[0]);
	if (may_echo && IS_SET(MODE_ECHO)) {
		dbg("t1\n");
		twrite(s, n, 1);
	}

	if (!IS_SET(MODE_CRLF)) {
		dbg("t2\n");
		ttywriteraw(s, n);
		return;
	}

	dbg("ttywrite2 %d %x %c\n", n, s[0], s[0]);
	/* This is similar to how the kernel handles ONLCR for ttys */
	while (n > 0) {
		dbg("ttywrite3 %d %x %c\n", n, s[0], s[0]);
		if (*s == '\r') {
			next = s + 1;
			ttywriteraw((uchar*)"\r\n", 2);
		} else {
			next = memchr(s, '\r', n);
			DEFAULT(next, s + n);
			ttywriteraw(s, next - s);
		}
		n -= next - s;
		s = next;
	}
}

void ttywriteraw(const utfchar *s, size_t n) {
	fd_set wfd, rfd;
	ssize_t r;
	size_t lim = 256;

	dbg("ttywriteraw n: %d s[0]: %c\n", n, s[0]);

	/*
	 * Remember that we are using a pty, which might be a modem line.
	 * Writing too much will clog the line. That's why we are doing this
	 * dance.
	 * FIXME: Migrate the world to Plan 9.
	 */
	while (n > 0) {
		FD_ZERO(&wfd);
		FD_ZERO(&rfd);
		FD_SET(cmdfd, &wfd);
		FD_SET(cmdfd, &rfd);

		dbg("ttywriteraw while n: %d s[0]: %c\n", n, s[0]);
		/* Check if we can write. */
		if (pselect(cmdfd + 1, &rfd, &wfd, NULL, NULL, NULL) < 0) {
			if (errno == EINTR) {
				continue;
			}
			die("select failed: %s\n", strerror(errno));
		}
		if (FD_ISSET(cmdfd, &wfd)) {
			/*
			 * Only write the bytes written by ttywrite() or the
			 * default of 256. This seems to be a reasonable value
			 * for a serial line. Bigger values might clog the I/O.
			 */
			if ((r = write(cmdfd, s, (n < lim) ? n : lim)) < 0) {
				goto write_error;
			}
			dbg("ttywriteraw  n: %d s[0]: %c lim: %d  r: %d", n, s[0], lim, r);
			if (r < n) {
				/*
				 * We weren't able to write out everything.
				 * This means the buffer is getting full
				 * again. Empty it.
				 */
				if (n < lim) {
					lim = ttyread();
				}
				n -= r;
				s += r;
			} else {
				/* All bytes have been written. */
				break;
			}
		}
		if (FD_ISSET(cmdfd, &rfd)) {
			lim = ttyread();
		}
	}
	return;

write_error:
	die("write error on tty: %s\n", strerror(errno));
}


code:
#ifndef stTTY_H
#define stTTY_H

extern char *stty_args;

extern int iofd;
extern int cmdfd;

void ttyresize(int, int);
void stty(char **);
void sigchld(int);
void ttywriteraw(const utfchar *, size_t);
void sendbreak(const Arg *);
void tprinter(char *s, size_t len);

#endif


code:
#include <sys/types.h>

#include "utf8.h"
#include "term.h"

#ifdef UTF8
static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
#else
static uchar utfbyte[UTF_SIZ + 4] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 4] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 4] = {0, 0, 0x80, 0x0, 0x0};
static Rune utfmax[UTF_SIZ + 4] = {0xFF, 0x7F, 0xFF, 0xFF, 0xFF};
#endif

size_t utf8validate(Rune *u, size_t i) {
		if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) {
				*u = UTF_INVALID;
		}
		for (i = 1; *u > utfmax[i]; ++i) {
		}

		return i;
}

char utf8encodebyte(Rune u, size_t i) { return utfbyte[i] | (u & ~utfmask[i]); }

#ifdef UTF8
char *utf8strchr(char *s, Rune u) {
		Rune r;
		size_t i, j, len;

		len = strlen(s);
		for (i = 0, j = 0; i < len; i += j) {
				if (!(j = utf8decode(&s[i], &r, len - i)))
						break;
				if (r == u)
						return &(s[i]);
		}

		return NULL;
}
#endif

size_t utf8decode(const char *c, Rune *u, size_t clen) {
		size_t i, j, len, type;
		Rune udecoded;

		*u = UTF_INVALID;
		if (!clen) {
				return 0;
		}
		udecoded = utf8decodebyte(c[0], &len);
		if (!BETWEEN(len, 1, UTF_SIZ)) {
				return 1;
		}
		for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
				udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
				if (type != 0) {
						return j;
				}
		}
		if (j < len) {
				return 0;
		}
		*u = udecoded;
		utf8validate(u, len);

		return len;
}

Rune utf8decodebyte(char c, size_t *i) {
		for (*i = 0; *i < LEN(utfmask); ++(*i)) {
				if (((uchar)c & utfmask[*i]) == utfbyte[*i]) {
						return (uchar)c & ~utfmask[*i];
				}
		}

		return 0;
}

size_t utf8encode(Rune u, char *c) {
#ifndef UTF8
		c[0] = u;
		return 1;
#else
		size_t len, i;

		len = utf8validate(&u, 0);
		if (len > UTF_SIZ) {
				return 0;
		}

		for (i = len - 1; i != 0; --i) {
				c[i] = utf8encodebyte(u, 0);
				u >>= 6;
		}
		c[0] = utf8encodebyte(u, len);

		return len;
#endif
}


code:
#ifndef utf8_h
#define utf8_h

#include <stddef.h>

#ifdef UTF8
typedef uint_least32_t Rune;
#else
typedef unsigned char Rune;
#endif

size_t utf8decode(const char *c, Rune *u, size_t clen);
size_t utf8encode(Rune u, char *c);
size_t utf8validate(Rune *u, size_t i);
char utf8encodebyte(Rune u, size_t i);
Rune utf8decodebyte(char c, size_t *i);

#endif


code:
// clipboard handling
//

// todo: Ctrl+Alt+y : copy output of last command to clipboard
//  			-> in lessmode: copy output of the current retmark
//       ... : copy current screen to clipboard
//     make utf8 conversion switchable?

#include "xclipboard.h"

XSelection xsel;

#ifdef UTF8_CLIPBOARD

// utf8 conversion ( again, simplified, misc147 )
// converts from the current charmap to utf8
uint to_utf8( uchar* obuf, const uchar* ibuf ){
	uchar *ob = obuf;
	while ( *ibuf ){
		//printf("c: %d\n",(uint) (*ibuf));
		if ( *ibuf <128 ){ // char < 128
			*obuf = *ibuf;
			obuf++;
		} else {
			uint uc = charmap_convert( (uchar)*ibuf, 0 );
			//printf("%d\n",uc);
			int p = 2;

			//if ( !valid_uc_utf8(uc) )
			//	goto ERR_UTF8;
			// invalid values (rfc3629
			// sparing that. We do only have the unicode points of our chartable

			char initb=(char)0xc0;
			if ( uc >= 65536 ){
				obuf[3] = (uc & 0x3f) | 0x80;
				initb >>= (char)1;
				uc >>= 6;
				p++;
			}
			if ( uc >= 2048 ){
				obuf[2] = (uc & 0x3f) | 0x80;
				initb >>= (char)1;
				uc >>= 6;
				p++;
			}
			obuf[1] = (uc & 0x3f) | 0x80;
			obuf[0] = (uc>>6) | initb;
			obuf += p;
		}
		ibuf++;
	}
	*obuf = 0;
	return( obuf-ob );
}

// converts from utf8 to the current charmap,
// unsupported chars are left as utf8
uint from_utf8( uchar* obuf, const uchar* buf, uint len ){
	uchar *ob = obuf;
	int a = 0;
	while ( a<len ){
		if ( (a+1<len) && ( (buf[a+1] & 0xc0) == 0x80 ) ){
			// is utf8, convert
			int tmp = a;
			uint uc = ( (buf[a] & 0x1f) << 6 ) | (buf[a+1] & 0x3f);
			if ( (buf[a] & 0xe0) == 0xc0 ){ // initial Byte 2Byte utf8
				a++;
			} else if ( (a+2<len) && ( (buf[a+2] & 0xc0) == 0x80 ) ){
				uc = ( uc << 6 ) | (buf[a+2] & 0x3f);
				if ( (buf[a] & 0xf0) == 0xe0 ){ // initial Byte 3Byte utf8
					a+=2;
				} else if ( (a+3<len) && ( (buf[a+3] & 0xc0) == 0x80 ) ){
					if ( (buf[a] & 0xf8) == 0xf0 ){ // 4byte
						uc = ((uc<<6) & 0x1FFFFF ) | ( buf[a+3] & 0x3f );
						a+=3;
					}
				}
			} else { // either end of buf, no utf8, or utf8 error
				uc = 0;
			}
			// need to check, keep utf8, if char is not present
			*obuf = unicode_to_charmap( uc );
			if ( *obuf == 0 ){
				while( tmp <= a ){
					*obuf++ = buf[tmp];
					tmp++;
				}
			} else {
				obuf++;
			}
		} else {
			*obuf++ = buf[a];
		}
		a++;
	}
	*obuf = 0;

	return(obuf - ob);
}
#endif

void setsel(char *str, Time t) {
	if (!str)
		return;

	free(xsel.primary);
	xsel.primary = str;

	XSetSelectionOwner(xwin.dpy, XA_PRIMARY, xwin.win, t);
	if (XGetSelectionOwner(xwin.dpy, XA_PRIMARY) != xwin.win)
		selclear();

	clipcopy(NULL);
}

void xsetsel(char *str) { setsel(str, CurrentTime); }

void clipcopy(const Arg *dummy) {
	Atom clipboard;

	free(xsel.clipboard);
	xsel.clipboard = NULL;

	if (xsel.primary != NULL) {
		//printf( "clipcopy: %s\n",xsel.primary);
		//convert to utf8
		xsel.clipboard = xstrdup(xsel.primary);
	// convert to utf8 here? ( case of charmaps changes.. )
		//xsel.clipboard = xmalloc( strlen( xsel.primary) * 4 + 4 );
		//to_utf8( xsel.clipboard, xsel.primary );

		clipboard = XInternAtom(xwin.dpy, "CLIPBOARD", 0);
		XSetSelectionOwner(xwin.dpy, clipboard, xwin.win, CurrentTime);
	}
}

void clippaste(const Arg *dummy) {
	Atom clipboard;

	clipboard = XInternAtom(xwin.dpy, "CLIPBOARD", 0);
	XConvertSelection(xwin.dpy, clipboard, xsel.xtarget, clipboard, xwin.win,
			CurrentTime);
}

void selpaste(const Arg *dummy) {
	XConvertSelection(xwin.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, xwin.win,
			CurrentTime);
}

void xclipcopy(void) { clipcopy(NULL); }

void selclear_(XEvent *e) { selclear(); }

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(xwin.dpy, "TARGETS", 0);
	if (xsre->target == xa_targets) {
		/* respond with the supported type */
		string = xsel.xtarget;
		XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32,
				PropModeReplace, (uchar *)&string, 1);
		xev.property = xsre->property;
	} else if (xsre->target == xsel.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(xwin.dpy, "CLIPBOARD", 0);
		if (xsre->selection == XA_PRIMARY) {
			seltext = xsel.primary;
		} else if (xsre->selection == clipboard) {
			seltext = xsel.clipboard;
		} else {
			fprintf(stderr, "Unhandled clipboard selection 0x%lx\n", xsre->selection);
			return;
		}
		if (seltext != NULL) {

#ifdef UTF8_CLIPBOARD
			int len = strlen(seltext);
			{
				uchar buf[len*4+4];
				int blen = to_utf8( buf, (uchar*)seltext );
			//	printf("seltext: %s\n",seltext);
			//	printf("seltext utf8: %s\n",buf);
			XChangeProperty(xsre->display, xsre->requestor, xsre->property,
					xsre->target, 8, PropModeReplace,
					 (uchar*)buf, blen );
					//(uchar *)seltext, strlen(seltext));
			xev.property = xsre->property;
			}
#else
			XChangeProperty(xsre->display, xsre->requestor, xsre->property,
					xsre->target, 8, PropModeReplace,
					(uchar *)seltext, strlen(seltext));
			xev.property = xsre->property;
#endif

		}
	}

	/* 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 selnotify(XEvent *e) {
	ulong nitems, ofs, rem;
	int format;
	uchar *data, *last, *repl;
	Atom type, incratom, property = None;

	incratom = XInternAtom(xwin.dpy, "INCR", 0);

	ofs = 0;
	if (e->type == SelectionNotify)
		property = e->xselection.property;
	else if (e->type == PropertyNotify)
		property = e->xproperty.atom;

	if (property == None)
		return;

	do {
		if (XGetWindowProperty(xwin.dpy, xwin.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(xwin.attrs.event_mask, 0, PropertyChangeMask);
			XChangeWindowAttributes(xwin.dpy, xwin.win, CWEventMask, &xwin.attrs);
		}

		if (type == incratom) {
			/*
			 * Activate the PropertyNotify events so we receive
			 * when the selection owner does send us the next
			 * chunk of data.
			 */
			MODBIT(xwin.attrs.event_mask, 1, PropertyChangeMask);
			XChangeWindowAttributes(xwin.dpy, xwin.win, CWEventMask, &xwin.attrs);

			/*
			 * Deleting the property is the transfer start signal.
			 */
			XDeleteProperty(xwin.dpy, xwin.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((utfchar*)"\033[200~", 6, 0);

#ifdef UTF8_CLIPBOARD
		//printf("Paste: %s  \nsize: %d\n",data,last-data);
		//convert from utf8 / different charmap here
			{
				uchar buf[last-data];
				int len = from_utf8( buf, data, last-data );
				ttywrite(buf, len, 1);
			}
#else
		ttywrite((char *)data, nitems * format / 8, 1);
#endif

		if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
			ttywrite((utfchar*)"\033[201~", 6, 0);
		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(xwin.dpy, xwin.win, (int)property);
}

void printsel(const Arg *arg) { tdumpsel(); }

void tdumpsel(void) {
	char *ptr;

	if ((ptr = getsel())) {
		tprinter(ptr, strlen(ptr));
		free(ptr);
	}
}


code:
#pragma once

// clipboard
typedef struct {
		Atom xtarget;
		char *primary, *clipboard;
		struct timespec tclick1;
		struct timespec tclick2;
} XSelection;

extern XSelection xsel;

//clipboard events
void selnotify(XEvent *);
void selclear_(XEvent *);
void selrequest(XEvent *);

void clipcopy(const Arg *);
void clippaste(const Arg *);
void selpaste(const Arg *);


code:
// cursor drawing and
// cursor color functions
//

#include "xcursor.h"

int _xsetcursor(int cursor, int attr) {
	DEFAULT(cursor, 1);
	if (!BETWEEN(cursor, 0, 12))
		return 1;
	twin.cursor = cursor;
	twin.cursor_attr[0] = attr;
	return 0;
}

int xgetcursor(){
	return(twin.cursor);
}

Color *getcursorcolor( Glyph g, int cx, int cy ){
	Color *col;
	Color drawcol;
	if ( g.bg == defaultbg ){
		col = &dc.color_array[defaultcs];
	} else {
		if ( !( col = getcachecolor( 2, &g, twin.mode ) ) ){
			col = xdrawglyph(g, cx, cy); // unneccessary, but need the bg color

			// invert bgcolor
			XRenderColor csc;
			//#define ASB(c) csc.c = 0xff-col->color.c //~col->color.c
#define ASB(c) csc.c = ~col->color.c
			ASB(red);ASB(green);ASB(blue);
#undef ASB
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &csc, &drawcol);
			col = cachecolor(2,&g,twin.mode,&drawcol);
			//col = &drawcol;
		}

	}

	return(col);
}

void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) {
	Color drawcol;
	static int focusinx, focusiny;
	uchar tmp;
	Color *col = 0;

	// hide cursor in lessmode
	if (inputmode&MODE_LESS && !(twin.mode & MODE_KBDSELECT))
		return;

	//printf("xdrawcursor: %d %d, %d %d, %d\n",cx,cy,ox,oy, term->scr);

	/* remove the old cursor */
	if (selected(ox, oy))
		og.mode ^= ATTR_REVERSE;

	xdrawglyph(og, ox, oy);

	/*
	 * Select the right color for the right mode.
	 */
/*
#ifdef UTF8
	g.mode &= ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK | ATTR_WIDE;
#else
	g.mode &= ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK;
#endif

	if (IS_SET(MODE_REVERSE)) {
		g.mode |= ATTR_REVERSE;
		g.bg = defaultfg;
		if (selected(cx, cy)) {
			drawcol = dc.color_array[defaultrcs];
			g.fg = defaultbg;
		} else {
			drawcol = dc.color_array[defaultrcs];
			g.fg = defaultbg;
		}
	} else {
		if (selected(cx, cy)) {
			g.fg = defaultfg;
			g.bg = defaultrcs;
		} else {
			g.fg = defaultbg;
			g.bg = defaultcs;
		}
		drawcol = dc.color_array[g.bg];
	}
	*/

	/* draw text cursor */
	if (IS_SET(MODE_FOCUSED)) {

		switch (twin.cursor) {
			case 7: /* st extension: snowman (U+2603) */
				// g.u = 0x2603;
				if ( twin.cursor_attr[0] )
					g.u = twin.cursor_attr[0];
				else
					g.u = 'X';
				g.bg = 9;
			case 0: /* Blinking Block */
			case 1: /* Blinking Block */ // doesnt work out. I dislike blinking anyways.
												  // Thats a feature!
				//g.mode |= ATTR_BLINK | ATTR_REVERSE;
				//term->cursor.attr.mode |= ATTR_BLINK;
				//printf("blc\n");
				//term->cursor.attr.mode |= ATTR_BLINK;
				//tsetdirtattr(ATTR_BLINK);
				//xdrawglyph(g, cx, cy);
				//break;
			case 2: /* Steady Block */
			//if ( g.bg == defaultbg ){
			//	g.bg = defaultcs;
			//} else {
				//if ( (twin.cursor==2) || !( twin.mode & MODE_BLINK )){
					tmp = g.fg;
					g.fg = g.bg;
					g.bg = tmp;
				//}
			//}
				xdrawglyph(g, cx, cy);
				break;

			case 3: /* Blinking Underline */
			case 4: /* Steady Underline */
			case 8: // double underline
				if ( focusinx == cx && focusiny == cy ) { // highlight cursor on focusin
					g.bg = 208;
					g.fg = 4;
					xdrawglyph(g, cx, cy);

					drawcol = dc.color_array[1];

					// underline
					drawcol = dc.color_array[defaultcs];
					XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch - cursorthickness, twin.cw,
							cursorthickness);

				} else { // draw cursor as underline
					focusinx=focusiny=0;
					//drawcol = dc.color_array[defaultcs];

					col = getcursorcolor( g, cx, cy );

					if ( twin.cursor == 8 ){ // double underline
						XftDrawRect(xwin.draw, col,
							twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch - 1, twin.cw, 1);
						XftDrawRect(xwin.draw, col,
							twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch - 3, twin.cw, 1);
					} else { // underline
						XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch - cursorthickness, twin.cw,
							cursorthickness);
					}

				}
				break;

			case 5: /* Blinking bar */
			case 6: /* Steady bar */
				col = getcursorcolor( g, cx, cy );

				XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
						twin.vborderpx + (cy) * twin.ch, cursorthickness, twin.ch);
				break;

			case 9: // empty block, unfilled
					col = getcursorcolor( g, cx, cy );

					// upper line
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + cy * twin.ch, twin.cw - 1, 1);

					// lines at sides
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + cy * twin.ch, 1, twin.ch);

					XftDrawRect(xwin.draw, col, twin.hborderpx + (cx + 1) * twin.cw - 1,
							twin.vborderpx + cy * twin.ch, 1, twin.ch);

					// lower line
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch -1, twin.cw, 1);

					break;

			case 11: //
			case 10: // bar with two lines at the sides
					col = getcursorcolor( g, cx, cy );
					// lower cursor part
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
								(twin.vborderpx + cy * twin.ch )+(twin.ch*12)/16, 1, twin.ch-twin.ch*12/16 );

					XftDrawRect(xwin.draw, col, twin.hborderpx + (cx + 1) * twin.cw - 1,
								(twin.vborderpx + cy * twin.ch )+(twin.ch*12)/16, 1, twin.ch-twin.ch*12/16 );

					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + (cy + 1) * twin.ch -1, twin.cw, 1);

					if ( twin.cursor == 10 )
						break;

			case 12:
					if ( !col ) col = getcursorcolor( g, cx, cy );
					// upper line
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
							twin.vborderpx + cy * twin.ch, twin.cw - 1, 1);

					// lines at sides
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw,
						twin.vborderpx + cy * twin.ch, 1, twin.ch-twin.ch*12/16);
					XftDrawRect(xwin.draw, col, twin.hborderpx + (cx + 1) * twin.cw - 1,
						twin.vborderpx + cy * twin.ch, 1, twin.ch-twin.ch*12/16);
					break;

			case 13:  // unfinished
					col = getcursorcolor( g, cx, cy );
				// a cross
					XftDrawRect(xwin.draw, col, twin.hborderpx + cx * twin.cw + twin.cw/2 ,
					twin.vborderpx + cy * twin.ch+3, 1, twin.ch - twin.ch*12/16);
					XftDrawRect(xwin.draw, col, (twin.hborderpx + cx * twin.cw) + 2,
					twin.vborderpx + cy * twin.ch + (twin.ch/2)-1, twin.ch - twin.ch*12/16, 1);
				break;

		}
	} else { // window hasn't the focus.
				//g.fg = unfocusedrcs;
		drawcol = dc.color_array[unfocusedrcs];
		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + cx * twin.cw,
				twin.vborderpx + cy * twin.ch, twin.cw - 1, 1);
		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + cx * twin.cw,
				twin.vborderpx + cy * twin.ch, 1, twin.ch-twin.ch/16*12);
		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + (cx + 1) * twin.cw - 1,
				twin.vborderpx + cy * twin.ch, 1, twin.ch-twin.ch/16*12);

		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + cx * twin.cw,
				(twin.vborderpx + cy * twin.ch )+(twin.ch/16)*12, 1, twin.ch-twin.ch/16*12);
		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + (cx + 1) * twin.cw - 1,
				twin.vborderpx + cy * twin.ch + (twin.ch/16)*12, 1, twin.ch-twin.ch/16*12);
		XftDrawRect(xwin.draw, &drawcol, twin.hborderpx + cx * twin.cw,
				twin.vborderpx + (cy + 1) * twin.ch -1, twin.cw, 1);
		focusinx = cx;
		focusiny = cy;
	}
}


code:
// cursor drawing and
// cursor color functions

#pragma once

int _xsetcursor(int cursor, int attr);
#define __xsetcursor(_a,_b,...) _xsetcursor(_a,_b)
#define xsetcursor(_cursor,...) __xsetcursor(_cursor,__VA_OPT__(__VA_ARGS__,) 0 )

int xgetcursor();

Color *getcursorcolor( Glyph g, int cx, int cy );

void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og);


code:
#include "xdraw.h"

#include "xwindow.h"

DC dc;

/*
 * Absolute coordinates.
 */
void xclear(int x1, int y1, int x2, int y2) {
	XftDrawRect(xwin.draw, &dc.color_array[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
			x1, y1, x2 - x1, y2 - y1);
}

void xdrawline(Line line, int x1, int y1, int x2) {
	int i, x, ox, numspecs;
	Glyph base, new;
	XftGlyphFontSpec *specs = xwin.specbuf;
#ifndef UTF8
	numspecs = noutf8_xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
#else
	numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
#endif

	i = ox = 0;
	for (x = x1; x < x2 && i < numspecs; x++) {
		new = line[x];
#ifdef UTF8
		if (new.mode == ATTR_WDUMMY)
			continue;
#endif
		if (selected(x, y1))
			new.mode ^= ATTR_REVERSE;
		if (i > 0 && ATTRCMP(base, new)) {
			xdrawglyphfontspecs(specs, base, i, ox, y1);
			specs += i;
			numspecs -= i;
			i = 0;
		}
		if (i == 0) {
			ox = x;
			base = new;
		}
		i++;
	}
	if (i > 0)
		xdrawglyphfontspecs(specs, base, i, ox, y1);
}

Color* xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,
		int x, int y) {
#ifdef UTF8
	int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
#else
	int charlen = len;// * ((base.mode & ATTR_WIDE) ? 2 : 1);
#endif
	int winx = twin.hborderpx + x * twin.cw, winy = twin.vborderpx + y * twin.ch,
		 width = charlen * twin.cw;
	Color *fg, *bg, revfg, revbg, truefg, truebg, *cltmp;
	XRenderColor colfg, colbg;
	XRectangle r;
	int fgcache = 0, bgcache = 0;

	//get colors from cache, if present
	if (  !(twin.mode & MODE_FOCUSED) || IS_SET(MODE_REVERSE) ){
		if ( ( bg =getcachecolor( 0, &base,twin.mode ) ) )
			bgcache = 1;
		if ( ( fg =getcachecolor( 1, &base,twin.mode ) ) )
			fgcache = 1;
	} else {
		if ( base.mode& (ATTR_BOLD|ATTR_FAINT) ){
			if ( base.fg>15 )
				if ( ( fg =getcachecolor( 1, &base,twin.mode ) ) )
					fgcache = 1;
		}
	}

	if ( !bgcache ){
		if ( base.bg < 16 ){ //misc use 16 color bg table
			bg = &dc.bgcolors[base.bg];
		} else {
			if (IS_TRUECOL(base.bg)) { // Always false, if compiled without UTF8
				colbg.alpha = 0xffff;
				colbg.green = TRUEGREEN(base.bg);
				colbg.red = TRUERED(base.bg);
				colbg.blue = TRUEBLUE(base.bg);
				XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &truebg);
				bg = &truebg;
			} else {
				bg = &dc.color_array[base.bg];
			}
		}
	}

	if ( !fgcache ){
		if ( base.fg < 8 ){
			//printf("<c %d>an",base.fg);
			int fi = 0;
			if ((base.mode & ATTR_FAINT) == ATTR_FAINT )
				fi = 2;
			if ((base.mode & ATTR_BOLD) == ATTR_BOLD )
				fi++;

			fg = &dc.colortable[base.fg+8*fi];
		} else if ( base.fg < 16 ) {
			fg = &dc.colortable[base.fg];
		} else {
			// old code
			if (IS_TRUECOL(base.fg)) {
				//printf("Truecolor\n");
				colfg.alpha = 0xffff;
				colfg.red = TRUERED(base.fg);
				colfg.green = TRUEGREEN(base.fg);
				colfg.blue = TRUEBLUE(base.fg);
				XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &truefg);
				fg = &truefg;
			} else {
				fg = &dc.color_array[base.fg];
			}

			//#define cbold(c) colfg.c = fg->color.c + boldf <= 0xffff ? fg->color.c+boldf : fg->color.c ;
#define cbold(c) colfg.c = ((fg->color.c + fg->color.c/2) | fg->color.c ) & 0xffff
			//#define cbold(c) colfg.c = fg->color.c > 250?  : fg->color.c+ 5;
			//#define cfaint(c) colfg.c = fg->color.c - (fg->color.c/2)
#define cfaint(c) colfg.c = fg->color.c - fg->color.c/2; // prev: - .c/4
																			//
			/* Change basic system colors [0-7] to bright system colors [8-15] */
			if ((base.mode & ATTR_BOLD) == ATTR_BOLD ){
				if ( BETWEEN(base.fg, 0, 7)){
					fg = &dc.color_array[base.fg + 8];
				} else {
					//if ( ( (base.mode & ATTR_BOLD) == ATTR_BOLD ) && !BETWEEN(base.fg,0,15) )
					cbold(red); //= fg->color.red * 2;
					cbold(green); //= fg->color.green * 2;
					cbold(blue); //= fg->color.blue +  2;
					colfg.alpha = fg->color.alpha;
					XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
					fg = &revfg;
				}
			}

			// also BOLD|FAINT
			if ( (base.mode & ATTR_FAINT) == ATTR_FAINT ) { //&& !BETWEEN(base.fg,0,15) )
				cfaint(red); //= fg->color.red * 2;
				cfaint(green); //= fg->color.green * 2;
				cfaint(blue); //= fg->color.blue +  2;
				colfg.alpha = fg->color.alpha;//2;
				XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
				fg = &revfg;
			}
		}
	}

#if 1

#define CLFA 24000
	// Change colors on focusout
	if ( !(twin.mode & MODE_FOCUSED) ){
		/*colfg.red = fg->color.red / 2;
		  colfg.green = fg->color.green / 4 * 3;
		  colfg.blue = fg->color.blue / 4 * 3;*/
		if ( !fgcache && (fg->color.blue > CLFA) && (fg->color.red < CLFA) && (fg->color.green < CLFA) ){
			colfg.red = fg->color.red +13000;
			colfg.green = fg->color.green +13000;
			colfg.blue = fg->color.blue;
			colfg.alpha = fg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
			fg = &revfg;
		}
		if ( !bgcache && (bg->color.blue > CLFA) && (bg->color.red < CLFA) && (bg->color.green < CLFA) ){
			colbg.red = bg->color.red +CLFA;
			colbg.green = bg->color.green +CLFA;
			colbg.blue = bg->color.blue;
			colbg.alpha = bg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &revbg);
			bg = &revbg;
		}
	}

#endif

	if (IS_SET(MODE_REVERSE)) { // inverse mode (Ctrl+Shift+I)
		if ( !fgcache ){
			if ( fg == &dc.color_array[defaultfg]) {
				fg = &dc.color_array[defaultbg];
			} else {
				colfg.alpha = fg->color.alpha;
#define AS(c) colfg.c = ~fg->color.c
				FOR_RGB(AS);
#undef AS

				XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
				fg = &revfg;
			}
		}

		if ( !bgcache ){
			if ( bg == &dc.color_array[defaultbg]) {
				bg = &dc.color_array[defaultfg];
			} else {
				colbg.alpha = bg->color.alpha;
#define ASB(c) colbg.c = ~bg->color.c
				FOR_RGB(ASB);
#undef ASB
				XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &revbg);
				bg = &revbg;
			}
		}
	}

	// reverse background and foreground colors, Attribute 7
	if (base.mode & ATTR_REVERSE) {
			cltmp = bg;
			bg = fg;
			fg = cltmp;
	}

	if (base.mode & ATTR_INVISIBLE)
		fg = bg; // top secret

	if (base.mode & ATTR_BLINK && twin.mode & MODE_BLINK){
		if ( base.mode & ATTR_REVERSE ){ // blink by reversing colors
			cltmp = bg;
			bg = fg;
			fg = cltmp;
		} else fg = bg; // blink
	}

	/* Intelligent cleaning up of the borders. */
	if (x == 0) {
		xclear(0, (y == 0) ? 0 : winy, twin.vborderpx,
				winy + twin.ch +
				((winy + twin.ch >= twin.vborderpx + twin.th) ? twin.h : 0));
	}
	if (winx + width >= twin.hborderpx + twin.tw) {
		xclear(
				winx + width, (y == 0) ? 0 : winy, twin.w,
				((winy + twin.ch >= twin.vborderpx + twin.th) ? twin.h : (winy + twin.ch)));
	}
	if (y == 0)
		xclear(winx, 0, winx + width, twin.hborderpx);
	if (winy + twin.ch >= twin.vborderpx + twin.th)
		xclear(winx, winy + twin.ch, winx + width, twin.h);

	/* Clean up the region we want to draw to. */
	XftDrawRect(xwin.draw, bg, winx, winy, width, twin.ch);

	/* Set the clip region because Xft is sometimes dirty. */
	r.x = 0;
	r.y = 0;
	r.height = twin.ch;
	r.width = width;
	XftDrawSetClipRectangles(xwin.draw, winx, winy, &r, 1);

	//printf("spec %x\n",specs->glyph);
	/* Render the glyphs. */
	XftDrawGlyphFontSpec(xwin.draw, fg, specs, len);

	/* Render underline and strikethrough. */
	if (base.mode & ATTR_UNDERLINE) {
		XftDrawRect(xwin.draw, fg, winx, winy + dc.font.ascent + 1, width, 1);
		if (base.mode & ATTR_STRUCK) { // struck and underline - double underline
			XftDrawRect(xwin.draw, fg, winx, winy + dc.font.ascent + 3, width, 1);
		}
	} else {
		if (base.mode & ATTR_STRUCK) {
			XftDrawRect(xwin.draw, fg, winx, winy + 5*dc.font.ascent /8, width, 1);
			//XftDrawRect(xwin.draw, fg, winx, winy + 2 * dc.font.ascent / 3, width, 1);
		}
	}

	/* Reset clip to none. */
	XftDrawSetClip(xwin.draw, 0);

	// free colors, if allocated and not in one of the tables
	if ( !fgcache && (fg == &revfg || fg == &revbg) && fg!=bg )
		cachecolor( base.mode & ATTR_REVERSE? 0:1, &base, twin.mode, fg );
			//XftColorFree(xwin.dpy, xwin.vis, xwin.cmap, &revfg);

	if ( !bgcache && (bg == &revbg || bg == &revfg) )
		cachecolor( base.mode & ATTR_REVERSE? 1:0, &base, twin.mode, bg );
		//	XftColorFree(xwin.dpy, xwin.vis, xwin.cmap, &revbg);

	return(bg);
}

Color* xdrawglyph(Glyph g, int x, int y) {
	int numspecs;
	XftGlyphFontSpec spec;
#ifndef UTF8
	numspecs = noutf8_xmakeglyphfontspecs(&spec, &g, 1, x, y);
#else
	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
#endif
	return( xdrawglyphfontspecs(&spec, g, numspecs, x, y) );
}

int xstartdraw(void) { return IS_SET(MODE_VISIBLE); }

void xfinishdraw(void) {
	XCopyArea(xwin.dpy, xwin.buf, xwin.win, dc.gc, 0, 0, twin.w, twin.h, 0, 0);
	XSetForeground(xwin.dpy, dc.gc,
			dc.color_array[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
}


code:
#ifndef xdraw_h
#define xdraw_h

// Returns the used background color
Color* xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
// Returns the used background color
Color* xdrawglyph(Glyph, int, int);
void xclear(int, int, int, int);

int xstartdraw(void);

void xdrawcursor(int, int, Glyph, int, int, Glyph);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);

#endif


code:
// input event handling
//
//

#include "xevent.h"

/* the configuration is in config.h (generated from config.h.in) */
#include "config.h"

// The callbacks for the different Events are egistered here.
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,
	/*
	 * Uncomment if you want the selection to disappear when you select
	 * something different in another window.
	 */
	/*	[SelectionClear] = selclear_, */
	[SelectionNotify] = selnotify,
	/*
	 * PropertyNotify is only turned on when there is some INCR transfer
	 * happening for the selection retrieval.
	 */
	[PropertyNotify] = propnotify,
	[SelectionRequest] = selrequest,
};

// the main event loop
void run() {
	XEvent ev;
	int w = twin.w, h = twin.h;
	fd_set rfd;
	int xfd = XConnectionNumber(xwin.dpy), xev, blinkset = 0, dodraw = 0;
	int ttyfd;
	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
	long deltatime;

	/* Waiting for window mapping */
	do {
		XNextEvent(xwin.dpy, &ev);
		/*
		 * This XFilterEvent call is required because of XOpenIM. It
		 * does filter out the key event and some client message for
		 * the input method too.
		 */
		if (XFilterEvent(&ev, None))
			continue;
		if (ev.type == ConfigureNotify) {
			w = ev.xconfigure.width;
			h = ev.xconfigure.height;
		}
	} while (ev.type != MapNotify);

	// also start shell in ttynew. args are global. somewhere.
	ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
	cresize(w, h);

	clock_gettime(CLOCK_MONOTONIC, &last);
	lastblink = last;

	xev = (1<<actionfps_shift);
	while (1) { // main loop
	//for (xev = (1<<actionfps_shift);;) { // main loop
		FD_ZERO(&rfd);
		FD_SET(ttyfd, &rfd);
		FD_SET(xfd, &rfd);

		if (pselect(MAX(xfd, ttyfd) + 1, &rfd, NULL, NULL, tv, NULL) < 0) {
			if (errno == EINTR) //? xevent ?
				continue;
			die("select failed: %s\n", strerror(errno));
		}
		if (FD_ISSET(ttyfd, &rfd)) {
			ttyread();
			if (blinktimeout) {
				blinkset = tattrset(ATTR_BLINK);
				if (!blinkset)
					MODBIT(twin.mode, 0, MODE_BLINK);
			}
		}

		if (FD_ISSET(xfd, &rfd))
			xev = (1<<actionfps_shift);

		clock_gettime(CLOCK_MONOTONIC, &now);
		drawtimeout.tv_sec = 0;
		drawtimeout.tv_nsec = 1000000000 >> xfps_shift;
		//drawtimeout.tv_nsec = (1000 * 1E6) / xfps;
		tv = &drawtimeout;

		dodraw = 0;
		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
			tsetdirtattr(ATTR_BLINK);
			twin.mode ^= MODE_BLINK; // read in xdraw.
			lastblink = now;
			dodraw = 1;
		}
		deltatime = TIMEDIFF(now, last);
		if (deltatime > (1000 >> (xev ? xfps_shift : actionfps_shift) ) ) {
			dodraw = 1;
			last = now;
		}

		if (dodraw) {
			while (XPending(xwin.dpy)) {
				XNextEvent(xwin.dpy, &ev);
				if (XFilterEvent(&ev, None))
					continue;
				if (handler[ev.type]) // process x events
					(handler[ev.type])(&ev);
			}

			draw();
			XFlush(xwin.dpy);

			if (xev && !FD_ISSET(xfd, &rfd))
				xev--;
			if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
				if (blinkset) {
					if (TIMEDIFF(now, lastblink) > blinktimeout) {
						drawtimeout.tv_nsec = 1000;
					} else {
						drawtimeout.tv_nsec =
							((long)(blinktimeout - TIMEDIFF(now, lastblink)) << 20);
						//(1E6 * (blinktimeout - TIMEDIFF(now, lastblink)));
					}
					// drawtimeout.tv_nsec = ( drawtimeout.tv_nsec - ( drawtimeout.tv_sec = (drawtimeout.tv_nsec >> 9 )) >>9) ; //
					//drawtimeout.tv_sec = drawtimeout.tv_nsec / 1E9; // Thats bad misc
					//drawtimeout.tv_nsec %= (long)1E9; // Better don't divide
					//
					// better shift ? division is the most expensive operation.
					// Anyways. doesn't seem to be a big difference. I'm however wondering.
					// More strange. E.g. dividing by 512 prevents blinking???
					// Ok. I confused exponential and hexadecimal. It's exponential.
					// 1E9 equals 1.000.000.000
					// 2^30 might be close enough

					drawtimeout.tv_sec = (drawtimeout.tv_nsec >> 30); // ..
					drawtimeout.tv_nsec -= (long)(drawtimeout.tv_sec << 30);
				} else {
					tv = NULL;
				}
			}
		}
	}
}
void toggle_winmode(int flag) { twin.mode ^= flag; }

void ttysend(const Arg *arg) { ttywrite((utfchar*)arg->s, strlen(arg->s), 1); }

void resize(XEvent *e) {
	if (e->xconfigure.width == twin.w && e->xconfigure.height == twin.h)
		return;

	cresize(e->xconfigure.width, e->xconfigure.height);
}

void cmessage(XEvent *e) {
	/*
	 * See xembed specs
	 *  http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
	 */
	if (e->xclient.message_type == xwin.xembed && e->xclient.format == 32) {
		if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
			twin.mode |= MODE_FOCUSED;
			xseturgency(0);
		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
			twin.mode &= ~MODE_FOCUSED;
		}
	} else if (e->xclient.data.l[0] == xwin.wmdeletewin) {
		ttyhangup();
		exit(0);
	}
}

#define FCB 4
void focus(XEvent *ev) {
	XFocusChangeEvent *e = &ev->xfocus;

	if (e->mode == NotifyGrab)
		return;
	static int colorsaved = 0;
	static Color tmp;
	if ( !colorsaved ){
		tmp = dc.color_array[FCB];
		colorsaved = 1;
	}

	if (ev->type == FocusIn) {
		if ( !( twin.mode & MODE_FOCUSED) ){
			twin.mode |= MODE_FOCUSED;
			XSetICFocus(xwin.xic);
			xseturgency(0);
			if (IS_SET(MODE_FOCUS))
				ttywrite((utfchar*)"\033[I", 3, 0);
			statusbar_focusin();
			dc.color_array[FCB] = tmp;
			redraw();
		}

	} else { // focus out
		if ( ( twin.mode & MODE_FOCUSED) ){
			twin.mode &= ~MODE_FOCUSED;
			XUnsetICFocus(xwin.xic);
			if (IS_SET(MODE_FOCUS))
				ttywrite((utfchar*)"\033[O", 3, 0);
			statusbar_focusout();
			dc.color_array[FCB] = dc.color_array[7];
			redraw();
		}

	}
}

void expose(XEvent *ev) { redraw(); }

void visibility(XEvent *ev) {
	XVisibilityEvent *e = &ev->xvisibility;

	MODBIT(twin.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE);
}

void unmap(XEvent *ev) { twin.mode &= ~MODE_VISIBLE; }

void propnotify(XEvent *e) {
	XPropertyEvent *xpev;
	Atom clipboard = XInternAtom(xwin.dpy, "CLIPBOARD", 0);

	xpev = &e->xproperty;
	if (xpev->state == PropertyNewValue &&
			(xpev->atom == XA_PRIMARY || xpev->atom == clipboard)) {
		selnotify(e);
	}
}


code:
#ifndef input_h
#define input_h
#include <X11/Xlib.h>

extern void (*handler[LASTEvent])(XEvent *);

//void tty_send_unicode(const Arg *arg);

/* XEMBED messages */
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5

// the main event loop
void run();

// callbacks
//void temp(const Arg *);

// event handling

// xwindow related
void expose(XEvent *);
void visibility(XEvent *);
void unmap(XEvent *);
void cmessage(XEvent *);
void resize(XEvent *);
void focus(XEvent *);
void propnotify(XEvent *);

#endif


code:
// keyboard handling

// inputmode. switchable via lessmode_toggle GLBLMARK
int inputmode = 1;
int help_storedinputmode = 0;

int match(uint mask, uint state) {
	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
}

int kmap(KeySym k, uint state) {
	Key *kp;
	int i;
	//KeySym k2 = k;

	dbg("Key: %d %c\n", k,k);
	/* Check for mapped keys out of X11 function keys. */
	for (i = 0; i < LEN(mappedkeys); i++) { //? misc.
														 // Better compare first with a bitfield,
														 // by the or'ed mapped keys
		if (mappedkeys[i] == k)
			break;
	}

	if (i == LEN(mappedkeys)) { // no mapped key
		KeySym tk = k;
			if ( tk>0x1000000 )
				tk-= 0x1000000; // convert to unicode

		if ((tk & 0xFFFF) < 0xFD00) { // No control/function/mod key
											  // dbg ("Here\n");// -> no multibyte key. no match. ret.
			dbg("Key2: %x %c\n", tk,tk);
			/* Check for mapped keys out of X11 function keys. */
			if ( (tk > 0x80) && ( tk<0xf000 ) ){ //unicode translation to current codepage needed
				if ( tk >= UNITABLE ){ // greater than the cached table
					for ( uchar a = 0; a<128; a++ ){
						if ( codepage[selected_codepage][a] == tk ){
							ttywrite( &a,1,1 );
							return(1);
							//k = codepage[selected_codepage][a];
							//goto CONT;
						}
					}
				} else {
					if ( uni_to_cp[tk] ){
						dbg("uni to cp: %x\n",uni_to_cp[tk]);
						ttywrite( &uni_to_cp[tk],1,1 );
						return(1);
						//k = uni_to_cp[tk];
						//goto CONT;
					}
				}
				ttywrite((utfchar*)"~",1,1); // drop utf8 here
			}

			return(0);
		}
	}
//CONT:

// key ist the key binding array (!) defined in config.h. man.
// doesn't seem useful to sort, normally a key is within the array, when
// arrived here.
	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 (IS_SET(MODE_NUMLOCK) && kp->appkey == 2)
			continue;

		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
			continue;

		ttywrite((utfchar*)kp->s, kp->len, 1);
		return(1); // abort further handling
	}
//	if ( k2 != k ){ // translated from unicode to codepage
//		ttywrite((uchar*)&k, 1, 1);
//		return(1);
//	}
	//printf("looking for: %x\n",kp->k);
	return(0);
}

// sort the shortcuts,
// to be able to abort scanning through all of them for each key
// gets callen at startup
void sort_shortcuts(){
	// Do a stable sort. Elements of the same
	// keysym value stay in the same order.
	// This is callen only once at startup. for about 100 elements.
#define SIZE (sizeof(shortcuts)/sizeof(Shortcut))
	//uint cp[SIZE];
	KeySym bing; //
	uint pt = 0;  //

	for ( int a = 0; a<SIZE; a++ )
		if ( !shortcuts[a].keysym )
			die("Invalid configuration, shortcut number %d, keysym is 0\n",a+1);

	 while (1){
		bing = UINT_MAX;
		for ( int a = pt; a<SIZE; a++ ){
			if ( shortcuts[a].keysym < bing   )
				bing = shortcuts[a].keysym;
		}
		if ( bing == UINT_MAX )
			break;
		for ( int a = pt; a<SIZE; a++ )
			if ( bing == shortcuts[a].keysym ){
				Shortcut tmp;
				memcpy(&tmp,shortcuts+a,sizeof(Shortcut));
				memcpy(shortcuts+a,shortcuts+pt,sizeof(Shortcut));
				memcpy(shortcuts+pt,&tmp,sizeof(Shortcut));
				/*char *l1 = (char*)(shortcuts+a), *l2= (char*)(shortcuts+pt);
				while( l1<(char*)(shortcuts+a)+sizeof(Shortcut) ){
				asm("XXXXX:");
				asm("lea %0,%%ecx\n"
				    "lea %1,%%eax\n"
						//"xor %%rax,%%rcx\nxor %%rcx,%%rax\nxor %%rax,%%rcx\n"
					"mov %%ecx,%1\n"
					"mov %%eax,%0\n":
					"+m"(l1), "+m"(l2) : : "cc", "memory", "rcx", "rax" );
					*/
				/*	*l1^=*l2;
					*l2^=*l1;
					*l1^=*l2;
					l1++; l2++;
				} */ // doesnt work. ??? :( finally. my processor is faulty.
					  // (misc 24) - there seems to be a bug with the order of instruction execution
					  // did have more trouble, also with rep mov et al
				pt++;
			}
	};

//	Shortcut tmp[SIZE];
//	memcpy( tmp, shortcuts, sizeof(shortcuts) );

//	for ( int a = 0; a<SIZE; a++ )
//		memcpy( shortcuts+a, tmp+cp[a], sizeof(Shortcut) );

#if 0
	 printf("=== sort_shortcuts\n");
	for ( int a = 0; a<SIZE; a++ ){
		printf("%d %x  \n",a,shortcuts[a].keysym);
	}
#endif

#undef SIZE
}

// Keystrokes are handled here.
void kpress(XEvent *ev) {
	XKeyEvent *e = &ev->xkey;
	KeySym ksym;
	unsigned char buf[32];
	int len;
	Rune c;
	Status status;
	Shortcut *bp;

	if (IS_SET(MODE_KBDLOCK))
		return;

	len = XmbLookupString(xwin.xic, e, (char*)buf, sizeof buf, &ksym, &status);

	if (IS_SET(MODE_KBDSELECT)) {
		if (match(XK_NO_MOD, e->state) || (XK_Shift_L | XK_Shift_R) & e->state)
			twin.mode ^= trt_kbdselect(ksym, (char*)buf, len);
		return;
	}

	if ( IS_SET( MODE_ENTERSTRING ) ){
		statusbar_kpress( &ksym, (char*)buf );
		return;
	}

	dbg("key: %x, keycode: %x, state: %x\n",ksym, e->keycode, e->state );

	// handle return, add retmark
	if ( ( ksym == XK_Return ) && (term->scr==0) && ( inputmode == MODE_REGULAR ) && !( twin.mode & MODE_KBDSELECT ) ){
		//if ( (!IS_SET(MODE_ALTSCREEN)) && ( ksym == XK_Return ) ){
		set_retmark();
	}

	/* 1. shortcuts */
	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
		 if ( ksym < bp->keysym ){  // bp->keysym > ksym
			break;
		}

		if ( (( ksym == bp->keysym ) || ( bp->keysym == ALL_KEYS )) &&
				match(bp->mod, e->state) &&
				(bp->inputmode & inputmode)) {

			bp->func(&(bp->arg));
			return;
		}
	}

	if ( term->mode & TMODE_HELP ) // in the help browser. Only shortcuts used
											 //if ( inputmode & MODE_HELP )
		return;

	/* 2. keys to translate, defined in config.h */
	if (kmap(ksym, e->state)) {
		//ttywrite(customkey, strlen(customkey), 1);
		return;
	}

	dbg("Key2: %d %c, state:%x, mod1: %x, len %d\n", ksym, ksym, e->state,
			Mod1Mask, len);
	/* 3. composed string from input method */
	if (len == 0)
		return;
	if (len == 1 && e->state & Mod1Mask) {
		dbg("K\n");
		if (IS_SET(MODE_8BIT)) {
			if (*buf < 0177) {
				c = *buf | 0x80;
				len = utf8encode(c, (char*)buf);
			}
		} else {
			buf[1] = buf[0];
			buf[0] = '\033';
			len = 2;
		}
	}
	ttywrite(buf, len, 1);
}

void numlock(const Arg *dummy) {
	twin.mode ^= MODE_NUMLOCK;
}

/*
void temp(const Arg *dummy){
	for ( int a = 0; a<128; a++){//2190
			  //cpe4002a[a] = a+0x238a;
	}
} */

// does nothing. Aborts shortcut scanning and key processing
void dummy( const Arg *a){
}

void dump_terminfo( const Arg *a){
#ifdef INCLUDETERMINFO
				ttywrite((utfchar*)slterm_terminfo, strlen(slterm_terminfo),1 );
#endif
}


code:
// keyboard input handling.

/* types used in config.h */
typedef struct {
		unsigned int mod;
		KeySym keysym;
		void (*func)(const Arg *);
		const Arg arg;
		unsigned int inputmode;
} Shortcut;

typedef struct {
		KeySym k;  // this is unsigned int (32) here
		unsigned int mask;
		char *s;
		unsigned char len;
		/* three-valued logic variables: 0 indifferent, 1 on, -1 off */
		signed char appkey;    /* application keypad */
		signed char appcursor; /* application cursor */
} Key;

// save different inputmodes
extern int inputmode;
extern int help_storedinputmode;

/* X modifiers */
#define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0
#define XK_SWITCH_MOD (1 << 13)

int kmap(KeySym k, unsigned int state);
void numlock(const Arg *);
void kpress(XEvent *ev);

int match(unsigned int mask, unsigned int state);

// callbacks . Used in config.h
void ttysend(const Arg *);

void dummy( const Arg *a);
void dump_terminfo( const Arg *a);


code:
// mouse handling
void mousereport(XEvent *e) {
	static int oldbutton = 3; /* button event on startup: 3 = release */

	int len, x = evcol(e), y = evrow(e), button = e->xbutton.button,
		 state = e->xbutton.state;
	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((utfchar*)buf, len, 0);
}

int mouseaction(XEvent *e, uint release) {
	MouseShortcut *ms;

	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
		if (ms->release == release && ms->button == e->xbutton.button &&
				(!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
				(match(ms->mod, e->xbutton.state) || /* exact or forced */
				 match(ms->mod, e->xbutton.state & ~forcemousemod))) {
			ms->func(&(ms->arg));
			return 1;
		}
	}

	return 0;
}

void bpress(XEvent *e) {
	struct timespec now;
	int snap;

	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
		mousereport(e);
		return;
	}

	if (mouseaction(e, 0))
		return;

	if (e->xbutton.button == Button1) {
		/*
		 * If the user clicks below predefined timeouts specific
		 * snapping behaviour is exposed.
		 */
		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 {
			snap = 0;
		}
		xsel.tclick2 = xsel.tclick1;
		xsel.tclick1 = now;

		selstart(evcol(e), evrow(e), snap);
	}
}

void brelease(XEvent *e) {
	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
		mousereport(e);
		return;
	}

	//	if (mouseaction(e, 1))
	//		return;

	if (e->xbutton.button == Button2)
		clippaste(NULL);
	else if (e->xbutton.button == Button1)
		mousesel(e, 1);
}

void bmotion(XEvent *e) {
	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
		mousereport(e);
		return;
	}

	mousesel(e, 0);
}

int evcol(XEvent *e) {
	int x = e->xbutton.x - twin.hborderpx;
	LIMIT(x, 0, twin.tw - 1);
	return x / twin.cw;
}

int evrow(XEvent *e) {
	int y = e->xbutton.y - twin.vborderpx;
	LIMIT(y, 0, twin.th - 1);
	return y / twin.ch;
}


code:
// mouse events handling
typedef struct {
		unsigned int mod;
		unsigned int button;
		void (*func)(const Arg *);
		const Arg arg;
		unsigned int release;
		int altscrn; /* 0: don't care,  -1: not alt screen,  1: alt screen */
} MouseShortcut;

// event handling

int mouseaction(XEvent *, unsigned int);
void brelease(XEvent *);
void bpress(XEvent *);
void bmotion(XEvent *);
void mousereport(XEvent *);

int evcol(XEvent *);
int evrow(XEvent *);


code:
/* See LICENSE for license details. */
#include "includes.h"

#include "term.h"
#include "xwindow.h"
#include "fonts.h"
#include "mem.h"
#include "scroll.h"
#include "selection.h"
#include "xevent.h"
#include "tty.h"
#include "system.h"
#include "compile.h"

//#define ENABLE_DEBUG 5
#include "debug.h"

#ifdef XRESOURCES
/* Xresources preferences */
enum resource_type { STRING = 0, INTEGER = 1, FLOAT = 2 };

typedef struct {
	char *name;
	enum resource_type type;
	void *dst;
} ResourcePref;
#endif

#include "config.h"

/* macros */
#ifdef IS_SET
#undef IS_SET
#endif
// (!) is redefined, with different definitions (termmode,winmode,..)
#define IS_SET(flag) ((twin.mode & (flag)) != 0)

int xgeommasktogravity(int);
void ximopen(Display *);
void ximinstantiate(Display *, XPointer, XPointer);
void ximdestroy(XIM, XPointer, XPointer);
void xinit(int, int);
void xresize(int, int);
void xsetenv(void);
void xseturgency(int);

void resettitle(void) { xsettitle(NULL); }

void cresize(int width, int height) {
	int col, row;

	if (width != 0)
		twin.w = width;
	if (height != 0)
		twin.h = height;

	col = (twin.w - 2 * borderpx) / twin.cw;
	row = (twin.h - 2 * borderpx) / twin.ch;
	col = MAX(1, col);
	row = MAX(1, row);

	twin.hborderpx = (twin.w - col * twin.cw) / 2;
	twin.vborderpx = (twin.h - row * twin.ch) / 2;

	tresize(col, row);
	xresize(col, row);
	ttyresize(twin.tw, twin.th);
}

void xresize(int col, int row) {
	twin.tw = col * twin.cw;
	twin.th = row * twin.ch;

	XFreePixmap(xwin.dpy, xwin.buf);
	xwin.buf =
		XCreatePixmap(xwin.dpy, xwin.win, twin.w, twin.h, DefaultDepth(xwin.dpy, xwin.scr));
	XftDrawChange(xwin.draw, xwin.buf);
	xclear(0, 0, twin.w, twin.h);

	/* resize to new width */
	xwin.specbuf = xrealloc(xwin.specbuf, col * sizeof(GlyphFontSpec));

	updatestatus();
}

void xhints(void) {
#ifdef XRESOURCES
	XClassHint class = {opt_name ? opt_name : "slterm", opt_class ? opt_class : "Slterm"};
#else
	XClassHint class = {opt_name ? opt_name : termname,
		opt_class ? opt_class : termname};
#endif

	XWMHints wm = {.flags = InputHint, .input = 1};
	XSizeHints *sizeh;

	sizeh = XAllocSizeHints();

	sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
	sizeh->height = twin.h;
	sizeh->width = twin.w;
	sizeh->height_inc = 1;
	sizeh->width_inc = 1;
	sizeh->base_height = 2 * borderpx;
	sizeh->base_width = 2 * borderpx;
	sizeh->min_height = twin.ch + 2 * borderpx;
	sizeh->min_width = twin.cw + 2 * borderpx;
	if (xwin.isfixed) {
		sizeh->flags |= PMaxSize;
		sizeh->min_width = sizeh->max_width = twin.w;
		sizeh->min_height = sizeh->max_height = twin.h;
	}
	if (xwin.gm & (XValue | YValue)) {
		sizeh->flags |= USPosition | PWinGravity;
		sizeh->x = xwin.l;
		sizeh->y = xwin.t;
		sizeh->win_gravity = xgeommasktogravity(xwin.gm);
	}

	XSetWMProperties(xwin.dpy, xwin.win, NULL, NULL, NULL, 0, sizeh, &wm, &class);
	XFree(sizeh);
}

int xgeommasktogravity(int mask) {
	switch (mask & (XNegative | YNegative)) {
		case 0:
			return NorthWestGravity;
		case XNegative:
			return NorthEastGravity;
		case YNegative:
			return SouthWestGravity;
	}

	return SouthEastGravity;
}
void ximopen(Display *dpy) {
	XIMCallback destroy = {.client_data = NULL, .callback = ximdestroy};

	if ((xwin.xim = XOpenIM(xwin.dpy, NULL, NULL, NULL)) == NULL) {
		XSetLocaleModifiers("@im=local");
		if ((xwin.xim = XOpenIM(xwin.dpy, NULL, NULL, NULL)) == NULL) {
			XSetLocaleModifiers("@im=");
			if ((xwin.xim = XOpenIM(xwin.dpy, NULL, NULL, NULL)) == NULL)
				die("XOpenIM failed. Could not open input device.\n");
		}
	}
	if (XSetIMValues(xwin.xim, XNDestroyCallback, &destroy, NULL) != NULL)
		die("XSetIMValues failed. Could not set input method value.\n");
	xwin.xic = XCreateIC(xwin.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
			XNClientWindow, xwin.win, XNFocusWindow, xwin.win, NULL);
	if (xwin.xic == NULL)
		die("XCreateIC failed. Could not obtain input method.\n");
}

void ximinstantiate(Display *dpy, XPointer client, XPointer call) {
	ximopen(dpy);
	XUnregisterIMInstantiateCallback(xwin.dpy, NULL, NULL, NULL, ximinstantiate,
			NULL);
}

void ximdestroy(XIM xim, XPointer client, XPointer call) {
	xwin.xim = NULL;
	XRegisterIMInstantiateCallback(xwin.dpy, NULL, NULL, NULL, ximinstantiate,
			NULL);
}

void xinit(int cols, int rows) {
	XGCValues gcvalues;
	Cursor cursor;
	Window parent;
	pid_t thispid = getpid();
	XColor xmousefg, xmousebg;

#ifndef XRESOURCES
	if (!(xwin.dpy = XOpenDisplay(NULL)))
		die("can't open display\n");
#endif

	xwin.scr = XDefaultScreen(xwin.dpy);
	xwin.vis = XDefaultVisual(xwin.dpy, xwin.scr);

	/* font */
	if (!FcInit())
		die("could not init fontconfig.\n");

	//usedfont = (opt_font == NULL) ? regular_font : opt_font;
	xloadfonts(0);

	/* colors */
	xwin.cmap = XDefaultColormap(xwin.dpy, xwin.scr);
	xloadcolors();

	/* adjust fixed window geometry */
	twin.w = 2 * twin.hborderpx + cols * twin.cw;
	twin.h = 2 * twin.vborderpx + rows * twin.ch;
	if (xwin.gm & XNegative)
		xwin.l += DisplayWidth(xwin.dpy, xwin.scr) - twin.w - 2;
	if (xwin.gm & YNegative)
		xwin.t += DisplayHeight(xwin.dpy, xwin.scr) - twin.h - 2;

	/* Events */
	xwin.attrs.background_pixel = dc.color_array[defaultbg].pixel;
	xwin.attrs.border_pixel = dc.color_array[defaultbg].pixel;
	xwin.attrs.bit_gravity = NorthWestGravity;
	xwin.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
		ExposureMask | VisibilityChangeMask |
		StructureNotifyMask | ButtonMotionMask |
		ButtonPressMask | ButtonReleaseMask;
	xwin.attrs.colormap = xwin.cmap;

	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
		parent = XRootWindow(xwin.dpy, xwin.scr);
	xwin.win = XCreateWindow(xwin.dpy, parent, xwin.l, xwin.t, twin.w, twin.h, 0,
			XDefaultDepth(xwin.dpy, xwin.scr), InputOutput, xwin.vis,
			CWBackPixel | CWBorderPixel | CWBitGravity |
			CWEventMask | CWColormap,
			&xwin.attrs);

	memset(&gcvalues, 0, sizeof(gcvalues));
	gcvalues.graphics_exposures = False;
	dc.gc = XCreateGC(xwin.dpy, parent, GCGraphicsExposures, &gcvalues);
	xwin.buf =
		XCreatePixmap(xwin.dpy, xwin.win, twin.w, twin.h, DefaultDepth(xwin.dpy, xwin.scr));
	XSetForeground(xwin.dpy, dc.gc, dc.color_array[defaultbg].pixel);
	XFillRectangle(xwin.dpy, xwin.buf, dc.gc, 0, 0, twin.w, twin.h);

	/* font spec buffer */
	xwin.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));

	/* Xft rendering context */
	xwin.draw = XftDrawCreate(xwin.dpy, xwin.buf, xwin.vis, xwin.cmap);

	/* input methods */
	ximopen(xwin.dpy);

	/* white cursor, black outline */
	cursor = XCreateFontCursor(xwin.dpy, mouseshape);
	XDefineCursor(xwin.dpy, xwin.win, cursor);

	if (XParseColor(xwin.dpy, xwin.cmap, colorname[mousefg], &xmousefg) == 0) {
		xmousefg.red = 0xffff;
		xmousefg.green = 0xffff;
		xmousefg.blue = 0xffff;
	}

	if (XParseColor(xwin.dpy, xwin.cmap, colorname[mousebg], &xmousebg) == 0) {
		xmousebg.red = 0x0000;
		xmousebg.green = 0x0000;
		xmousebg.blue = 0x0000;
	}

	XRecolorCursor(xwin.dpy, cursor, &xmousefg, &xmousebg);

	xwin.xembed = XInternAtom(xwin.dpy, "_XEMBED", False);
	xwin.wmdeletewin = XInternAtom(xwin.dpy, "WM_DELETE_WINDOW", False);
	xwin.netwmname = XInternAtom(xwin.dpy, "_NET_WM_NAME", False);
	XSetWMProtocols(xwin.dpy, xwin.win, &xwin.wmdeletewin, 1);

	xwin.netwmpid = XInternAtom(xwin.dpy, "_NET_WM_PID", False);
	XChangeProperty(xwin.dpy, xwin.win, xwin.netwmpid, XA_CARDINAL, 32, PropModeReplace,
			(uchar *)&thispid, 1);

	twin.mode = MODE_NUMLOCK;
	resettitle();
	xhints();
	XMapWindow(xwin.dpy, xwin.win);
	XSync(xwin.dpy, False);

	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2);
	xsel.primary = NULL;
	xsel.clipboard = NULL;
	xsel.xtarget = XInternAtom(xwin.dpy, "UTF8_STRING", 0);
	if (xsel.xtarget == None)
		xsel.xtarget = XA_STRING;
}

void xsetenv(void) {
	char buf[sizeof(long) * 8 + 1];

	snprintf(buf, sizeof(buf), "%lu", xwin.win);
	setenv("WINDOWID", buf, 1);
}

void xsettitle(char *p) {
	XTextProperty prop;
	DEFAULT(p, opt_title);

	Xutf8TextListToTextProperty(xwin.dpy, &p, 1, XUTF8StringStyle, &prop);
	XSetWMName(xwin.dpy, xwin.win, &prop);
	XSetTextProperty(xwin.dpy, xwin.win, &prop, xwin.netwmname);
	XFree(prop.value);
}

void xximspot(int x, int y) {
	XPoint spot = {borderpx + x * twin.cw, borderpx + (y + 1) * twin.ch};
	XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);

	XSetICValues(xwin.xic, XNPreeditAttributes, attr, NULL);
	XFree(attr);
}

void xsetpointermotion(int set) {
	MODBIT(xwin.attrs.event_mask, set, PointerMotionMask);
	XChangeWindowAttributes(xwin.dpy, xwin.win, CWEventMask, &xwin.attrs);
}

void xsetmode(int set, unsigned int flags) {
	int mode = twin.mode;
	MODBIT(twin.mode, set, flags);
	if ((twin.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
		redraw();
}

void xseturgency(int add) {
	XWMHints *h = XGetWMHints(xwin.dpy, xwin.win);

	MODBIT(h->flags, add, XUrgencyHint);
	XSetWMHints(xwin.dpy, xwin.win, h);
	XFree(h);
}

void xbell(void) {
	if (!(IS_SET(MODE_FOCUSED)))
		xseturgency(1);
	if (bellvolume)
		XkbBell(xwin.dpy, xwin.win, bellvolume, (Atom)NULL);
}


code:
#ifndef stX_H
#define stX_H

//typedef Glyph;
//typedef Line;
//typedef Arg;
#include "fonts.h"
#include "xdraw.h"

/* macros */
#ifdef IS_SET
#undef IS_SET
#endif
// seems ok. is there a reason?
#define IS_SET(flag) ((twin.mode & (flag)) != 0)

void SET(int flag);

enum win_mode {
	MODE_VISIBLE = 1 << 0,
	MODE_FOCUSED = 1 << 1,
	MODE_APPKEYPAD = 1 << 2,
	MODE_MOUSEBTN = 1 << 3,
	MODE_MOUSEMOTION = 1 << 4,
	MODE_REVERSE = 1 << 5,
	MODE_KBDLOCK = 1 << 6,
	MODE_HIDE = 1 << 7, // inactive cursor
	MODE_APPCURSOR = 1 << 8,
	MODE_MOUSESGR = 1 << 9,
	MODE_8BIT = 1 << 10,
	MODE_BLINK = 1 << 11,
	MODE_FBLINK = 1 << 12,
	MODE_FOCUS = 1 << 13,
	MODE_MOUSEX10 = 1 << 14,
	MODE_MOUSEMANY = 1 << 15,
	MODE_BRCKTPASTE = 1 << 16,
	MODE_NUMLOCK = 1 << 17,
	MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10|MODE_MOUSEMANY,
	MODE_KBDSELECT = 1 << 18,
	MODE_LESS = 1 << 19, // also hides cursor.
	MODE_ENTERSTRING = 1 << 20,
};

void cresize(int, int);
void xhints(void);

void xinit(int cols, int rows);
void xsetenv(void);

void xbell(void);
void xclipcopy(void);
void xloadcolors(void);
int xsetcolorname(int, const char *);
void xsettitle(char *);
void xsetmode(int, unsigned int);
void xsetpointermotion(int);
void xximspot(int, int);
void toggle_winmode(int);
#ifdef shared
int stmain(int argc, char *argv[]);
#endif

#endif


code:
#!/bin/sh

echo
echo -e "\033[1;37mBackground colors\e[0m"

echo
#echo -n '     '
for i in `seq 0 7`; do echo -ne "\e[48;5;$i""m    $i   \e[30m"; done
echo -e "\e[0m"

for i in `seq 8 15`; do printf "\e[30;48;5;$i""m   %2d   " $i; done
echo -e "\e[0m"
echo


code:
#!/bin/sh

echo -ne "\n\033[1;37m";
echo -e 256 Color mode, \#0-7 "\033[0;1m (indexed palette)" "\033[0;30;40m "
echo

for a in 2 0 1 '1;2'; do
	printf '\033[37;0m%3sm: ' $a
	for b in `seq 30 37`;do
		printf "\033[$a;$b"'m  %03d  ' $b
	done
	printf "\033[0m\n"
done

echo

echo -e "\n\033[1;37mInverse\e[0m"
echo

for a in 2 0 1 '1;2'; do
	printf '\033[37;0m%3sm: ' $a
	for b in `seq 30 37`;do
		printf "\033[$a;7;$b"'m  %03d  ' $b
	done
	printf "\033[0m\n"
done

echo


code:
UTF-8 encoded sample plain-text file
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾

Markus Kuhn [ˈmaʳkʊs kuːn] <http://www.cl.cam.ac.uk/~mgk25/> — 2002-07-25 CC BY

The ASCII compatible UTF-8 encoding used in this plain-text file
is defined in Unicode, ISO 10646-1, and RFC 2279.

Using Unicode/UTF-8, you can write in emails and source code things such as

Mathematics and scien#es:

  ∮ E⋅da = Q,  n → ∞, ∑ f(i) = ∏ g(i),      ⎧⎡⎛┌─────┐⎞⎤⎫
                                            ⎪⎢⎜│a²+b³ ⎟⎥⎪
  ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β),    ⎪⎢⎜│───── ⎟⎥⎪
                                            ⎪⎢⎜⎷ c₈   ⎟⎥⎪
  ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ,                   ⎨⎢⎜       ⎟⎥⎬
                                            ⎪⎢⎜ ∞     ⎟⎥⎪
  ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫),      ⎪⎢⎜ ⎲     ⎟⎥⎪
                                            ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪
  2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm     ⎩⎣⎝i=1    ⎠⎦⎭

Linguistics and dictionaries:

  ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
  Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]

APL:

  ((V⍳V)=⍳⍴V)/V←,V    ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈

Nicer typography in plain text files:

  ╔══════════════════════════════════════════╗
  ║                                          ║
  ║   • ‘single’ and “double” quotes         ║
  ║                                          ║
  ║   • Curly apostrophes: “We’ve been here” ║
  ║                                          ║
  ║   • Latin-1 apostrophe and accents: '´`  ║
  ║                                          ║
  ║   • ‚deutsche‘ „Anführungszeichen“       ║
  ║                                          ║
  ║   • †, ‡, ‰, •, 3–4, —, −5/+5, ™, …      ║
  ║                                          ║
  ║   • ASCII safety test: 1lI|, 0OD, 8B     ║
  ║                      ╭─────────╮         ║
  ║   • the euro symbol: │ 14.95 € │         ║
  ║                      ╰─────────╯         ║
  ╚══════════════════════════════════════════╝

Combining characters:

  STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑

Greek (in Polytonic):

  The Greek anthem:

  Σὲ γνωρίζω ἀπὸ τὴν κόψη
  τοῦ σπαθιοῦ τὴν τρομερή,
  σὲ γνωρίζω ἀπὸ τὴν ὄψη
  ποὺ μὲ βία μετράει τὴ γῆ.

  ᾿Απ᾿ τὰ κόκκαλα βγαλμένη
  τῶν ῾Ελλήνων τὰ ἱερά
  καὶ σὰν πρῶτα ἀνδρειωμένη
  χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!

  From a speech of Demosthenes in the 4th century BC:

  Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,
  ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς
  λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ
  τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿
  εἰς τοῦτο προήκοντα,  ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ
  πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν
  οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,
  οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν
  ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον
  τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι
  γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν
  προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους
  σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ
  τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ
  τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς
  τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.

  Δημοσθένους, Γ´ ᾿Ολυνθιακὸς

Georgian:

  From a Unicode conference invitation:

  გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო
  კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,
  ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს
  ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,
  ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება
  ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,
  ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.

Russian:

  From a Unicode conference invitation:

  Зарегистрируйтесь сейчас на Десятую Международную Конференцию по
  Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.
  Конференция соберет широкий круг экспертов по  вопросам глобального
  Интернета и Unicode, локализации и интернационализации, воплощению и
  применению Unicode в различных операционных системах и программных
  приложениях, шрифтах, верстке и многоязычных компьютерных системах.

Thai (UCS Level 2):

  Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese
  classic 'San Gua'):

  [----------------------------|------------------------]
    ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช  พระปกเกศกองบู๊กู้ขึ้นใหม่
  สิบสองกษัตริย์ก่อนหน้าแลถัดไป       สององค์ไซร้โง่เขลาเบาปัญญา
    ทรงนับถือขันทีเป็นที่พึ่ง           บ้านเมืองจึงวิปริตเป็นนักหนา
  โฮจิ๋นเรียกทัพทั่วหัวเมืองมา         หมายจะฆ่ามดชั่วตัวสำคัญ
    เหมือนขับไสไล่เสือจากเคหา      รับหมาป่าเข้ามาเลยอาสัญ
  ฝ่ายอ้องอุ้นยุแยกให้แตกกัน          ใช้สาวนั้นเป็นชนวนชื่นชวนใจ
    พลันลิฉุยกุยกีกลับก่อเหตุ          ช่างอาเพศจริงหนาฟ้าร้องไห้
  ต้องรบราฆ่าฟันจนบรรลัย           ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ

  (The above is a two-column text. If combining characters are handled
  correctly, the lines of the second column should be aligned with the
  | character above.)

Ethiopian:

  Proverbs in the Amharic language:

  ሰማይ አይታረስ ንጉሥ አይከሰስ።
  ብላ ካለኝ እንደአባቴ በቆመጠኝ።
  ጌጥ ያለቤቱ ቁምጥና ነው።
  ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።
  የአፍ ወለምታ በቅቤ አይታሽም።
  አይጥ በበላ ዳዋ ተመታ።
  ሲተረጉሙ ይደረግሙ።
  ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።
  ድር ቢያብር አንበሳ ያስር።
  ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።
  እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።
  የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።
  ሥራ ከመፍታት ልጄን ላፋታት።
  ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።
  የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።
  ተንጋሎ ቢተፉ ተመልሶ ባፉ።
  ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።
  እግርህን በፍራሽህ ልክ ዘርጋ።

Runes:

  ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ

  (Old English, which transcribed into Latin reads 'He cwaeth that he
  bude thaem lande northweardum with tha Westsae.' and means 'He said
  that he lived in the northern land near the Western Sea.')

Braille:

  ⡌⠁⠧⠑ ⠼⠁⠒  ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌

  ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞
  ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎
  ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂
  ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙
  ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑
  ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲

  ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲

  ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹
  ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞
  ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕
  ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹
  ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎
  ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎
  ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳
  ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞
  ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲

  (The first couple of paragraphs of "A Christmas Carol" by Dickens)

Compact font selection example text:

  ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789
  abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ
  –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд
  ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ ﬁ�⑀₂ἠḂӥẄɐː⍎אԱა

Greetings in various languages:

  Hello world, Καλημέρα κόσμε, コンニチハ

Box drawing alignment tests:                                          █
                                                                      ▉
  ╔══╦══╗  ┌──┬──┐  ╭──┬──╮  ╭──┬──╮  ┏━━┳━━┓  ┎┒┏┑   ╷  ╻ ┏┯┓ ┌┰┐    ▊ ╱╲╱╲╳╳╳
  ║┌─╨─┐║  │╔═╧═╗│  │╒═╪═╕│  │╓─╁─╖│  ┃┌─╂─┐┃  ┗╃╄┙  ╶┼╴╺╋╸┠┼┨ ┝╋┥    ▋ ╲╱╲╱╳╳╳
  ║│╲ ╱│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╿ │┃  ┍╅╆┓   ╵  ╹ ┗┷┛ └┸┘    ▌ ╱╲╱╲╳╳╳
  ╠╡ ╳ ╞╣  ├╢   ╟┤  ├┼─┼─┼┤  ├╫─╂─╫┤  ┣┿╾┼╼┿┫  ┕┛┖┚     ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
  ║│╱ ╲│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╽ │┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▎
  ║└─╥─┘║  │╚═╤═╝│  │╘═╪═╛│  │╙─╀─╜│  ┃└─╂─┘┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▏
  ╚══╩══╝  └──┴──┘  ╰──┴──╯  ╰──┴──╯  ┗━━┻━━┛  ▗▄▖▛▀▜   └╌╌┘ ╎ ┗╍╍┛ ┋  ▁▂▃▄▅▆▇█
                                               ▝▀▘▙▄▟


code:
#if 0
COMPILE PRINTF

return
#endif

/* dump a chartable to the terminal */

#ifndef MLIB
#include <stdio.h>
#endif

int main(int argc, char **argv){
	for ( int a = 32; a<256; a++ ){
		printf("%2x: %c  ", a, a );
		if ( !((a+1)%8) )
			printf("\n");
	}
	return(0);
}


code:
#if 0
COMPILE prints printl itohex printf fmtd strcpy strcat ewrites atoi
SHRINKELF

return
#endif

#ifndef MLIB
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define writes(msg) write(1,msg,sizeof(msg))
#define ewrites(msg) write(2,msg,sizeof(msg))
#define printl() printf("\n")

#endif

const struct { char *shortname; char *desc; } ctrl[] = {
	{ "NUL", "Null, End of file" },
	{ "SOH", "Start of Heading" },
	{ "STX", "Start of Text" },
	{ "ETX", "End of Text" },
	{ "EOT", "End of Transmission" },
	{ "ENQ", "Enquiry" },
	{ "ACK", "Acknowledge (Telnet)" },
	{ "BEL", "Bell (audible or attention signal)" },
	{ "BS" , "Backspace (Delete)" },
	{ "TAB", "Horizontal Tabulation" },
	{ "LF" , "Line Feed" },
	{ "VT" , "Vertical Tabulation" },
	{ "FF" , "Form Feed" },
	{ "CR" , "Carriage Return, Enter" },
	{ "SO" , "Shift Out" },
	{ "SI" , "Shift In" },
	{ "DLE", "Data Link Escape" },
	{ "DC1", "Device Control 1" },
	{ "DC2", "Device Control 2" },
	{ "DC3", "Device Control 3" },
	{ "DC4", "Device Control 4" },
	{ "NAK", "Negative Acknowledge" },
	{ "SYN", "Synchronous Idle" },
	{ "ETB", "End of Transmission Block" },
	{ "CAN", "Cancel" },
	{ "EM" , "End of Medium" },
	{ "SUB", "Substitute" },
	{ "ESC", "Escape, VT100 Initiate Control Sequence" },
	{ "FS" , "File Separator" },
	{ "GS" , "Group Separator" },
	{ "RS" , "Record Separator" },
	{ "US" , "Unit Separator" },
};

void usage(){
	ewrites( R"(ascii [-dhxct] [-f num] [-t num]
Dump an ascii table to stdout.
Options:
	-s num : start with num
	-e num : end at num
	-c     : colorize
	-x     : show hexadecimal numbers
	-d     : decimal numbers
	-t     : dump a table and descriptions of the control chars 0-31
	-F fmt : printf format. printf is callen with 3 times c (current char)
	-T num : Linebreak after num columns (default 8)
	-h     : show this help.

(c) 2023, BSD 3-clause, misc (github.com/michael105)
)" );
	exit(0);
}

int main(int argc, char **argv){
	int opt=0;
	int from = 32;
	int to = 255;
	int lb = 8; // linebreak after 8 columns
	char fmtb[32];
	char *fmt = fmtb;
	strcpy(fmt,"%2x:");
	for ( *argv++; *argv; *argv++ ){
		if ( argv[0][0] == '-' ){
			for ( char *o = *argv + 1; *o; o++ )
			switch ( *o ){
				case 'd':
					opt |= 1;
					strcpy(fmt,"%3d:");
					break;
				case 'x':
					opt |= 2;
					break;
				case 'c':
					opt |= 4;
					break;
				case 't':
					for ( int a = 0; a<32; a++ ){
						printf("%2d - %2x: %3s  %s\n",a,a,ctrl[a].shortname, ctrl[a].desc );
					}
					exit(0);
				case 's':
					*argv++;
					from = atoi( *argv );
					break;
				case 'e':
					*argv++;
					to = atoi( *argv );
					break;
				case 'T':
					*argv++;
					lb = atoi( *argv );
					break;
				case 'F':
					opt = -1;
					*argv++;
					if ( *argv )
						fmt = *argv;
					break;

				case 'h':
					usage();

				default:
					writes("ascii [-hdxct] [-s num] [-e num]\n");
					exit(0);
			}
		}
	}
	if ( opt >= 0 ){
		if ( (opt&3) == 3 )
			strcpy(fmt,"%3d(%2x):");
		if ( (opt&4) )
			strcat(fmt," \e[36m%c\e[37m  ");
		else
			strcat(fmt," %c  ");
	}

	int col = 1;
	for ( int a = from; a<=to; a++ ){
		printf(fmt, a, a, a );

		if ( col++ == lb ){
			printl();
			col=1;
		}
	}
	exit(0);
}


code:
#!/bin/sh

for i in `seq 0 18`
do
	echo -e "\e[0m" Attr: $i "\e[$i"m Some text
done


code:
German umlauts,
encoded with CP1252 (ANSI)

���
���
�


code:
CC:=gcc -Os -Wall -Wno-unused-value -static -s

all: cpfilter ttfz ttfdz

cpfilter: cpfilter.c ../src/charmaps.h
	${CC} -o cpfilter cpfilter.c

ttfz: ttfz.c sdefl.h
	gcc -Os -s -o ttfz ttfz.c

ttfdz: ttfdz.c sdefl.h
	gcc -Os -s -o ttfdz ttfdz.c

path: tools/Makefile


code:
contents:

cpfilter (misc147), filter between different codepages

szcomp, szdecomp,
	uses the sinfl/sdefl library of Micha Mettke, https://github.com/vurtun/lib
	used to embed compressed fonts

path: tools/README