#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
+#include <libgen.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
#define IS_SET(flag) ((term.mode & (flag)) != 0)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x) (1 << 24 & (x))
+#define TRUERED(x) (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x) (((x) & 0xff00))
+#define TRUEBLUE(x) (((x) & 0xff) << 8)
+
#define VT102ID "\033[?6c"
enum cursor_state {
CURSOR_DEFAULT = 0,
CURSOR_WRAPNEXT = 1,
- CURSOR_ORIGIN = 2
+ CURSOR_ORIGIN = 2
};
enum term_mode {
- MODE_WRAP = 1,
+ MODE_WRAP = 1,
MODE_INSERT = 2,
MODE_APPKEYPAD = 4,
MODE_ALTSCREEN = 8,
- MODE_CRLF = 16,
+ MODE_CRLF = 16,
MODE_MOUSEBTN = 32,
MODE_MOUSEMOTION = 64,
- MODE_MOUSE = 32|64,
MODE_REVERSE = 128,
MODE_KBDLOCK = 256,
- MODE_HIDE = 512,
- MODE_ECHO = 1024,
- MODE_APPCURSOR = 2048,
+ MODE_HIDE = 512,
+ MODE_ECHO = 1024,
+ MODE_APPCURSOR = 2048,
MODE_MOUSESGR = 4096,
- MODE_8BIT = 8192,
- MODE_BLINK = 16384,
- MODE_FBLINK = 32768,
+ MODE_8BIT = 8192,
+ MODE_BLINK = 16384,
+ MODE_FBLINK = 32768,
+ MODE_FOCUS = 65536,
+ MODE_MOUSEX10 = 131072,
+ MODE_MOUSEMANY = 262144,
+ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+ |MODE_MOUSEMANY,
};
enum escape_state {
ESC_START = 1,
- ESC_CSI = 2,
- ESC_STR = 4, /* DSC, OSC, PM, APC */
+ ESC_CSI = 2,
+ ESC_STR = 4, /* DSC, OSC, PM, APC */
ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
SNAP_LINE = 2
};
-/* bit macro */
-#undef B0
-enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
-
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef struct {
- char c[UTF_SIZ]; /* character code */
- uchar mode; /* attribute flags */
- ushort fg; /* foreground */
- ushort bg; /* background */
+ char c[UTF_SIZ]; /* character code */
+ uchar mode; /* attribute flags */
+ ulong fg; /* foreground */
+ ulong bg; /* background */
} Glyph;
typedef Glyph *Line;
typedef struct {
- Glyph attr; /* current char attributes */
+ Glyph attr; /* current char attributes */
int x;
int y;
char state;
/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ int len; /* raw string length */
char priv;
int arg[ESC_ARG_SIZ];
- int narg; /* nb of args */
+ int narg; /* nb of args */
char mode;
} CSIEscape;
/* STR Escape sequence structs */
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct {
- char type; /* ESC type ... */
+ char type; /* ESC type ... */
char buf[STR_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ int len; /* raw string length */
char *args[STR_ARG_SIZ];
- int narg; /* nb of args */
+ int narg; /* nb of args */
} STREscape;
/* Internal representation of the screen */
typedef struct {
- int row; /* nb row */
- int col; /* nb col */
- Line *line; /* screen */
- Line *alt; /* alternate screen */
- bool *dirty; /* dirtyness of lines */
- TCursor c; /* cursor */
- int top; /* top scroll limit */
- int bot; /* bottom scroll limit */
- int mode; /* terminal mode flags */
- int esc; /* escape state flags */
- bool numlock; /* lock numbers in keyboard */
+ int row; /* nb row */
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ bool *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
+ bool numlock; /* lock numbers in keyboard */
bool *tabs;
} Term;
XIC xic;
Draw draw;
Visual *vis;
+ XSetWindowAttributes attrs;
int scr;
bool isfixed; /* is fixed geometry? */
int fx, fy, fw, fh; /* fixed geometry */
uint mask;
char s[ESC_BUF_SIZ];
/* three valued logic variables: 0 indifferent, 1 on, -1 off */
- signed char appkey; /* application keypad */
- signed char appcursor; /* application cursor */
- signed char crlf; /* crlf mode */
+ signed char appkey; /* application keypad */
+ signed char appcursor; /* application cursor */
+ signed char crlf; /* crlf mode */
} Key;
-/* TODO: use better name for vars... */
typedef struct {
int mode;
int type;
static void tsetmode(bool, bool, int *, int);
static void tfulldirt(void);
static void techo(char *, int);
-
+static ulong tdefcolor(int *, int *, int);
static inline bool match(uint, uint);
static void ttynew(void);
static void ttyread(void);
static int xloadfontset(Font *);
static void xsettitle(char *);
static void xresettitle(void);
+static void xsetpointermotion(int);
static void xseturgency(int);
static void xsetsel(char*);
static void xtermclear(int, int, int, int);
static char *opt_embed = NULL;
static char *opt_class = NULL;
static char *opt_font = NULL;
+static int oldbutton = 3; /* button event on startup: 3 = release */
static char *usedfont = NULL;
static int usedfontsize = 0;
typedef struct {
XftFont *font;
- long c;
int flags;
} Fontcache;
-/*
- * Fontcache is a ring buffer, with frccur as current position and frclen as
- * the current length of used elements.
- */
-
-static Fontcache frc[1024];
-static int frccur = -1, frclen = 0;
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
ssize_t
xwrite(int fd, char *s, size_t len) {
rtn = 1;
c = *s;
- if(~c & B7) { /* 0xxxxxxx */
+ if(~c & 0x80) { /* 0xxxxxxx */
*u = c;
return rtn;
- } else if((c & (B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
- *u = c&(B4|B3|B2|B1|B0);
+ } else if((c & 0xE0) == 0xC0) { /* 110xxxxx */
+ *u = c & 0x1F;
n = 1;
- } else if((c & (B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
- *u = c&(B3|B2|B1|B0);
+ } else if((c & 0xF0) == 0xE0) { /* 1110xxxx */
+ *u = c & 0x0F;
n = 2;
- } else if((c & (B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
- *u = c & (B2|B1|B0);
+ } else if((c & 0xF8) == 0xF0) { /* 11110xxx */
+ *u = c & 0x07;
n = 3;
} else {
goto invalid;
for(i = n, ++s; i > 0; --i, ++rtn, ++s) {
c = *s;
- if((c & (B7|B6)) != B7) /* 10xxxxxx */
+ if((c & 0xC0) != 0x80) /* 10xxxxxx */
goto invalid;
*u <<= 6;
- *u |= c & (B5|B4|B3|B2|B1|B0);
+ *u |= c & 0x3F;
}
if((n == 1 && *u < 0x80) ||
*sp = uc; /* 0xxxxxxx */
return 1;
} else if(*u < 0x800) {
- *sp = (uc >> 6) | (B7|B6); /* 110xxxxx */
+ *sp = (uc >> 6) | 0xC0; /* 110xxxxx */
n = 1;
} else if(uc < 0x10000) {
- *sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */
+ *sp = (uc >> 12) | 0xE0; /* 1110xxxx */
n = 2;
} else if(uc <= 0x10FFFF) {
- *sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */
+ *sp = (uc >> 18) | 0xF0; /* 11110xxx */
n = 3;
} else {
goto invalid;
}
for(i=n,++sp; i>0; --i,++sp)
- *sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
+ *sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */
return n+1;
invalid:
c3 = (uchar *)++s;
if(b < 1) {
return 0;
- } else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1) {
+ } else if((*c1 & 0xE0) == 0xC0 && b == 1) {
return 0;
- } else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
+ } else if((*c1 & 0xF0) == 0xE0 &&
((b == 1) ||
- ((b == 2) && (*c2&(B7|B6)) == B7))) {
+ ((b == 2) && (*c2 & 0xC0) == 0x80))) {
return 0;
- } else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
+ } else if((*c1 & 0xF8) == 0xF0 &&
((b == 1) ||
- ((b == 2) && (*c2&(B7|B6)) == B7) ||
- ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7))) {
+ ((b == 2) && (*c2 & 0xC0) == 0x80) ||
+ ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) {
return 0;
} else {
return 1;
utf8size(char *s) {
uchar c = *s;
- if(~c&B7) {
+ if(~c & 0x80) {
return 1;
- } else if((c&(B7|B6|B5)) == (B7|B6)) {
+ } else if((c & 0xE0) == 0xC0) {
return 2;
- } else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) {
+ } else if((c & 0xF0) == 0xE0) {
return 3;
} else {
return 4;
button = e->xbutton.button, state = e->xbutton.state,
len;
char buf[40];
- static int ob, ox, oy;
+ static int ox, oy;
/* from urxvt */
if(e->xbutton.type == MotionNotify) {
- if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
+ if(x == ox && y == oy)
+ return;
+ if(!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return;
- button = ob + 32;
+ /* 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)
if(button >= 3)
button += 64 - 3;
if(e->xbutton.type == ButtonPress) {
- ob = button;
+ oldbutton = button;
ox = x;
oy = y;
}
}
- button += (state & ShiftMask ? 4 : 0)
- + (state & Mod4Mask ? 8 : 0)
- + (state & ControlMask ? 16 : 0);
+ if(!IS_SET(MODE_MOUSEX10)) {
+ button += (state & ShiftMask ? 4 : 0)
+ + (state & Mod4Mask ? 8 : 0)
+ + (state & ControlMask ? 16 : 0);
+ }
len = 0;
if(IS_SET(MODE_MOUSESGR)) {
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);
+ IS_SET(MODE_MOUSEX10)? button-1 : 32+button,
+ 32+x+1, 32+y+1);
} else {
return;
}
gettimeofday(&now, NULL);
/* Clear previous selection, logically and visually. */
- if(sel.ob.x != -1) {
- sel.ob.x = -1;
- tsetdirt(sel.nb.y, sel.ne.y);
- draw();
- }
+ selclear(NULL);
sel.mode = 1;
sel.type = SEL_REGULAR;
sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
if(sel.snap != 0) {
sel.mode++;
tsetdirt(sel.nb.y, sel.ne.y);
- draw();
}
sel.tclick2 = sel.tclick1;
sel.tclick1 = now;
selpaste(NULL);
} else if(e->xbutton.button == Button1) {
if(sel.mode < 2) {
- sel.ob.x = -1;
+ selclear(NULL);
} else {
getbuttoninfo(e);
selcopy();
int stat = 0;
if(waitpid(pid, &stat, 0) < 0)
- die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
+ die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
if(WIFEXITED(stat)) {
exit(WEXITSTATUS(stat));
if(BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
if((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
- sel.ob.x = -1;
+ selclear(NULL);
return;
}
if(sel.type == SEL_RECTANGULAR) {
tscrollup(term.c.y, n);
}
+ulong
+tdefcolor(int *attr, int *npar, int l) {
+ long idx = -1;
+ uint r, g, b;
+
+ switch (attr[*npar + 1]) {
+ case 2: /* direct colour 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 (%d,%d,%d)\n",
+ r, g, b);
+ else
+ idx = TRUECOLOR(r, g, b);
+ break;
+ case 5: /* indexed colour */
+ 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
+ idx = attr[*npar];
+ break;
+ case 0: /* implemented defined (only foreground) */
+ case 1: /* transparent */
+ case 3: /* direct colour in CMY space */
+ case 4: /* direct colour in CMYK space */
+ default:
+ fprintf(stderr,
+ "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+ }
+
+ return idx;
+}
+
void
tsetattr(int *attr, int l) {
int i;
+ ulong idx;
for(i = 0; i < l; i++) {
switch(attr[i]) {
term.c.attr.mode &= ~ATTR_REVERSE;
break;
case 38:
- if(i + 2 < l && attr[i + 1] == 5) {
- i += 2;
- if(BETWEEN(attr[i], 0, 255)) {
- term.c.attr.fg = attr[i];
- } else {
- fprintf(stderr,
- "erresc: bad fgcolor %d\n",
- attr[i]);
- }
- } else {
- fprintf(stderr,
- "erresc(38): gfx attr %d unknown\n",
- attr[i]);
- }
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.fg = idx;
break;
case 39:
term.c.attr.fg = defaultfg;
break;
case 48:
- if(i + 2 < l && attr[i + 1] == 5) {
- i += 2;
- if(BETWEEN(attr[i], 0, 255)) {
- term.c.attr.bg = attr[i];
- } else {
- fprintf(stderr,
- "erresc: bad bgcolor %d\n",
- attr[i]);
- }
- } else {
- fprintf(stderr,
- "erresc(48): gfx attr %d unknown\n",
- attr[i]);
- }
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.bg = idx;
break;
case 49:
term.c.attr.bg = defaultbg;
case 25: /* DECTCEM -- Text Cursor Enable Mode */
MODBIT(term.mode, !set, MODE_HIDE);
break;
- case 1000: /* 1000,1002: enable xterm mouse report */
+ case 9: /* X10 mouse compatibility mode */
+ xsetpointermotion(0);
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEX10);
+ break;
+ case 1000: /* 1000: report button press */
+ xsetpointermotion(0);
+ MODBIT(term.mode, 0, MODE_MOUSE);
MODBIT(term.mode, set, MODE_MOUSEBTN);
- MODBIT(term.mode, 0, MODE_MOUSEMOTION);
break;
- case 1002:
+ case 1002: /* 1002: report motion on button press */
+ xsetpointermotion(0);
+ MODBIT(term.mode, 0, MODE_MOUSE);
MODBIT(term.mode, set, MODE_MOUSEMOTION);
- MODBIT(term.mode, 0, MODE_MOUSEBTN);
break;
- case 1006:
+ case 1003: /* 1003: enable all mouse motions */
+ xsetpointermotion(set);
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEMANY);
+ break;
+ case 1004: /* 1004: send focus events to tty */
+ MODBIT(term.mode, set, MODE_FOCUS);
+ break;
+ case 1006: /* 1006: extended reporting mode */
MODBIT(term.mode, set, MODE_MOUSESGR);
break;
case 1034:
tclearregion(0, 0, term.col-1,
term.row-1);
}
- if(set ^ alt) /* set is always 1 or 0 */
+ if(set ^ alt) /* set is always 1 or 0 */
tswapscreen();
if(*args != 1049)
break;
case 1048:
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
break;
+ /* Not implemented mouse modes. See comments there. */
+ case 1001: /* mouse highlight mode; can hang the
+ terminal by design when implemented. */
+ case 1005: /* UTF-8 mouse mode; will confuse
+ applications not supporting UTF-8
+ and luit. */
+ case 1015: /* urxvt mangled mouse mode; incompatible
+ and can be mistaken for other control
+ codes. */
default:
fprintf(stderr,
"erresc: unknown private set/reset mode %d\n",
}
}
}
-#undef MODBIT
-
void
csihandle(void) {
tputtab(1);
break;
case 'J': /* ED -- Clear screen */
- sel.ob.x = -1;
+ selclear(NULL);
switch(csiescseq.arg[0]) {
case 0: /* below */
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
for(; len > 0; buf++, len--) {
char c = *buf;
- if(c == '\033') { /* escape */
+ if(c == '\033') { /* escape */
tputc("^", 1);
tputc("[", 1);
- } else if(c < '\x20') { /* control code */
+ } else if(c < '\x20') { /* control code */
if(c != '\n' && c != '\r' && c != '\t') {
c |= '\x40';
tputc("^", 1);
*/
if(control) {
switch(ascii) {
- case '\t': /* HT */
+ case '\t': /* HT */
tputtab(1);
return;
- case '\b': /* BS */
+ case '\b': /* BS */
tmoveto(term.c.x-1, term.c.y);
return;
- case '\r': /* CR */
+ case '\r': /* CR */
tmoveto(0, term.c.y);
return;
- case '\f': /* LF */
- case '\v': /* VT */
- case '\n': /* LF */
+ case '\f': /* LF */
+ case '\v': /* VT */
+ case '\n': /* LF */
/* go to first col if the mode is set */
tnewline(IS_SET(MODE_CRLF));
return;
- case '\a': /* BEL */
+ case '\a': /* BEL */
if(!(xw.state & WIN_FOCUSED))
xseturgency(1);
return;
- case '\033': /* ESC */
+ case '\033': /* ESC */
csireset();
term.esc = ESC_START;
return;
- case '\016': /* SO */
- case '\017': /* SI */
+ case '\016': /* SO */
+ case '\017': /* SI */
/*
* Different charsets are hard to handle. Applications
* should use the right alt charset escapes for the
* rest is incompatible history st should not support.
*/
return;
- case '\032': /* SUB */
- case '\030': /* CAN */
+ case '\032': /* SUB */
+ case '\030': /* CAN */
csireset();
return;
- case '\005': /* ENQ (IGNORED) */
- case '\000': /* NUL (IGNORED) */
- case '\021': /* XON (IGNORED) */
- case '\023': /* XOFF (IGNORED) */
- case 0177: /* DEL (IGNORED) */
+ case '\005': /* ENQ (IGNORED) */
+ case '\000': /* NUL (IGNORED) */
+ case '\021': /* XON (IGNORED) */
+ case '\023': /* XOFF (IGNORED) */
+ case 0177: /* DEL (IGNORED) */
return;
}
} else if(term.esc & ESC_START) {
treset();
term.esc = 0;
xresettitle();
+ xloadcols();
break;
case '=': /* DECPAM -- Application keypad */
term.mode |= MODE_APPKEYPAD;
if(control && !(term.c.attr.mode & ATTR_GFX))
return;
if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
- sel.ob.x = -1;
+ selclear(NULL);
if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
tnewline(1);
xloadcols(void) {
int i, r, g, b;
XRenderColor color = { .alpha = 0xffff };
+ static bool loaded;
+ Colour *cp;
+
+ if(loaded) {
+ for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+ }
/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
for(i = 0; i < LEN(colorname); i++) {
die("Could not allocate color %d\n", i);
}
}
+ loaded = true;
}
int
die("st: can't open font %s\n", fontstr);
/* Setting character width and height. */
- xw.cw = dc.font.width;
- xw.ch = dc.font.height;
+ xw.cw = CEIL(dc.font.width * cwscale);
+ xw.ch = CEIL(dc.font.height * chscale);
FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
void
xunloadfonts(void) {
- int i, ip;
+ int i;
- /*
- * Free the loaded fonts in the font cache. This is done backwards
- * from the frccur.
- */
- for(i = 0, ip = frccur; i < frclen; i++, ip--) {
- if(ip < 0)
- ip = LEN(frc) - 1;
- XftFontClose(xw.dpy, frc[ip].font);
+ /* Free the loaded fonts in the font cache. */
+ for(i = 0; i < frclen; i++) {
+ XftFontClose(xw.dpy, frc[i].font);
}
- frccur = -1;
frclen = 0;
xunloadfont(&dc.font);
void
xinit(void) {
- XSetWindowAttributes attrs;
XGCValues gcvalues;
Cursor cursor;
Window parent;
}
/* Events */
- attrs.background_pixel = dc.col[defaultbg].pixel;
- attrs.border_pixel = dc.col[defaultbg].pixel;
- attrs.bit_gravity = NorthWestGravity;
- attrs.event_mask = FocusChangeMask | KeyPressMask
+ xw.attrs.background_pixel = dc.col[defaultbg].pixel;
+ xw.attrs.border_pixel = dc.col[defaultbg].pixel;
+ xw.attrs.bit_gravity = NorthWestGravity;
+ xw.attrs.event_mask = FocusChangeMask | KeyPressMask
| ExposureMask | VisibilityChangeMask | StructureNotifyMask
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
- attrs.colormap = xw.cmap;
+ xw.attrs.colormap = xw.cmap;
parent = opt_embed ? strtol(opt_embed, NULL, 0) : \
XRootWindow(xw.dpy, xw.scr);
xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
- xw.vis,
- CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
- | CWColormap,
- &attrs);
+ xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
+ | CWEventMask | CWColormap, &xw.attrs);
memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False;
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
/* input methods */
- if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+ if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
XSetLocaleModifiers("@im=local");
if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
XSetLocaleModifiers("@im=");
xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
width = charlen * xw.cw, xp, i;
- int frp, frcflags;
+ int frcflags;
int u8fl, u8fblen, u8cblen, doesexist;
char *u8c, *u8fs;
long u8char;
FcPattern *fcpattern, *fontpattern;
FcFontSet *fcsets[] = { NULL };
FcCharSet *fccharset;
- Colour *fg, *bg, *temp, revfg, revbg;
+ Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
Rectangle r;
+ int oneatatime;
frcflags = FRC_NORMAL;
if(base.fg == defaultfg)
base.fg = defaultunderline;
}
- fg = &dc.col[base.fg];
- bg = &dc.col[base.bg];
+ if(IS_TRUECOL(base.fg)) {
+ colfg.red = TRUERED(base.fg);
+ colfg.green = TRUEGREEN(base.fg);
+ colfg.blue = TRUEBLUE(base.fg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
+ fg = &truefg;
+ } else {
+ fg = &dc.col[base.fg];
+ }
+
+ if(IS_TRUECOL(base.bg)) {
+ colbg.green = TRUEGREEN(base.bg);
+ colbg.red = TRUERED(base.bg);
+ colbg.blue = TRUEBLUE(base.bg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
+ bg = &truebg;
+ } else {
+ bg = &dc.col[base.bg];
+ }
+
+
if(base.mode & ATTR_BOLD) {
if(BETWEEN(base.fg, 0, 7)) {
}
/*
* Those ranges will not be brightened:
- * 8 - 15 – bright system colors
- * 196 - 231 – highest 256 color cube
- * 252 - 255 – brightest colors in greyscale
+ * 8 - 15 – bright system colors
+ * 196 - 231 – highest 256 color cube
+ * 252 - 255 – brightest colors in greyscale
*/
font = &dc.bfont;
frcflags = FRC_BOLD;
u8fs = s;
u8fblen = 0;
u8fl = 0;
+ oneatatime = font->width != xw.cw;
for(;;) {
u8c = s;
u8cblen = utf8decode(s, &u8char);
s += u8cblen;
bytelen -= u8cblen;
- doesexist = XftCharIndex(xw.dpy, font->match, u8char);
- if(!doesexist || bytelen <= 0) {
- if(bytelen <= 0) {
+ doesexist = XftCharExists(xw.dpy, font->match, u8char);
+ if(oneatatime || !doesexist || bytelen <= 0) {
+ if(oneatatime || bytelen <= 0) {
if(doesexist) {
u8fl++;
u8fblen += u8cblen;
winy + font->ascent,
(FcChar8 *)u8fs,
u8fblen);
- xp += font->width * u8fl;
+ xp += CEIL(font->width * cwscale * u8fl);
}
break;
u8fl++;
u8fblen += u8cblen;
}
- if(doesexist)
+ if(doesexist) {
+ if (oneatatime);
+ continue;
break;
+ }
- frp = frccur;
/* Search the font cache. */
- for(i = 0; i < frclen; i++, frp--) {
- if(frp <= 0)
- frp = LEN(frc) - 1;
-
- if(frc[frp].c == u8char
- && frc[frp].flags == frcflags) {
+ for(i = 0; i < frclen; i++) {
+ if(XftCharExists(xw.dpy, frc[i].font, u8char)
+ && frc[i].flags == frcflags) {
break;
}
}
/*
* Overwrite or create the new cache entry.
*/
- frccur++;
- frclen++;
- if(frccur >= LEN(frc))
- frccur = 0;
- if(frclen > LEN(frc)) {
- frclen = LEN(frc);
- XftFontClose(xw.dpy, frc[frccur].font);
+ if(frclen >= LEN(frc)) {
+ frclen = LEN(frc) - 1;
+ XftFontClose(xw.dpy, frc[frclen].font);
}
- frc[frccur].font = XftFontOpenPattern(xw.dpy,
+ frc[frclen].font = XftFontOpenPattern(xw.dpy,
fontpattern);
- frc[frccur].c = u8char;
- frc[frccur].flags = frcflags;
+ frc[frclen].flags = frcflags;
+
+ i = frclen;
+ frclen++;
FcPatternDestroy(fcpattern);
FcCharSetDestroy(fccharset);
-
- frp = frccur;
}
- XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
- xp, winy + frc[frp].font->ascent,
+ XftDrawStringUtf8(xw.draw, fg, frc[i].font,
+ xp, winy + frc[i].font->ascent,
(FcChar8 *)u8c, u8cblen);
- xp += font->width;
+ xp += CEIL(font->width * cwscale);
}
/*
xw.state &= ~WIN_VISIBLE;
}
+void
+xsetpointermotion(int set) {
+ MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
+ XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
+}
+
void
xseturgency(int add) {
XWMHints *h = XGetWMHints(xw.dpy, xw.win);
XSetICFocus(xw.xic);
xw.state |= WIN_FOCUSED;
xseturgency(0);
+ if(IS_SET(MODE_FOCUS))
+ ttywrite("\033[I", 3);
} else {
XUnsetICFocus(xw.xic);
xw.state &= ~WIN_FOCUSED;
+ if(IS_SET(MODE_FOCUS))
+ ttywrite("\033[O", 3);
}
}
-inline bool
+static inline bool
match(uint mask, uint state) {
- state &= ~(ignoremod);
+ state &= ~ignoremod;
if(mask == XK_NO_MOD && state)
return false;
if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
return false;
- if((state & mask) != state)
- return false;
- return true;
+ if(mask == XK_ANY_MOD)
+ return true;
+ return state == mask;
}
void
char*
kmap(KeySym k, uint state) {
- uint mask;
Key *kp;
int i;
}
for(kp = key; kp < key + LEN(key); kp++) {
- mask = kp->mask;
-
if(kp->k != k)
continue;
- if(!match(mask, state))
+ if(!match(kp->mask, state))
continue;
if(kp->appkey > 0) {
if(len == 1 && e->state & Mod1Mask) {
if(IS_SET(MODE_8BIT)) {
if(*xstr < 0177) {
- c = *xstr | B7;
+ c = *xstr | 0x80;
ret = utf8encode(&c, cp);
cp += ret;
len = 0;
void
run(void) {
XEvent ev;
+ int w = xw.w, h = xw.h;
fd_set rfd;
int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
struct timeval drawtimeout, *tv = NULL, now, last, lastblink;
+ /* Waiting for window mapping */
+ while(1) {
+ XNextEvent(xw.dpy, &ev);
+ if(ev.type == ConfigureNotify) {
+ w = ev.xconfigure.width;
+ h = ev.xconfigure.height;
+ } else if(ev.type == MapNotify) {
+ break;
+ }
+ }
+
+ if(!xw.isfixed)
+ cresize(w, h);
+ else
+ cresize(xw.fw, xw.fh);
+ ttynew();
+
gettimeofday(&lastblink, NULL);
gettimeofday(&last, NULL);
main(int argc, char *argv[]) {
int bitm, xr, yr;
uint wr, hr;
+ char *titles;
xw.fw = xw.fh = xw.fx = xw.fy = 0;
xw.isfixed = False;
break;
case 'e':
/* eat all remaining arguments */
- if(argc > 1)
+ if(argc > 1) {
opt_cmd = &argv[1];
+ if(argv[1] != NULL && opt_title == NULL) {
+ titles = strdup(argv[1]);
+ opt_title = basename(titles);
+ }
+ }
goto run;
case 'f':
opt_font = EARGF(usage());
XSetLocaleModifiers("");
tnew(80, 24);
xinit();
- ttynew();
selinit();
- if(xw.isfixed)
- cresize(xw.h, xw.w);
run();
return 0;