#include <X11/keysym.h>
#include <X11/Xutil.h>
+#if defined(__linux)
+ #include <pty.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__)
+ #include <util.h>
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <libutil.h>
+#endif
+
/* Arbitrary sizes */
#define ESC_TITLE_SIZ 256
#define ESC_BUF_SIZ 256
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
+#define IS_SET(flag) (term.mode & (flag))
/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW,
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8 };
enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
enum { SCREEN_UPDATE, SCREEN_REDRAW };
Glyph attr; /* current char attributes */
int x;
int y;
+ char state;
} TCursor;
/* CSI Escape sequence structs */
typedef struct {
int row; /* nb row */
int col; /* nb col */
- Line* line; /* screen */
+ Line* line; /* screen */
+ Line* alt; /* alternate screen */
TCursor c; /* cursor */
- char hidec;
int top; /* top scroll limit */
int bot; /* bottom scroll limit */
int mode; /* terminal mode flags */
int bufh; /* pixmap height */
int ch; /* char height */
int cw; /* char width */
+ int hasfocus;
} XWindow;
typedef struct {
static void tclearregion(int, int, int, int);
static void tcursor(int);
-static void tmovecursor(int);
static void tdeletechar(int);
static void tdeleteline(int);
static void tinsertblank(int);
static void tmoveto(int, int);
static void tnew(int, int);
static void tnewline(void);
+static void tputtab(void);
static void tputc(char);
static void tputs(char*, int);
static void treset(void);
static void tresize(int, int);
-static void tscroll(void);
static void tscrollup(int);
static void tscrolldown(int);
static void tsetattr(int*, int);
static void tsetchar(char);
static void tsetscroll(int, int);
+static void tswapscreen(void);
static void ttynew(void);
static void ttyread(void);
static void ttyresize(int, int);
static void ttywrite(const char *, size_t);
+static void xdraws(char *, Glyph, int, int, int);
+static void xhints(void);
static void xclear(int, int, int, int);
-static void xcursor(int);
+static void xdrawcursor(void);
static void xinit(void);
static void xloadcols(void);
+static void xseturgency(int);
static void expose(XEvent *);
static char* kmap(KeySym);
static void kpress(XEvent *);
static void resize(XEvent *);
+static void focus(XEvent *);
+static void brelease(XEvent *e);
+static void bpress(XEvent *e);
+static void bmotion(XEvent *e);
+
static void (*handler[LASTEvent])(XEvent *) = {
[KeyPress] = kpress,
[Expose] = expose,
- [ConfigureNotify] = resize
+ [ConfigureNotify] = resize,
+ [FocusIn] = focus,
+ [FocusOut] = focus,
+ [MotionNotify] = bmotion,
+ [ButtonPress] = bpress,
+ [ButtonRelease] = brelease,
};
/* Globals */
static CSIEscape escseq;
static int cmdfd;
static pid_t pid;
-static int running;
+
+/* selection */
+// TODO: use X11 clipboard
+static int selmode = 0;
+static int selbx = -1, selby;
+static int selex, seley;
+int sb[2], se[2];
+static const char *clipboard = NULL;
+
+static inline int selected(int x, int y) {
+ if ((seley==y && selby==y)) {
+ int bx = MIN(selbx, selex);
+ int ex = MAX(selbx, selex);
+ return (x>=bx && x<=ex);
+ }
+ return (((y>sb[1] && y<se[1]) || (y==se[1] && x<=se[0])) || \
+ (y==sb[1] && x>=sb[0] && (x<=se[0] || sb[1]!=se[1])));
+}
+
+static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
+ if(b) *b = e->xbutton.state,
+ *b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
+ *x = e->xbutton.x/xw.cw;
+ *y = e->xbutton.y/xw.ch;
+ sb[0] = selby<seley?selbx:selex;
+ sb[1] = MIN(selby, seley);
+ se[0] = selby<seley?selex:selbx;
+ se[1] = MAX(selby, seley);
+}
+
+static void bpress(XEvent *e) {
+ selmode = 1;
+ selex = selbx = e->xbutton.x/xw.cw;
+ seley = selby = e->xbutton.y/xw.ch;
+}
+
+static char *getseltext() {
+ char *str, *ptr;
+ int ls, x, y, sz;
+ if(selbx==-1)
+ return NULL;
+ sz = ((xw.w/xw.ch) * (se[1]-sb[1]+2));
+ ptr = str = malloc (sz);
+ for(y = 0; y < term.row; y++) {
+ for(x = 0; x < term.col; x++) {
+ if(term.line[y][x].c && (ls=selected(x, y))) {
+ *ptr = term.line[y][x].c;
+ ptr++;
+ }
+ }
+ if (ls) {
+ *ptr = '\n';
+ ptr++;
+ }
+ }
+ *ptr = 0;
+ return str;
+}
+
+static void clipboard_copy(const char *str) {
+ free((void *)clipboard);
+ clipboard = str;
+}
+
+static void clipboard_paste() {
+ if(clipboard)
+ ttywrite(clipboard, strlen(clipboard));
+}
+
+// TODO: doubleclick to select word
+static void brelease(XEvent *e) {
+ int b;
+ selmode = 0;
+ getbuttoninfo(e, &b, &selex, &seley);
+ if(b==4)
+ tscrollup(1);
+ else
+ if(b==5)
+ tscrolldown(1);
+ else
+ if(selbx==selex && selby==seley) {
+ selbx = -1;
+ if(b==2)
+ clipboard_paste();
+ } else {
+ if(b==1)
+ clipboard_copy(getseltext());
+ }
+ draw(1);
+}
+
+static void bmotion(XEvent *e) {
+ if (selmode) {
+ getbuttoninfo(e, NULL, &selex, &seley);
+ draw(1);
+ }
+}
#ifdef DEBUG
void
void
execsh(void) {
char *args[3] = {getenv("SHELL"), "-i", NULL};
- DEFAULT(args[0], "/bin/sh"); /* default shell if getenv() failed */
+ DEFAULT(args[0], SHELL); /* if getenv() failed */
putenv("TERM=" TNAME);
execvp(args[0], args);
}
-void
-xbell(void) { /* visual bell */
- XRectangle r = { BORDER, BORDER, xw.bufw, xw.bufh };
- XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
- XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
- /* usleep(30000); */
- draw(SCREEN_REDRAW);
-}
-
void
sigchld(int a) {
int stat = 0;
void
ttynew(void) {
int m, s;
- char *pts;
-
- if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
- die("openpt failed: %s\n", SERRNO);
- if(grantpt(m) < 0)
- die("grandpt failed: %s\n", SERRNO);
- if(unlockpt(m) < 0)
- die("unlockpt failed: %s\n", SERRNO);
- if(!(pts = ptsname(m)))
- die("ptsname failed: %s\n", SERRNO);
- if((s = open(pts, O_RDWR | O_NOCTTY)) < 0)
- die("Couldn't open slave: %s\n", SERRNO);
- fcntl(s, F_SETFL, O_NDELAY);
+
+ /* 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)
+ die("openpty failed: %s\n", SERRNO);
+
switch(pid = fork()) {
case -1:
die("fork failed\n");
dup2(s, STDOUT_FILENO);
dup2(s, STDERR_FILENO);
if(ioctl(s, TIOCSCTTY, NULL) < 0)
- die("ioctl TTIOCSTTY failed: %s\n", SERRNO);
+ die("ioctl TIOCSCTTY failed: %s\n", SERRNO);
+ close(s);
+ close(m);
execsh();
break;
default:
void
treset(void) {
- term.c.attr.mode = ATTR_NULL;
- term.c.attr.fg = DefaultFG;
- term.c.attr.bg = DefaultBG;
- term.c.x = term.c.y = 0;
- term.hidec = 0;
+ term.c = (TCursor){{
+ .mode = ATTR_NULL,
+ .fg = DefaultFG,
+ .bg = DefaultBG
+ }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
+
term.top = 0, term.bot = term.row - 1;
term.mode = MODE_WRAP;
tclearregion(0, 0, term.col-1, term.row-1);
}
void
-tnew(int col, int row) { /* screen size */
+tnew(int col, int row) {
+ /* set screen size */
term.row = row, term.col = col;
- term.top = 0, term.bot = term.row - 1;
- /* mode */
- term.mode = MODE_WRAP;
- /* cursor */
- term.c.attr.mode = ATTR_NULL;
- term.c.attr.fg = DefaultFG;
- term.c.attr.bg = DefaultBG;
- term.c.x = term.c.y = 0;
- term.hidec = 0;
- /* allocate screen */
- term.line = calloc(term.row, sizeof(Line));
- for(row = 0 ; row < term.row; row++)
- term.line[row] = calloc(term.col, sizeof(Glyph));
+ term.line = malloc(term.row * sizeof(Line));
+ term.alt = malloc(term.row * sizeof(Line));
+ for(row = 0 ; row < term.row; row++) {
+ term.line[row] = malloc(term.col * sizeof(Glyph));
+ term.alt [row] = malloc(term.col * sizeof(Glyph));
+ }
+ /* setup screen */
+ treset();
}
-/* TODO: Replace with scrollup/scolldown */
void
-tscroll(void) {
- Line temp = term.line[term.top];
- int i;
-
- for(i = term.top; i < term.bot; i++)
- term.line[i] = term.line[i+1];
- memset(temp, 0, sizeof(Glyph) * term.col);
- term.line[term.bot] = temp;
+tswapscreen(void) {
+ Line* tmp = term.line;
+ term.line = term.alt;
+ term.alt = tmp;
+ term.mode ^= MODE_ALTSCREEN;
}
void
for(i = 0; i < n; i++)
memset(term.line[term.top+i], 0, term.col*sizeof(Glyph));
- for(i = term.top; i <= term.bot-n; i++) {
+ for(i = term.top; i <= term.bot-n; i++) {
temp = term.line[i];
term.line[i] = term.line[i+n];
term.line[i+n] = temp;
- }
+ }
}
void
tnewline(void) {
int y = term.c.y + 1;
if(y > term.bot)
- tscroll(), y = term.bot;
+ tscrollup(1), y = term.bot;
tmoveto(0, y);
}
void
tmoveto(int x, int y) {
- term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x;
- term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y;
+ LIMIT(x, 0, term.col-1);
+ LIMIT(y, 0, term.row-1);
+ term.c.state &= ~CURSOR_WRAPNEXT;
+ term.c.x = x;
+ term.c.y = y;
}
-void
-tmovecursor(int dir) {
- int xf = term.c.x, yf = term.c.y;
-
- switch(dir) {
- case CURSOR_UP:
- yf--;
- break;
- case CURSOR_DOWN:
- yf++;
- break;
- case CURSOR_LEFT:
- xf--;
- if(term.mode & MODE_WRAP && xf < 0) {
- xf = term.col-1, yf--;
- if(yf < term.top)
- yf = term.top, xf = 0;
- }
- break;
- case CURSOR_RIGHT:
- xf++;
- if(term.mode & MODE_WRAP && xf >= term.col) {
- xf = 0, yf++;
- if(yf > term.bot)
- yf = term.bot, tscroll();
- }
- break;
- }
- tmoveto(xf, yf);
-}
-
void
tsetchar(char c) {
term.line[term.c.y][term.c.x] = term.c.attr;
case 12: /* att610 -- Stop blinking cursor (IGNORED) */
break;
case 25:
- term.hidec = 1;
+ term.c.state |= CURSOR_HIDE;
break;
- case 1048: /* XXX: no alt. screen to erase/save */
- case 1049:
+ case 1049: /* = 1047 and 1048 */
+ case 1047:
+ if(IS_SET(MODE_ALTSCREEN)) {
+ tclearregion(0, 0, term.col-1, term.row-1);
+ tswapscreen();
+ }
+ if(escseq.arg[0] == 1047)
+ break;
+ case 1048:
tcursor(CURSOR_LOAD);
- tclearregion(0, 0, term.col-1, term.row-1);
break;
default:
goto unknown;
case 12: /* att610 -- Start blinking cursor (IGNORED) */
break;
case 25:
- term.hidec = 0;
+ term.c.state &= ~CURSOR_HIDE;
break;
- case 1048:
- case 1049: /* XXX: no alt. screen to erase/save */
+ case 1049: /* = 1047 and 1048 */
+ case 1047:
+ if(IS_SET(MODE_ALTSCREEN))
+ tclearregion(0, 0, term.col-1, term.row-1);
+ else
+ tswapscreen();
+ if(escseq.arg[0] == 1047)
+ break;
+ case 1048:
tcursor(CURSOR_SAVE);
- tclearregion(0, 0, term.col-1, term.row-1);
break;
default: goto unknown;
}
DEFAULT(escseq.arg[0], 1);
DEFAULT(escseq.arg[1], term.row);
tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+ tmoveto(0, 0);
}
break;
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
void
tputtab(void) {
int space = TAB - term.c.x % TAB;
-
- if(term.c.x + space >= term.col)
- space--;
-
- for(; space > 0; space--)
- tmovecursor(CURSOR_RIGHT);
+ tmoveto(term.c.x + space, term.c.y);
}
void
case '(':
term.esc |= ESC_ALTCHARSET;
break;
- case 'A':
- tmoveto(term.c.x, term.c.y-1);
- term.esc = 0;
- break;
- case 'B':
- tmoveto(term.c.x, term.c.y+1);
- term.esc = 0;
- break;
- case 'C':
- tmoveto(term.c.x+1, term.c.y);
- term.esc = 0;
- break;
- case 'D': /* XXX: CUP (VT100) or IND (VT52) ... */
- tmoveto(term.c.x-1, term.c.y);
+ case 'D': /* IND -- Linefeed */
+ if(term.c.y == term.bot)
+ tscrollup(1);
+ else
+ tmoveto(term.c.x, term.c.y+1);
term.esc = 0;
break;
case 'E': /* NEL -- Next line */
treset();
term.esc = 0;
break;
- case '=': /* DECPAM */
+ case '=': /* DECPAM -- Application keypad */
term.mode |= MODE_APPKEYPAD;
term.esc = 0;
break;
- case '>': /* DECPNM */
+ case '>': /* DECPNM -- Normal keypad */
term.mode &= ~MODE_APPKEYPAD;
term.esc = 0;
break;
- case '7':
+ case '7': /* DECSC -- Save Cursor*/
tcursor(CURSOR_SAVE);
term.esc = 0;
break;
- case '8':
+ case '8': /* DECRC -- Restore Cursor */
tcursor(CURSOR_LOAD);
term.esc = 0;
break;
tputtab();
break;
case '\b':
- tmovecursor(CURSOR_LEFT);
+ tmoveto(term.c.x-1, term.c.y);
break;
case '\r':
tmoveto(0, term.c.y);
tnewline();
break;
case '\a':
- xbell();
+ if(!xw.hasfocus)
+ xseturgency(1);
break;
case '\033':
csireset();
term.esc = ESC_START;
break;
default:
+ if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
+ tnewline();
tsetchar(c);
- tmovecursor(CURSOR_RIGHT);
+ if(term.c.x+1 < term.col)
+ tmoveto(term.c.x+1, term.c.y);
+ else
+ term.c.state |= CURSOR_WRAPNEXT;
break;
}
}
void
tresize(int col, int row) {
int i;
- Line *line;
int minrow = MIN(row, term.row);
int mincol = MIN(col, term.col);
if(col < 1 || row < 1)
return;
- /* alloc */
- line = calloc(row, sizeof(Line));
- for(i = 0 ; i < row; i++)
- line[i] = calloc(col, sizeof(Glyph));
- /* copy */
- for(i = 0 ; i < minrow; i++)
- memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
- /* free */
- for(i = 0; i < term.row; i++)
+
+ /* free uneeded rows */
+ for(i = row; i < term.row; i++) {
free(term.line[i]);
- free(term.line);
-
- LIMIT(term.c.x, 0, col-1);
- LIMIT(term.c.y, 0, row-1);
- LIMIT(term.top, 0, row-1);
- LIMIT(term.bot, 0, row-1);
+ free(term.alt[i]);
+ }
+
+ /* resize to new height */
+ term.line = realloc(term.line, row * sizeof(Line));
+ term.alt = realloc(term.alt, row * sizeof(Line));
+
+ /* resize each row to new width, zero-pad if needed */
+ for(i = 0; i < minrow; i++) {
+ term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
+ term.alt[i] = realloc(term.alt[i], col * sizeof(Glyph));
+ memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
+ memset(term.alt[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
+ }
+
+ /* allocate any new rows */
+ for(/* i == minrow */; i < row; i++) {
+ term.line[i] = calloc(col, sizeof(Glyph));
+ term.alt [i] = calloc(col, sizeof(Glyph));
+ }
- term.bot = row-1;
- term.line = line;
+ /* update terminal size */
term.col = col, term.row = row;
+ /* make use of the LIMIT in tmoveto */
+ tmoveto(term.c.x, term.c.y);
+ /* reset scrolling region */
+ tsetscroll(0, row-1);
}
void
void
xinit(void) {
- xw.dis = XOpenDisplay(NULL);
- xw.scr = XDefaultScreen(xw.dis);
- if(!xw.dis)
+ if(!(xw.dis = XOpenDisplay(NULL)))
die("Can't open display\n");
+ xw.scr = XDefaultScreen(xw.dis);
/* font */
if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT)))
/* colors */
xloadcols();
- term.c.attr.fg = DefaultFG;
- term.c.attr.bg = DefaultBG;
- term.c.attr.mode = ATTR_NULL;
/* windows */
xw.h = term.row * xw.ch + 2*BORDER;
xw.w = term.col * xw.cw + 2*BORDER;
xw.bufw = xw.w - 2*BORDER;
xw.bufh = xw.h - 2*BORDER;
xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+ xw.hasfocus = 1;
/* gc */
dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
XMapWindow(xw.dis, xw.win);
}
void
-xcursor(int mode) {
+xdrawcursor(void) {
static int oldx = 0;
static int oldy = 0;
Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
xclear(oldx, oldy, oldx, oldy);
/* draw the new one */
- if(mode == CURSOR_DRAW) {
+ if(!(term.c.state & CURSOR_HIDE) && xw.hasfocus) {
xdraws(&g.c, g, term.c.x, term.c.y, 1);
oldx = term.c.x, oldy = term.c.y;
}
if(term.line[y][x].state & GLYPH_SET)
xdrawc(x, y, term.line[y][x]);
- if(!term.hidec)
- xcursor(CURSOR_DRAW);
+ xdrawcursor();
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
int i, x, y, ox;
Glyph base, new;
char buf[DRAW_BUF_SIZ];
-
+
XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
- XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
+ XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.bufw, xw.bufh);
for(y = 0; y < term.row; y++) {
base = term.line[y][0];
i = ox = 0;
for(x = 0; x < term.col; x++) {
new = term.line[y][x];
- if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ)
- buf[i++] = new.c;
- else {
+ if(selbx!=-1 && new.c && selected(x, y))
+ new.mode ^= ATTR_REVERSE;
+ if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
+ i >= DRAW_BUF_SIZ)) {
xdraws(buf, base, ox, y, i);
- buf[0] = new.c;
- i = 1;
- ox = x;
- base = new;
+ i = 0;
+ }
+ if(new.state & GLYPH_SET) {
+ if(i == 0) {
+ ox = x;
+ base = new;
+ }
+ buf[i++] = new.c;
}
}
- xdraws(buf, base, ox, y, i);
+ if(i > 0)
+ xdraws(buf, base, ox, y, i);
}
- xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW);
+ xdrawcursor();
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
draw(SCREEN_REDRAW);
}
+void
+xseturgency(int add) {
+ XWMHints *h = XGetWMHints(xw.dis, xw.win);
+ h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+ XSetWMHints(xw.dis, xw.win, h);
+ XFree(h);
+}
+
+void
+focus(XEvent *ev) {
+ if((xw.hasfocus = ev->type == FocusIn))
+ xseturgency(0);
+ draw(SCREEN_UPDATE);
+}
+
char*
kmap(KeySym k) {
int i;
case XK_Down:
case XK_Left:
case XK_Right:
- sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]);
+ sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]);
ttywrite(buf, 3);
break;
case XK_Insert:
XEvent ev;
fd_set rfd;
int xfd = XConnectionNumber(xw.dis);
+ long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
- running = 1;
- XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
+ XSelectInput(xw.dis, xw.win, mask);
XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
- while(running) {
+ while(1) {
FD_ZERO(&rfd);
FD_SET(cmdfd, &rfd);
FD_SET(xfd, &rfd);
- if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) == -1) {
+ if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
if(errno == EINTR)
continue;
die("select failed: %s\n", SERRNO);
int
main(int argc, char *argv[]) {
if(argc == 2 && !strncmp("-v", argv[1], 3))
- die("st-" VERSION ", © 2009 st engineers\n");
+ die("st-" VERSION ", (c) 2010 st engineers\n");
else if(argc != 1)
die("usage: st [-v]\n");
setlocale(LC_CTYPE, "");