#define XK_NO_MOD 0
#define XK_SWITCH_MOD (1<<13)
-#define REDRAW_TIMEOUT (80*1000) /* 80 ms */
-
/* macros */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a))
} TCursor;
/* CSI Escape sequence structs */
-/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
+/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */
int len; /* raw string length */
char priv;
int arg[ESC_ARG_SIZ];
int narg; /* nb of args */
- char mode;
+ char mode[2];
} CSIEscape;
/* STR Escape sequence structs */
int ch; /* char height */
int cw; /* char width */
char state; /* focus, redraw, visible */
+ int cursor; /* cursor style */
} XWindow;
typedef struct {
int x, y;
} nb, ne, ob, oe;
- char *clip;
+ char *primary, *clipboard;
Atom xtarget;
bool alt;
struct timespec tclick1;
} Shortcut;
/* function definitions used in config.h */
+static void clipcopy(const Arg *);
static void clippaste(const Arg *);
static void numlock(const Arg *);
static void selpaste(const Arg *);
static void die(const char *, ...);
static void draw(void);
-static void redraw(int);
+static void redraw(void);
static void drawregion(int, int, int, int);
static void execsh(void);
static void sigchld(int);
[MotionNotify] = bmotion,
[ButtonPress] = bpress,
[ButtonRelease] = brelease,
- [SelectionClear] = selclear,
+/*
+ * Uncomment if you want the selection to disappear when you select something
+ * different in another window.
+ */
+/* [SelectionClear] = selclear, */
[SelectionNotify] = selnotify,
[SelectionRequest] = selrequest,
};
typedef struct {
XftFont *font;
int flags;
+ long unicodep;
} Fontcache;
/* Fontcache is an array now. A new font will be appended to the array. */
memset(&sel.tclick2, 0, sizeof(sel.tclick2));
sel.mode = 0;
sel.ob.x = -1;
- sel.clip = NULL;
+ sel.primary = NULL;
+ sel.clipboard = NULL;
sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
if(sel.xtarget == None)
sel.xtarget = XA_STRING;
int format;
uchar *data, *last, *repl;
Atom type;
+ XSelectionEvent *xsev;
ofs = 0;
+ xsev = (XSelectionEvent *)e;
+ if (xsev->property == None)
+ return;
do {
- if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
- False, AnyPropertyType, &type, &format,
- &nitems, &rem, &data)) {
+ if(XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
+ BUFSIZ/4, False, AnyPropertyType,
+ &type, &format, &nitems, &rem,
+ &data)) {
fprintf(stderr, "Clipboard allocation failed\n");
return;
}
xw.win, CurrentTime);
}
+void
+clipcopy(const Arg *dummy) {
+ Atom clipboard;
+
+ if(sel.clipboard != NULL)
+ free(sel.clipboard);
+
+ if(sel.primary != NULL) {
+ sel.clipboard = xstrdup(sel.primary);
+ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+ XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+ }
+}
+
void
clippaste(const Arg *dummy) {
Atom clipboard;
clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY,
+ XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard,
xw.win, CurrentTime);
}
selrequest(XEvent *e) {
XSelectionRequestEvent *xsre;
XSelectionEvent xev;
- Atom xa_targets, string;
+ Atom xa_targets, string, clipboard;
+ char *seltext;
xsre = (XSelectionRequestEvent *) e;
xev.type = SelectionNotify;
XA_ATOM, 32, PropModeReplace,
(uchar *) &string, 1);
xev.property = xsre->property;
- } else if(xsre->target == sel.xtarget && sel.clip != NULL) {
- XChangeProperty(xsre->display, xsre->requestor, xsre->property,
- xsre->target, 8, PropModeReplace,
- (uchar *) sel.clip, strlen(sel.clip));
- xev.property = xsre->property;
+ } else if(xsre->target == sel.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(xw.dpy, "CLIPBOARD", 0);
+ if(xsre->selection == XA_PRIMARY) {
+ seltext = sel.primary;
+ } else if(xsre->selection == clipboard) {
+ seltext = sel.clipboard;
+ } else {
+ fprintf(stderr,
+ "Unhandled clipboard selection 0x%lx\n",
+ xsre->selection);
+ return;
+ }
+ if(seltext != NULL) {
+ XChangeProperty(xsre->display, xsre->requestor,
+ xsre->property, xsre->target,
+ 8, PropModeReplace,
+ (uchar *)seltext, strlen(seltext));
+ xev.property = xsre->property;
+ }
}
/* all done, send a notification to the listener */
void
xsetsel(char *str) {
- /* register the selection for both the clipboard and the primary */
- Atom clipboard;
-
- free(sel.clip);
- sel.clip = str;
+ free(sel.primary);
+ sel.primary = str;
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
-
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
}
void
break;
p++;
}
- csiescseq.mode = *p;
+ csiescseq.mode[0] = *p++;
+ csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0';
}
/* for absolute user moves, when decom is set */
mode = term.mode;
MODBIT(term.mode, set, MODE_REVERSE);
if(mode != term.mode)
- redraw(REDRAW_TIMEOUT);
+ redraw();
break;
case 6: /* DECOM -- Origin */
MODBIT(term.c.state, set, CURSOR_ORIGIN);
char buf[40];
int len;
- switch(csiescseq.mode) {
+ switch(csiescseq.mode[0]) {
default:
unknown:
fprintf(stderr, "erresc: unknown csi ");
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
tcursor(CURSOR_LOAD);
break;
+ case ' ':
+ switch (csiescseq.mode[1]) {
+ case 'q': /* DECSCUSR -- Set Cursor Style */
+ DEFAULT(csiescseq.arg[0], 1);
+ if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
+ goto unknown;
+ }
+ xw.cursor = csiescseq.arg[0];
+ break;
+ default:
+ goto unknown;
+ }
+ break;
}
}
* TODO if defaultbg color is changed, borders
* are dirty
*/
- redraw(0);
+ redraw();
}
return;
}
void
strparse(void) {
+ int c;
char *p = strescseq.buf;
strescseq.narg = 0;
strescseq.buf[strescseq.len] = '\0';
- while(p && strescseq.narg < STR_ARG_SIZ)
- strescseq.args[strescseq.narg++] = strsep(&p, ";");
+
+ if(*p == '\0')
+ return;
+
+ while(strescseq.narg < STR_ARG_SIZ) {
+ strescseq.args[strescseq.narg++] = p;
+ while((c = *p) != ';' && c != '\0')
+ ++p;
+ if(c == '\0')
+ return;
+ *p++ = '\0';
+ }
}
void
c = "\357\277\275"; /* UTF_INVALID */
width = 1;
}
- control = ISCONTROLC1(unicodep);
ascii = unicodep;
}
* character.
*/
if(term.esc & ESC_STR) {
- if(width == 1 &&
+ if(len == 1 &&
(ascii == '\a' || ascii == 030 ||
ascii == 032 || ascii == 033 ||
ISCONTROLC1(unicodep))) {
gp = &term.line[term.c.y][term.c.x];
}
- if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
- memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
+ if(IS_SET(MODE_INSERT) && term.c.x+width < term.col)
+ memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
if(term.c.x+width > term.col) {
tnewline(1);
if(!pattern)
die("st: can't open font %s\n", fontstr);
- if(fontsize > 0) {
+ if(fontsize > 1) {
FcPatternDel(pattern, FC_PIXEL_SIZE);
FcPatternDel(pattern, FC_SIZE);
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
xunloadfonts();
xloadfonts(usedfont, arg->i);
cresize(0, 0);
- redraw(0);
+ redraw();
xhints();
}
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 frcflags;
+ int frcflags, charexists;
int u8fl, u8fblen, u8cblen, doesexist;
char *u8c, *u8fs;
long unicodep;
/* Search the font cache. */
for(i = 0; i < frclen; i++) {
- if(XftCharExists(xw.dpy, frc[i].font, unicodep)
- && frc[i].flags == frcflags) {
+ charexists = XftCharExists(xw.dpy, frc[i].font, unicodep);
+ /* Everything correct. */
+ if(charexists && frc[i].flags == frcflags)
+ break;
+ /* We got a default font for a not found glyph. */
+ if(!charexists && frc[i].flags == frcflags \
+ && frc[i].unicodep == unicodep) {
break;
}
}
FcMatchPattern);
FcDefaultSubstitute(fcpattern);
- fontpattern = FcFontSetMatch(0, fcsets,
- FcTrue, fcpattern, &fcres);
+ fontpattern = FcFontSetMatch(0, fcsets, 1,
+ fcpattern, &fcres);
/*
* Overwrite or create the new cache entry.
if(frclen >= LEN(frc)) {
frclen = LEN(frc) - 1;
XftFontClose(xw.dpy, frc[frclen].font);
+ frc[frclen].unicodep = 0;
}
frc[frclen].font = XftFontOpenPattern(xw.dpy,
fontpattern);
frc[frclen].flags = frcflags;
+ frc[frclen].unicodep = unicodep;
i = frclen;
frclen++;
/* draw the new one */
if(xw.state & WIN_FOCUSED) {
- if(IS_SET(MODE_REVERSE)) {
- g.mode |= ATTR_REVERSE;
- g.fg = defaultcs;
- g.bg = defaultfg;
- }
+ switch (xw.cursor) {
+ case 0: /* Blinking Block */
+ case 1: /* Blinking Block (Default) */
+ case 2: /* Steady Block */
+ if(IS_SET(MODE_REVERSE)) {
+ g.mode |= ATTR_REVERSE;
+ g.fg = defaultcs;
+ g.bg = defaultfg;
+ }
- sl = utf8len(g.c);
- width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
- ? 2 : 1;
- xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+ sl = utf8len(g.c);
+ width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
+ ? 2 : 1;
+ xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+ break;
+ case 3: /* Blinking Underline */
+ case 4: /* Steady Underline */
+ XftDrawRect(xw.draw, &dc.col[defaultcs],
+ borderpx + curx * xw.cw,
+ borderpx + (term.c.y + 1) * xw.ch - 1,
+ xw.cw, 1);
+ break;
+ case 5: /* Blinking bar */
+ case 6: /* Steady bar */
+ XftDrawRect(xw.draw, &dc.col[defaultcs],
+ borderpx + curx * xw.cw,
+ borderpx + term.c.y * xw.ch,
+ 1, xw.ch);
+ break;
+ }
} else {
XftDrawRect(xw.draw, &dc.col[defaultcs],
borderpx + curx * xw.cw,
}
void
-redraw(int timeout) {
- struct timespec tv = {0, timeout * 1000};
-
+redraw(void) {
tfulldirt();
draw();
-
- if(timeout > 0) {
- nanosleep(&tv, NULL);
- XSync(xw.dpy, False); /* necessary for a good tput flash */
- }
}
void
if(!e->count)
xw.state &= ~WIN_REDRAW;
}
- redraw(0);
+ redraw();
}
void
void
usage(void) {
- die("%s " VERSION " (c) 2010-2014 st engineers\n" \
+ die("%s " VERSION " (c) 2010-2015 st engineers\n" \
"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
" [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
}
xw.l = xw.t = 0;
xw.isfixed = False;
+ xw.cursor = 0;
ARGBEGIN {
case 'a':