#define USAGE \
"st " VERSION " (c) 2010-2012 st engineers\n" \
- "usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
+ "usage: st [-t title] [-c class] [-g geometry]" \
+ " [-w windowid] [-v] [-f file] [-e command...]\n"
/* XEMBED messages */
#define XEMBED_FOCUS_IN 4
#define SELECT_TIMEOUT (20*1000) /* 20 ms */
#define DRAW_TIMEOUT (20*1000) /* 20 ms */
+#define REDRAW_TIMEOUT (80*1000) /* 80 ms */
#define SERRNO strerror(errno)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
};
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,
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 '[' [[ [<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 */
XIM xim;
XIC xic;
int scr;
+ Bool isfixed; /* is fixed geometry? */
+ int fx, fy, fw, fh; /* fixed geometry */
int w; /* window width */
int h; /* window height */
int ch; /* char height */
struct {int x, y;} b, e;
char *clip;
Atom xtarget;
+ bool alt;
struct timeval tclick1;
struct timeval tclick2;
} Selection;
static void die(const char*, ...);
static void draw(void);
+static void redraw(void);
static void drawregion(int, int, int, int);
static void execsh(void);
static void sigchld(int);
static void tmoveto(int, int);
static void tnew(int, int);
static void tnewline(int);
-static void tputtab(void);
+static void tputtab(bool);
static void tputc(char*);
static void treset(void);
static int tresize(int, int);
static void tsetscroll(int, int);
static void tswapscreen(void);
static void tsetdirt(int, int);
+static void tsetmode(bool, bool, int *, int);
static void tfulldirt(void);
static void ttynew(void);
static int cmdfd;
static pid_t pid;
static Selection sel;
+static FILE *fileio;
static char **opt_cmd = NULL;
+static char *opt_io = NULL;
static char *opt_title = NULL;
static char *opt_embed = NULL;
static char *opt_class = NULL;
int state = e->xbutton.state;
char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
static int ob, ox, oy;
-
+
/* from urxvt */
if(e->xbutton.type == MotionNotify) {
if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
ox = x, oy = y;
}
}
-
+
buf[3] = 32 + button + (state & ShiftMask ? 4 : 0)
+ (state & Mod4Mask ? 8 : 0)
+ (state & ControlMask ? 16 : 0);
-
+
ttywrite(buf, sizeof(buf));
}
}
*ptr = 0;
}
+ sel.alt = IS_SET(MODE_ALTSCREEN);
xsetsel(str);
}
void
ttynew(void) {
int m, s;
-
+
/* seems to work fine on linux, openbsd and freebsd */
struct winsize w = {term.row, term.col, 0, 0};
if(openpty(&m, &s, NULL, NULL, &w) < 0)
close(s);
cmdfd = m;
signal(SIGCHLD, sigchld);
+ if(opt_io && !(fileio = fopen(opt_io, "w"))) {
+ fprintf(stderr, "Error opening %s:%s\n",
+ opt_io, strerror(errno));
+ }
}
}
w.ws_row = term.row;
w.ws_col = term.col;
+ w.ws_xpixel = xw.w;
+ w.ws_ypixel = xw.h;
w.ws_xpixel = w.ws_ypixel = 0;
if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
- for (i = TAB; i < term.col; i += TAB)
+ for(i = TAB; i < term.col; i += TAB)
term.tabs[i] = 1;
term.top = 0, term.bot = term.row - 1;
term.mode = MODE_WRAP;
tscrolldown(int orig, int n) {
int i;
Line temp;
-
+
LIMIT(n, 0, term.bot-orig+1);
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
-
+
for(i = term.bot; i >= orig+n; i--) {
temp = term.line[i];
term.line[i] = term.line[i-n];
int i;
Line temp;
LIMIT(n, 0, term.bot-orig+1);
-
+
tclearregion(0, orig, term.col-1, orig+n-1);
-
+
for(i = orig; i <= term.bot-n; i++) {
temp = term.line[i];
term.line[i] = term.line[i+n];
selscroll(int orig, int n) {
if(sel.bx == -1)
return;
-
+
if(BETWEEN(sel.by, orig, term.bot) || BETWEEN(sel.ey, orig, term.bot)) {
if((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
sel.bx = -1;
csiescseq.narg = 0;
if(*p == '?')
csiescseq.priv = 1, p++;
-
+
while(p < csiescseq.buf+csiescseq.len) {
while(isdigit(*p)) {
csiescseq.arg[csiescseq.narg] *= 10;
int src = term.c.x + n;
int dst = term.c.x;
int size = term.col - src;
-
+
term.dirty[term.c.y] = 1;
if(src >= term.col) {
case 1:
term.c.attr.mode |= ATTR_BOLD;
break;
+ case 3: /* enter standout (highlight) mode TODO: make it italic */
+ term.c.attr.mode |= ATTR_REVERSE;
+ break;
case 4:
term.c.attr.mode |= ATTR_UNDERLINE;
break;
case 22:
term.c.attr.mode &= ~ATTR_BOLD;
break;
+ case 23: /* leave standout (highlight) mode TODO: make it italic */
+ term.c.attr.mode &= ~ATTR_REVERSE;
+ break;
case 24:
term.c.attr.mode &= ~ATTR_UNDERLINE;
break;
fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
}
else
- fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
+ fprintf(stderr, "erresc(38): gfx attr %d unknown\n", attr[i]);
break;
case 39:
term.c.attr.fg = DefaultFG;
fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
}
else
- fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
+ fprintf(stderr, "erresc(48): gfx attr %d unknown\n", attr[i]);
break;
case 49:
term.c.attr.bg = DefaultBG;
else if(BETWEEN(attr[i], 100, 107))
term.c.attr.fg = attr[i] - 100 + 8;
else
- fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]), csidump();
-
+ fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]), csidump();
break;
}
}
term.bot = b;
}
+#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+
+void
+tsetmode(bool priv, bool set, int *args, int narg) {
+ int *lim, mode;
+
+ for(lim = args + narg; args < lim; ++args) {
+ if(priv) {
+ switch(*args) {
+ case 1:
+ MODBIT(term.mode, set, MODE_APPKEYPAD);
+ break;
+ case 5: /* DECSCNM -- Reverve video */
+ mode = term.mode;
+ MODBIT(term.mode,set, MODE_REVERSE);
+ if(mode != term.mode)
+ redraw();
+ break;
+ case 7:
+ MODBIT(term.mode, set, MODE_WRAP);
+ break;
+ case 20:
+ MODBIT(term.mode, set, MODE_CRLF);
+ break;
+ case 12: /* att610 -- Start blinking cursor (IGNORED) */
+ break;
+ case 25:
+ MODBIT(term.c.state, !set, CURSOR_HIDE);
+ break;
+ case 1000: /* 1000,1002: enable xterm mouse report */
+ MODBIT(term.mode, set, MODE_MOUSEBTN);
+ break;
+ case 1002:
+ MODBIT(term.mode, set, MODE_MOUSEMOTION);
+ break;
+ case 1049: /* = 1047 and 1048 */
+ case 47:
+ case 1047:
+ if(IS_SET(MODE_ALTSCREEN))
+ tclearregion(0, 0, term.col-1, term.row-1);
+ if((set && !IS_SET(MODE_ALTSCREEN)) ||
+ (!set && IS_SET(MODE_ALTSCREEN))) {
+ tswapscreen();
+ }
+ if(*args != 1049)
+ break;
+ /* pass through */
+ case 1048:
+ tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+ break;
+ default:
+ fprintf(stderr,
+ "erresc: unknown private set/reset mode %d\n",
+ *args);
+ break;
+ }
+ } else {
+ switch(*args) {
+ case 4:
+ MODBIT(term.mode, set, MODE_INSERT);
+ break;
+ default:
+ fprintf(stderr,
+ "erresc: unknown set/reset mode %d\n",
+ *args);
+ break;
+ }
+ }
+ }
+}
+#undef MODBIT
+
+
void
csihandle(void) {
switch(csiescseq.mode) {
}
break;
case 'G': /* CHA -- Move to <col> */
- case '`': /* XXX: HPA -- same? */
+ case '`': /* HPA */
DEFAULT(csiescseq.arg[0], 1);
tmoveto(csiescseq.arg[0]-1, term.c.y);
break;
case 'H': /* CUP -- Move to <row> <col> */
- case 'f': /* XXX: HVP -- same? */
+ case 'f': /* HVP */
DEFAULT(csiescseq.arg[0], 1);
DEFAULT(csiescseq.arg[1], 1);
tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1);
break;
case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
DEFAULT(csiescseq.arg[0], 1);
- while (csiescseq.arg[0]--)
- tputtab();
+ while(csiescseq.arg[0]--)
+ tputtab(1);
break;
case 'J': /* ED -- Clear screen */
sel.bx = -1;
tinsertblankline(csiescseq.arg[0]);
break;
case 'l': /* RM -- Reset Mode */
- if(csiescseq.priv) {
- switch(csiescseq.arg[0]) {
- case 1:
- term.mode &= ~MODE_APPKEYPAD;
- break;
- case 5: /* DECSCNM -- Remove reverse video */
- if(IS_SET(MODE_REVERSE)) {
- term.mode &= ~MODE_REVERSE;
- draw();
- }
- break;
- case 7:
- term.mode &= ~MODE_WRAP;
- break;
- case 12: /* att610 -- Stop blinking cursor (IGNORED) */
- break;
- case 20:
- term.mode &= ~MODE_CRLF;
- break;
- case 25:
- term.c.state |= CURSOR_HIDE;
- break;
- case 1000: /* disable X11 xterm mouse reporting */
- term.mode &= ~MODE_MOUSEBTN;
- break;
- case 1002:
- term.mode &= ~MODE_MOUSEMOTION;
- break;
- case 1049: /* = 1047 and 1048 */
- case 47:
- case 1047:
- if(IS_SET(MODE_ALTSCREEN)) {
- tclearregion(0, 0, term.col-1, term.row-1);
- tswapscreen();
- }
- if(csiescseq.arg[0] != 1049)
- break;
- case 1048:
- tcursor(CURSOR_LOAD);
- break;
- default:
- goto unknown;
- }
- } else {
- switch(csiescseq.arg[0]) {
- case 4:
- term.mode &= ~MODE_INSERT;
- break;
- default:
- goto unknown;
- }
- }
+ tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg);
break;
case 'M': /* DL -- Delete <n> lines */
DEFAULT(csiescseq.arg[0], 1);
DEFAULT(csiescseq.arg[0], 1);
tdeletechar(csiescseq.arg[0]);
break;
- /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
+ case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
+ DEFAULT(csiescseq.arg[0], 1);
+ while(csiescseq.arg[0]--)
+ tputtab(0);
+ break;
case 'd': /* VPA -- Move to <row> */
DEFAULT(csiescseq.arg[0], 1);
tmoveto(term.c.x, csiescseq.arg[0]-1);
break;
case 'h': /* SM -- Set terminal mode */
- if(csiescseq.priv) {
- switch(csiescseq.arg[0]) {
- case 1:
- term.mode |= MODE_APPKEYPAD;
- break;
- case 5: /* DECSCNM -- Reverve video */
- if(!IS_SET(MODE_REVERSE)) {
- term.mode |= MODE_REVERSE;
- draw();
- }
- break;
- case 7:
- term.mode |= MODE_WRAP;
- break;
- case 20:
- term.mode |= MODE_CRLF;
- break;
- case 12: /* att610 -- Start blinking cursor (IGNORED) */
- /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
- if(csiescseq.narg > 1 && csiescseq.arg[1] != 25)
- break;
- case 25:
- term.c.state &= ~CURSOR_HIDE;
- break;
- case 1000: /* 1000,1002: enable xterm mouse report */
- term.mode |= MODE_MOUSEBTN;
- break;
- case 1002:
- term.mode |= MODE_MOUSEMOTION;
- break;
- case 1049: /* = 1047 and 1048 */
- case 47:
- case 1047:
- if(IS_SET(MODE_ALTSCREEN))
- tclearregion(0, 0, term.col-1, term.row-1);
- else
- tswapscreen();
- if(csiescseq.arg[0] != 1049)
- break;
- case 1048:
- tcursor(CURSOR_SAVE);
- break;
- default: goto unknown;
- }
- } else {
- switch(csiescseq.arg[0]) {
- case 4:
- term.mode |= MODE_INSERT;
- break;
- default: goto unknown;
- }
- };
+ tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg);
break;
case 'm': /* SGR -- Terminal attribute (color) */
tsetattr(csiescseq.arg, csiescseq.narg);
strhandle(void) {
char *p;
- p = strescseq.buf;
+ /*
+ * TODO: make this being useful in case of color palette change.
+ */
+ strparse();
+
+ p = strescseq.buf;
switch(strescseq.type) {
case ']': /* OSC -- Operating System Command */
switch(p[0]) {
case '0':
+ case '1':
case '2':
/*
* TODO: Handle special chars in string, like umlauts.
*/
if(p[1] == ';') {
- if(!strncmp(strescseq.buf, "settitle ", 9)) {
- XStoreName(xw.dpy, xw.win, strescseq.buf+11);
- } else {
- XStoreName(xw.dpy, xw.win, strescseq.buf+2);
- }
+ XStoreName(xw.dpy, xw.win, strescseq.buf+2);
}
break;
case ';':
}
void
-tputtab(void) {
- unsigned x;
+tputtab(bool forward) {
+ unsigned x = term.c.x;
- for (x = term.c.x + 1; x < term.col && !term.tabs[x]; ++x)
- /* nothing */ ;
+ if(forward) {
+ if(x == term.col)
+ return;
+ for(++x; x < term.col && !term.tabs[x]; ++x)
+ /* nothing */ ;
+ } else {
+ if(x == 0)
+ return;
+ for(--x; x > 0 && !term.tabs[x]; --x)
+ /* nothing */ ;
+ }
tmoveto(x, term.c.y);
}
void
tputc(char *c) {
char ascii = *c;
+
+ if(fileio)
+ putc(ascii, fileio);
+
if(term.esc & ESC_START) {
if(term.esc & ESC_CSI) {
csiescseq.buf[csiescseq.len++] = ascii;
break;
default:
strescseq.buf[strescseq.len++] = ascii;
- if (strescseq.len+1 >= STR_BUF_SIZ) {
+ if(strescseq.len+1 >= STR_BUF_SIZ) {
term.esc = 0;
strhandle();
}
sel.bx = -1;
switch(ascii) {
case '\t':
- tputtab();
+ tputtab(1);
break;
case '\b':
tmoveto(term.c.x-1, term.c.y);
term.line[i] = calloc(col, sizeof(Glyph));
term.alt [i] = calloc(col, sizeof(Glyph));
}
- if (col > term.col) {
+ if(col > term.col) {
bool *bp = term.tabs + term.col;
memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
- while (--bp > term.tabs && !*bp)
+ while(--bp > term.tabs && !*bp)
/* nothing */ ;
- for (bp += TAB; bp < term.tabs + col; bp += TAB)
+ for(bp += TAB; bp < term.tabs + col; bp += TAB)
*bp = 1;
}
/* update terminal size */
} else
dc.col[i] = color.pixel;
}
-
+
/* load colors [16-255] ; same colors as xterm */
for(i = 16, r = 0; r < 6; r++)
for(g = 0; g < 6; g++)
for(r = 0; r < 24; r++, i++) {
color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
- if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
+ if(!XAllocColor(xw.dpy, xw.cmap, &color)) {
dc.col[i] = white;
fprintf(stderr, "Could not allocate color %d\n", i);
} else
xclear(int x1, int y1, int x2, int y2) {
XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
XFillRectangle(xw.dpy, xw.buf, dc.gc,
- BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
- (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
+ BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
+ (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
}
void
xhints(void) {
XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
XWMHints wm = {.flags = InputHint, .input = 1};
- XSizeHints size = {
- .flags = PSize | PResizeInc | PBaseSize,
- .height = xw.h,
- .width = xw.w,
- .height_inc = xw.ch,
- .width_inc = xw.cw,
- .base_height = 2*BORDER,
- .base_width = 2*BORDER,
- };
- XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
+ XSizeHints *sizeh = NULL;
+
+ sizeh = XAllocSizeHints();
+ if(xw.isfixed == False) {
+ sizeh->flags = PSize | PResizeInc | PBaseSize;
+ sizeh->height = xw.h;
+ sizeh->width = xw.w;
+ sizeh->height_inc = xw.ch;
+ sizeh->width_inc = xw.cw;
+ sizeh->base_height = 2*BORDER;
+ sizeh->base_width = 2*BORDER;
+ } else {
+ sizeh->flags = PMaxSize | PMinSize;
+ sizeh->min_width = sizeh->max_width = xw.fw;
+ sizeh->min_height = sizeh->max_height = xw.fh;
+ }
+
+ XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class);
+ XFree(sizeh);
}
XFontSet
XSetWindowAttributes attrs;
Cursor cursor;
Window parent;
+ int sw, sh;
if(!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n");
xw.scr = XDefaultScreen(xw.dpy);
-
+
+ /* adjust fixed window geometry */
+ if(xw.isfixed) {
+ sw = DisplayWidth(xw.dpy, xw.scr);
+ sh = DisplayHeight(xw.dpy, xw.scr);
+ if(xw.fx < 0)
+ xw.fx = sw + xw.fx - xw.fw - 1;
+ if(xw.fy < 0)
+ xw.fy = sh + xw.fy - xw.fh - 1;
+
+ xw.h = xw.fh;
+ xw.w = xw.fw;
+ } else {
+ /* window - default size */
+ xw.h = 2*BORDER + term.row * xw.ch;
+ xw.w = 2*BORDER + term.col * xw.cw;
+ xw.fx = 0;
+ xw.fy = 0;
+ }
+
/* font */
initfonts(FONT, BOLDFONT);
xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
xloadcols();
- /* window - default size */
- xw.h = 2*BORDER + term.row * xw.ch;
- xw.w = 2*BORDER + term.col * xw.cw;
-
attrs.background_pixel = dc.col[DefaultBG];
attrs.border_pixel = dc.col[DefaultBG];
attrs.bit_gravity = NorthWestGravity;
attrs.colormap = xw.cmap;
parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
- xw.win = XCreateWindow(xw.dpy, parent, 0, 0,
+ xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
XDefaultVisual(xw.dpy, xw.scr),
CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
XNFocusWindow, xw.win, NULL);
/* gc */
dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
-
+
/* white cursor, black outline */
cursor = XCreateFontCursor(xw.dpy, XC_xterm);
XDefineCursor(xw.dpy, xw.win, cursor);
int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
XFontSet fontset = dc.font.set;
int i;
-
+
/* only switch default fg/bg if term is in RV mode */
if(IS_SET(MODE_REVERSE)) {
if(fg == DefaultFG)
}
XmbDrawImageString(xw.dpy, xw.buf, fontset, dc.gc, winx, winy, s, bytelen);
-
+
if(base.mode & ATTR_UNDERLINE)
XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
}
/* copy buffer pixmap to screen pixmap */
void
xcopy() {
- XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
- XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+ XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+ XdbeSwapBuffers(xw.dpy, swpinfo, 1);
}
static int oldy = 0;
int sl;
Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
-
+
LIMIT(oldx, 0, term.col-1);
LIMIT(oldy, 0, term.row-1);
-
+
if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
xcopy(term.c.x, term.c.y, 1, 1);
}
+void
+redraw(void) {
+ struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
+ tfulldirt();
+ draw();
+ nanosleep(&tv, NULL);
+}
+
void
draw() {
drawregion(0, 0, term.col, term.row);
int ic, ib, x, y, ox, sl;
Glyph base, new;
char buf[DRAW_BUF_SIZ];
+ bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN);
+ if((sel.alt && !alt) || (!sel.alt && alt))
+ ena_sel = 0;
if(!(xw.state & WIN_VISIBLE))
return;
ic = ib = ox = 0;
for(x = x1; x < x2; x++) {
new = term.line[y][x];
- if(sel.bx != -1 && *(new.c) && selected(x, y))
+ if(ena_sel && *(new.c) && selected(x, y))
new.mode ^= ATTR_REVERSE;
if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
if(xw.state & WIN_REDRAW) {
if(!e->count)
xw.state &= ~WIN_REDRAW;
- }
- xcopy();
+ }
+ xcopy();
}
void
meta = e->state & Mod1Mask;
shift = e->state & ShiftMask;
len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
-
+
/* 1. custom keys from config.h */
if((customkey = kmap(ksym, e->state)))
ttywrite(customkey, strlen(customkey));
cmessage(XEvent *e) {
/* See xembed specs
http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
- if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
- if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
+ if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
+ if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
xw.state |= WIN_FOCUSED;
xseturgency(0);
- } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+ } else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
xw.state &= ~WIN_FOCUSED;
}
draw();
void
resize(XEvent *e) {
int col, row;
-
+
if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
return;
-
+
xw.w = e->xconfigure.width;
xw.h = e->xconfigure.height;
col = (xw.w - 2*BORDER) / xw.cw;
return;
if(tresize(col, row))
draw();
- ttyresize(col, row);
xresize(col, row);
+ ttyresize(col, row);
}
bool
int xfd = XConnectionNumber(xw.dpy);
struct timeval timeout = {0};
bool stuff_to_print = 0;
-
+
for(;;) {
FD_ZERO(&rfd);
FD_SET(cmdfd, &rfd);
int
main(int argc, char *argv[]) {
- int i;
-
+ int i, bitm, xr, yr;
+ unsigned int wr, hr;
+
+ xw.fw = xw.fh = xw.fx = xw.fy = 0;
+ xw.isfixed = False;
+
for(i = 1; i < argc; i++) {
switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
case 't':
case 'w':
if(++i < argc) opt_embed = argv[i];
break;
+ case 'f':
+ if(++i < argc) opt_io = argv[i];
+ break;
case 'e':
/* eat every remaining arguments */
if(++i < argc) opt_cmd = &argv[i];
goto run;
+ case 'g':
+ if(++i >= argc)
+ break;
+
+ bitm = XParseGeometry(argv[i], &xr, &yr, &wr, &hr);
+ if(bitm & XValue)
+ xw.fx = xr;
+ if(bitm & YValue)
+ xw.fy = yr;
+ if(bitm & WidthValue)
+ xw.fw = (int)wr;
+ if(bitm & HeightValue)
+ xw.fh = (int)hr;
+ if(bitm & XNegative && xw.fx == 0)
+ xw.fx = -1;
+ if(bitm & XNegative && xw.fy == 0)
+ xw.fy = -1;
+
+ if(xw.fh != 0 && xw.fw != 0)
+ xw.isfixed = True;
+ break;
case 'v':
default:
die(USAGE);
run();
return 0;
}
+