Archived
0
0
Fork 0

st changes

This commit is contained in:
Daryl Ronningen 2022-07-30 15:21:29 -07:00
parent bf11e094f0
commit 1771a985bb
Signed by: Daryl Ronningen
GPG key ID: FD23F0C934A5EC6B
38 changed files with 305 additions and 1174 deletions

View file

@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`.
## I would like to have utmp and/or scroll functionality by default ## I would like to have utmp and/or scroll functionality by default
You can add the absolute patch of both programs in your config.h You can add the absolute path of both programs in your config.h file. You only
file. You only have to modify the value of utmp and scroll variables. have to modify the value of utmp and scroll variables.
## Why doesn't the Del key work in some programs? ## Why doesn't the Del key work in some programs?

View file

@ -1,6 +1,6 @@
MIT/X Consortium License MIT/X Consortium License
© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org> © 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com> © 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space> © 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>

View file

@ -7,6 +7,7 @@
*/ */
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
/* borderperc: percentage of cell width to use as a border /* borderperc: percentage of cell width to use as a border
* 0 = no border, 100 = border width is same as cell width */ * 0 = no border, 100 = border width is same as cell width */
int borderperc = 20; int borderperc = 20;
@ -28,7 +29,7 @@ char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */ /* identification sequence returned in DA and DECID */
char *vtiden = "\033[?12;4c"; char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */ /* Kerning / character bounding-box multipliers */
static float cwscale = 1.0; static float cwscale = 1.0;
@ -61,11 +62,6 @@ int allowwindowops = 0;
static double minlatency = 8; static double minlatency = 8;
static double maxlatency = 33; static double maxlatency = 33;
/*
* Synchronized-Update timeout in ms
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
*/
static uint su_timeout = 200;
/* /*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking * blinking timeout (set to 0 to disable blinking) for the terminal blinking
@ -244,10 +240,10 @@ static uint forcemousemod = ShiftMask;
* Beware that overloading Button1 will disable the selection. * Beware that overloading Button1 will disable the selection.
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* mask button function argument release alt */ /* mask button function argument release */
{ XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 },
{ ShiftMask, Button4, kscrollup, {.i = 1} }, { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ ShiftMask, Button5, kscrolldown, {.i = 1} }, { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ XK_NO_MOD, Button4, kscrollup, {.i = 1} }, { XK_NO_MOD, Button4, kscrollup, {.i = 1} },
{ XK_NO_MOD, Button5, kscrolldown, {.i = 1} }, { XK_NO_MOD, Button5, kscrolldown, {.i = 1} },
}; };
@ -283,8 +279,6 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, clippaste, {.i = 0} }, { TERMMOD, XK_Y, clippaste, {.i = 0} },
{ ShiftMask, XK_Insert, clippaste, {.i = 0} }, { ShiftMask, XK_Insert, clippaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ TERMMOD, XK_U, externalpipe, { .v = openurlcmd } },
{ TERMMOD, XK_X, invert, { 0 } },
}; };
/* /*

View file

@ -7,9 +7,10 @@
*/ */
static char *font = "FiraCode Nerd Font Mono:pixelsize=12:antialias=true:autohint=true"; static char *font = "FiraCode Nerd Font Mono:pixelsize=12:antialias=true:autohint=true";
/* borderperc: percentage of cell width to use as a border /* borderperc: percentage of cell width to use as a border
* 0 = no border, 100 = border width is same as cell width */ * 0 = no border, 100 = border width is same as cell width */
int borderperc = 20; int borderperc = 100;
static char *url_opener = "xdg-open"; static char *url_opener = "xdg-open";
@ -28,7 +29,7 @@ char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */ /* identification sequence returned in DA and DECID */
char *vtiden = "\033[?12;4c"; char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */ /* Kerning / character bounding-box multipliers */
static float cwscale = 1.0; static float cwscale = 1.0;
@ -61,11 +62,6 @@ int allowwindowops = 0;
static double minlatency = 8; static double minlatency = 8;
static double maxlatency = 33; static double maxlatency = 33;
/*
* Synchronized-Update timeout in ms
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
*/
static uint su_timeout = 200;
/* /*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking * blinking timeout (set to 0 to disable blinking) for the terminal blinking
@ -84,8 +80,8 @@ static unsigned int cursorthickness = 2;
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
* 0: disable (render all U25XX glyphs normally from the font). * 0: disable (render all U25XX glyphs normally from the font).
*/ */
const int boxdraw = 0; const int boxdraw = 1;
const int boxdraw_bold = 0; const int boxdraw_bold = 1;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 0; const int boxdraw_braille = 0;
@ -117,7 +113,7 @@ char *termname = "st-256color";
unsigned int tabspaces = 2; unsigned int tabspaces = 2;
/* bg opacity */ /* bg opacity */
float alpha = 0.7; float alpha = 0.3;
/* Terminal colors (16 first used in escape sequence) */ /* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = { static const char *colorname[] = {
@ -244,8 +240,10 @@ static uint forcemousemod = ShiftMask;
* Beware that overloading Button1 will disable the selection. * Beware that overloading Button1 will disable the selection.
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* mask button function argument release alt */ /* mask button function argument release */
{ XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ ShiftMask, Button4, kscrollup, {.i = 1} }, { ShiftMask, Button4, kscrollup, {.i = 1} },
{ ShiftMask, Button5, kscrolldown, {.i = 1} }, { ShiftMask, Button5, kscrolldown, {.i = 1} },
{ XK_NO_MOD, Button4, kscrollup, {.i = 1} }, { XK_NO_MOD, Button4, kscrollup, {.i = 1} },
@ -283,8 +281,6 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, clippaste, {.i = 0} }, { TERMMOD, XK_Y, clippaste, {.i = 0} },
{ ShiftMask, XK_Insert, clippaste, {.i = 0} }, { ShiftMask, XK_Insert, clippaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ TERMMOD, XK_U, externalpipe, { .v = openurlcmd } },
{ TERMMOD, XK_X, invert, { 0 } },
}; };
/* /*

View file

@ -1,5 +1,5 @@
# st version # st version
VERSION = 0.8.4 VERSION = 0.8.5
# Customize below to fit your system # Customize below to fit your system
@ -25,7 +25,7 @@ LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz` LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
# Uncomment this for the SIXEL patch / SIXEL_PATCH # Uncomment this for the SIXEL patch / SIXEL_PATCH
SIXEL_C = sixel.c sixel_hls.c #SIXEL_C = sixel.c sixel_hls.c
# includes and libs, uncomment harfbuzz for the ligatures patch # includes and libs, uncomment harfbuzz for the ligatures patch
INCS = -I$(X11INC) \ INCS = -I$(X11INC) \
@ -47,6 +47,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `pkg-config --libs fontconfig` \ # `pkg-config --libs fontconfig` \
# `pkg-config --libs freetype2` # `pkg-config --libs freetype2`
#MANPREFIX = ${PREFIX}/man
# compiler and linker # compiler and linker
# CC = c99 # CC = c99

View file

@ -1,12 +1,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <X11/Xft/Xft.h>
#include <time.h> #include <time.h>
#include <X11/Xft/Xft.h>
#include <X11/cursorfont.h>
#include <hb.h> #include <hb.h>
#include <hb-ft.h> #include <hb-ft.h>
#include "st.h" #include "st.h"
#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length); void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
hb_font_t *hbfindfont(XftFont *match); hb_font_t *hbfindfont(XftFont *match);
@ -18,6 +22,13 @@ typedef struct {
static int hbfontslen = 0; static int hbfontslen = 0;
static HbFontMatch *hbfontcache = NULL; static HbFontMatch *hbfontcache = NULL;
/*
* Poplulate the array with a list of font features, wrapped in FEATURE macro,
* e. g.
* FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
*/
hb_feature_t features[] = { };
void void
hbunloadfonts() hbunloadfonts()
{ {
@ -59,7 +70,7 @@ void
hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y) hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
{ {
int start = 0, length = 1, gstart = 0; int start = 0, length = 1, gstart = 0;
hb_codepoint_t *codepoints = calloc(len, sizeof(hb_codepoint_t)); hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(hb_codepoint_t));
for (int idx = 1, specidx = 1; idx < len; idx++) { for (int idx = 1, specidx = 1; idx < len; idx++) {
if (glyphs[idx].mode & ATTR_WDUMMY) { if (glyphs[idx].mode & ATTR_WDUMMY) {
@ -125,7 +136,7 @@ hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoin
} }
/* Shape the segment. */ /* Shape the segment. */
hb_shape(font, buffer, NULL, 0); hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
/* Get new glyph info. */ /* Get new glyph info. */
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL); hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);

View file

@ -1,118 +0,0 @@
void
tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg )
{
int i = start;
for( ; i < end; ++i )
{
term.line[row][i].fg = fg;
term.line[row][i].bg = bg;
}
}
char *
findlastany(char *str, const char** find, size_t len)
{
char* found = NULL;
int i = 0;
for(found = str + strlen(str) - 1; found >= str; --found) {
for(i = 0; i < len; i++) {
if(strncmp(found, find[i], strlen(find[i])) == 0) {
return found;
}
}
}
return NULL;
}
/*
** Select and copy the previous url on screen (do nothing if there's no url).
**
** FIXME: doesn't handle urls that span multiple lines; will need to add support
** for multiline "getsel()" first
*/
void
copyurl(const Arg *arg) {
/* () and [] can appear in urls, but excluding them here will reduce false
* positives when figuring out where a given url ends.
*/
static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-._~:/?#@!$&'*+,;=%";
static const char* URLSTRINGS[] = {"http://", "https://"};
/* remove highlighting from previous selection if any */
if(sel.ob.x >= 0 && sel.oe.x >= 0)
tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg);
int i = 0,
row = 0, /* row of current URL */
col = 0, /* column of current URL start */
startrow = 0, /* row of last occurrence */
colend = 0, /* column of last occurrence */
passes = 0; /* how many rows have been scanned */
char *linestr = calloc(term.col+1, sizeof(Rune));
char *c = NULL,
*match = NULL;
row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
LIMIT(row, term.top, term.bot);
startrow = row;
colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
LIMIT(colend, 0, term.col);
/*
** Scan from (term.bot,term.col) to (0,0) and find
** next occurrance of a URL
*/
while (passes !=term.bot + 2) {
/* Read in each column of every row until
** we hit previous occurrence of URL
*/
for (col = 0, i = 0; col < colend; ++col,++i) {
linestr[i] = term.line[row][col].u;
}
linestr[term.col] = '\0';
if ((match = findlastany(linestr, URLSTRINGS,
sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
break;
if (--row < term.top)
row = term.bot;
colend = term.col;
passes++;
};
if (match) {
/* must happen before trim */
selclear();
sel.ob.x = strlen(linestr) - strlen(match);
/* trim the rest of the line from the url match */
for (c = match; *c != '\0'; ++c)
if (!strchr(URLCHARS, *c)) {
*c = '\0';
break;
}
/* highlight selection by inverting terminal colors */
tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg);
/* select and copy */
sel.mode = 1;
sel.type = SEL_REGULAR;
sel.oe.x = sel.ob.x + strlen(match)-1;
sel.ob.y = sel.oe.y = row;
selnormalize();
tsetdirt(sel.nb.y, sel.ne.y);
xsetsel(getsel());
xclipcopy();
}
free(linestr);
}

View file

@ -1,3 +0,0 @@
void copyurl(const Arg *);
static void tsetcolor(int, int, int, uint32_t, uint32_t);
static char * findlastany(char *, const char**, size_t);

View file

@ -1,68 +0,0 @@
int extpipeactive = 0;
void
extpipe(const Arg *arg, int in)
{
int to[2];
char buf[UTF_SIZ];
void (*oldsigpipe)(int);
Glyph *bp, *end;
int lastpos, n, newline;
if (pipe(to) == -1)
return;
switch (fork()) {
case -1:
close(to[0]);
close(to[1]);
return;
case 0:
dup2(to[0], STDIN_FILENO);
close(to[0]);
close(to[1]);
if (in)
dup2(csdfd, STDOUT_FILENO);
close(csdfd);
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
perror("failed");
exit(0);
}
close(to[0]);
/* ignore sigpipe for now, in case child exists early */
oldsigpipe = signal(SIGPIPE, SIG_IGN);
newline = 0;
for (n = 0; n < term.row; n++) {
bp = term.line[n];
lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
if (lastpos < 0)
break;
end = &bp[lastpos + 1];
for (; bp < end; ++bp)
if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
break;
if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
continue;
if (xwrite(to[1], "\n", 1) < 0)
break;
newline = 0;
}
if (newline)
(void)xwrite(to[1], "\n", 1);
close(to[1]);
/* restore */
signal(SIGPIPE, oldsigpipe);
extpipeactive = 1;
}
void
externalpipe(const Arg *arg) {
extpipe(arg, 0);
}
void
externalpipein(const Arg *arg) {
extpipe(arg, 1);
}

View file

@ -1,2 +0,0 @@
void externalpipe(const Arg *);
void externalpipein(const Arg *);

View file

@ -1,94 +0,0 @@
int
xloadsparefont(FcPattern *pattern, int flags)
{
FcPattern *match;
FcResult result;
match = FcFontMatch(NULL, pattern, &result);
if (!match) {
return 1;
}
if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) {
FcPatternDestroy(match);
return 1;
}
frc[frclen].flags = flags;
/* Believe U+0000 glyph will present in each default font */
frc[frclen].unicodep = 0;
frclen++;
return 0;
}
void
xloadsparefonts(void)
{
FcPattern *pattern;
double sizeshift, fontval;
int fc;
char **fp;
if (frclen != 0)
die("can't embed spare fonts. cache isn't empty");
/* Calculate count of spare fonts */
fc = sizeof(font2) / sizeof(*font2);
if (fc == 0)
return;
/* Allocate memory for cache entries. */
if (frccap < 4 * fc) {
frccap += 4 * fc - frccap;
frc = xrealloc(frc, frccap * sizeof(Fontcache));
}
for (fp = font2; fp - font2 < fc; ++fp) {
if (**fp == '-')
pattern = XftXlfdParse(*fp, False, False);
else
pattern = FcNameParse((FcChar8 *)*fp);
if (!pattern)
die("can't open spare font %s\n", *fp);
if (defaultfontsize > 0) {
sizeshift = usedfontsize - defaultfontsize;
if (sizeshift != 0 &&
FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
FcResultMatch) {
fontval += sizeshift;
FcPatternDel(pattern, FC_PIXEL_SIZE);
FcPatternDel(pattern, FC_SIZE);
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
}
}
FcPatternAddBool(pattern, FC_SCALABLE, 1);
FcConfigSubstitute(NULL, pattern, FcMatchPattern);
XftDefaultSubstitute(xw.dpy, xw.scr, pattern);
if (xloadsparefont(pattern, FRC_NORMAL))
die("can't open spare font %s\n", *fp);
FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
if (xloadsparefont(pattern, FRC_ITALIC))
die("can't open spare font %s\n", *fp);
FcPatternDel(pattern, FC_WEIGHT);
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
if (xloadsparefont(pattern, FRC_ITALICBOLD))
die("can't open spare font %s\n", *fp);
FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
if (xloadsparefont(pattern, FRC_BOLD))
die("can't open spare font %s\n", *fp);
FcPatternDestroy(pattern);
}
}

View file

@ -1,2 +0,0 @@
static int xloadsparefont(FcPattern *, int);
static void xloadsparefonts(void);

View file

@ -1,21 +0,0 @@
static int invertcolors = 0;
void
invert(const Arg *dummy)
{
invertcolors = !invertcolors;
redraw();
}
Color
invertedcolor(Color *clr)
{
XRenderColor rc;
Color inverted;
rc.red = ~clr->color.red;
rc.green = ~clr->color.green;
rc.blue = ~clr->color.blue;
rc.alpha = clr->color.alpha;
XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &rc, &inverted);
return inverted;
}

View file

@ -1 +0,0 @@
static void invert(const Arg *);

View file

@ -1,217 +0,0 @@
void set_notifmode(int type, KeySym ksym)
{
static char *lib[] = { " MOVE ", " SEL "};
static Glyph *g, *deb, *fin;
static int col, bot;
if (ksym == -1) {
free(g);
col = term.col, bot = term.bot;
g = xmalloc(col * sizeof(Glyph));
memcpy(g, term.line[bot], col * sizeof(Glyph));
} else if (ksym == -2)
memcpy(term.line[bot], g, col * sizeof(Glyph));
if ( type < 2 ) {
char *z = lib[type];
for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
deb->mode = ATTR_REVERSE,
deb->u = *z,
deb->fg = defaultfg, deb->bg = defaultbg;
} else if (type < 5)
memcpy(term.line[bot], g, col * sizeof(Glyph));
else {
for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
deb->mode = ATTR_REVERSE,
deb->u = ' ',
deb->fg = defaultfg, deb->bg = defaultbg;
term.line[bot][0].u = ksym;
}
term.dirty[bot] = 1;
drawregion(0, bot, col, bot + 1);
}
void select_or_drawcursor(int selectsearch_mode, int type)
{
int done = 0;
if (selectsearch_mode & 1) {
selextend(term.c.x, term.c.y, type, done);
xsetsel(getsel());
} else {
xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
term.ocx, term.ocy, term.line[term.ocy][term.ocx],
term.line[term.ocy], term.col);
}
}
void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu)
{
Rune *r;
int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
for (r = target; r - target < ptarget; r++) {
if (*r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u) {
if (r - target == ptarget - 1)
break;
} else {
r = NULL;
break;
}
}
if (r != NULL)
break;
}
if (i != bound) {
term.c.y = i / term.col, term.c.x = i % term.col;
select_or_drawcursor(selectsearch_mode, type);
}
}
int trt_kbdselect(KeySym ksym, char *buf, int len)
{
static TCursor cu;
static Rune target[64];
static int type = 1, ptarget, in_use;
static int sens, quant;
static char selectsearch_mode;
int i, bound, *xy;
if (selectsearch_mode & 2) {
if (ksym == XK_Return) {
selectsearch_mode ^= 2;
set_notifmode(selectsearch_mode, -2);
if (ksym == XK_Escape)
ptarget = 0;
return 0;
} else if (ksym == XK_BackSpace) {
if (!ptarget)
return 0;
term.line[term.bot][ptarget--].u = ' ';
} else if (len < 1) {
return 0;
} else if (ptarget == term.col || ksym == XK_Escape) {
return 0;
} else {
utf8decode(buf, &target[ptarget++], len);
term.line[term.bot][ptarget].u = target[ptarget - 1];
}
if (ksym != XK_BackSpace)
search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
term.dirty[term.bot] = 1;
drawregion(0, term.bot, term.col, term.bot + 1);
return 0;
}
switch (ksym) {
case -1:
in_use = 1;
cu.x = term.c.x, cu.y = term.c.y;
set_notifmode(0, ksym);
return MODE_KBDSELECT;
case XK_s:
if (selectsearch_mode & 1)
selclear();
else
selstart(term.c.x, term.c.y, 0);
set_notifmode(selectsearch_mode ^= 1, ksym);
break;
case XK_t:
selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */
selextend(term.c.x, term.c.y, type, i = 0);
break;
case XK_slash:
case XK_KP_Divide:
case XK_question:
ksym &= XK_question; /* Divide to slash */
sens = (ksym == XK_slash) ? -1 : 1;
ptarget = 0;
set_notifmode(15, ksym);
selectsearch_mode ^= 2;
break;
case XK_Escape:
if (!in_use)
break;
selclear();
case XK_Return:
set_notifmode(4, ksym);
term.c.x = cu.x, term.c.y = cu.y;
select_or_drawcursor(selectsearch_mode = 0, type);
in_use = quant = 0;
return MODE_KBDSELECT;
case XK_n:
case XK_N:
if (ptarget)
search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
break;
case XK_BackSpace:
term.c.x = 0;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_dollar:
term.c.x = term.col - 1;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_Home:
term.c.x = 0, term.c.y = 0;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_End:
term.c.x = cu.x, term.c.y = cu.y;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_Page_Up:
case XK_Page_Down:
term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_exclam:
term.c.x = term.col >> 1;
select_or_drawcursor(selectsearch_mode, type);
break;
case XK_asterisk:
case XK_KP_Multiply:
term.c.x = term.col >> 1;
case XK_underscore:
term.c.y = cu.y >> 1;
select_or_drawcursor(selectsearch_mode, type);
break;
default:
if (ksym >= XK_0 && ksym <= XK_9) { /* 0-9 keyboard */
quant = (quant * 10) + (ksym ^ XK_0);
return 0;
} else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) { /* 0-9 numpad */
quant = (quant * 10) + (ksym ^ XK_KP_0);
return 0;
} else if (ksym == XK_k || ksym == XK_h)
i = ksym & 1;
else if (ksym == XK_l || ksym == XK_j)
i = ((ksym & 6) | 4) >> 1;
else if ((XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3)
break;
xy = (i & 1) ? &term.c.y : &term.c.x;
sens = (i & 2) ? 1 : -1;
bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
if (quant == 0)
quant++;
if (*xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)))
break;
*xy += quant * sens;
if (*xy < 0 || ( bound > 0 && *xy > bound))
*xy = bound;
select_or_drawcursor(selectsearch_mode, type);
}
quant = 0;
return 0;
}

View file

@ -1,2 +0,0 @@
void toggle_winmode(int);
int trt_kbdselect(KeySym, char *, int);

View file

@ -1,7 +0,0 @@
void toggle_winmode(int flag) {
win.mode ^= flag;
}
void keyboard_select(const Arg *dummy) {
win.mode ^= trt_kbdselect(-1, NULL, 0);
}

View file

@ -1,2 +0,0 @@
void toggle_winmode(int);
void keyboard_select(const Arg *);

View file

@ -1,30 +0,0 @@
void
newterm(const Arg* a)
{
int res;
switch (fork()) {
case -1:
die("fork failed: %s\n", strerror(errno));
break;
case 0:
switch (fork()) {
case -1:
die("fork failed: %s\n", strerror(errno));
break;
case 0:
res = chdir(getcwd_by_pid(pid));
execlp("st", "./st", NULL);
break;
default:
exit(0);
}
default:
wait(NULL);
}
}
static char *getcwd_by_pid(pid_t pid) {
char buf[32];
snprintf(buf, sizeof buf, "/proc/%d/cwd", pid);
return realpath(buf, NULL);
}

View file

@ -1,2 +0,0 @@
void newterm(const Arg *);
static char *getcwd_by_pid(pid_t pid);

View file

@ -1,19 +0,0 @@
void
opencopied(const Arg *arg)
{
int res;
size_t const max_cmd = 2048;
char * const clip = xsel.clipboard;
if (!clip) {
fprintf(stderr, "Warning: nothing copied to clipboard\n");
return;
}
/* account for space/quote (3) and \0 (1) and & (1) */
/* e.g.: xdg-open "https://st.suckless.org"& */
size_t const cmd_size = max_cmd + strlen(clip) + 5;
char cmd[cmd_size];
snprintf(cmd, cmd_size, "%s \"%s\"&", (char *)arg->v, clip);
res = system(cmd);
}

View file

@ -1 +0,0 @@
void opencopied(const Arg *);

View file

@ -15,7 +15,6 @@ kscrolldown(const Arg* a)
tfulldirt(); tfulldirt();
} }
scroll_images(-1*n);
} }
void void
@ -25,8 +24,8 @@ kscrollup(const Arg* a)
if (n < 0) if (n < 0)
n = term.row + n; n = term.row + n;
if (term.scr + n > term.histi) if (term.scr + n > term.histn)
n = term.histi - term.scr; n = term.histn - term.scr;
if (!n) if (!n)
return; return;
@ -37,5 +36,4 @@ kscrollup(const Arg* a)
tfulldirt(); tfulldirt();
} }
scroll_images(n);
} }

View file

@ -1,42 +0,0 @@
sixel_state_t sixel_st;
void
dcshandle(void)
{
switch (csiescseq.mode[0]) {
default:
fprintf(stderr, "erresc: unknown csi ");
csidump();
/* die(""); */
break;
case 'q': /* DECSIXEL */
if (sixel_parser_init(&sixel_st, 0, 0 << 16 | 0 << 8 | 0, 1, win.cw, win.ch) != 0)
perror("sixel_parser_init() failed");
term.mode |= MODE_SIXEL;
break;
}
}
void
scroll_images(int n) {
ImageList *im;
int tmp;
/* maximum sixel distance in lines from current view before
* deallocation
* TODO: should be in config.h */
int max_sixel_distance = 10000;
for (im = term.images; im; im = im->next) {
im->y += n;
/* check if the current sixel has exceeded the maximum
* draw distance, and should therefore be deleted */
tmp = im->y;
if (tmp < 0) { tmp = tmp * -1; }
if (tmp > max_sixel_distance) {
fprintf(stderr, "im@0x%08x exceeded maximum distance\n");
im->should_delete = 1;
}
}
}

View file

@ -1,2 +0,0 @@
static void dcshandle(void);
static void scroll_images(int n);

View file

@ -1,14 +0,0 @@
void
delete_image(ImageList *im)
{
if (im->prev)
im->prev->next = im->next;
else
term.images = im->next;
if (im->next)
im->next->prev = im->prev;
if (im->pixmap)
XFreePixmap(xw.dpy, (Drawable)im->pixmap);
free(im->pixels);
free(im);
}

View file

@ -1,6 +1,3 @@
/* Patches */ /* Patches */
#include "externalpipe.c"
#include "scrollback.c" #include "scrollback.c"
#include "universcroll.c" #include "universcroll.c"
#include "sixel_st.c"
#include "sync.c"

View file

@ -1,9 +1,6 @@
/* Patches */ /* Patches */
#include "externalpipe.h"
#include "scrollback.h" #include "scrollback.h"
#include "universcroll.h" #include "universcroll.h"
#include "sixel_st.h"
#include "sync.h"
// #if VIM_BROWSE_PATCH // #if VIM_BROWSE_PATCH
// #include "normalMode.h" // #include "normalMode.h"
// #endif // #endif

View file

@ -1,31 +0,0 @@
#include <time.h>
struct timespec sutv;
static void
tsync_begin()
{
clock_gettime(CLOCK_MONOTONIC, &sutv);
su = 1;
}
static void
tsync_end()
{
su = 0;
}
int
tinsync(uint timeout)
{
struct timespec now;
if (su && !clock_gettime(CLOCK_MONOTONIC, &now)
&& TIMEDIFF(now, sutv) >= timeout)
su = 0;
return su;
}
int
ttyread_pending()
{
return twrite_aborted;
}

View file

@ -1,7 +0,0 @@
static int su = 0;
static int twrite_aborted = 0;
static void tsync_begin();
static void tsync_end();
int tinsync(uint timeout);
int ttyread_pending();

View file

@ -1,7 +1,5 @@
/* Patches */ /* Patches */
#include "boxdraw.c" #include "boxdraw.c"
#include "fixkeyboardinput.c" #include "fixkeyboardinput.c"
#include "invert.c"
#include "openurlonclick.c" #include "openurlonclick.c"
#include "sixel_x.c"
#include "xresources.c" #include "xresources.c"

View file

@ -1,6 +1,5 @@
/* Patches */ /* Patches */
#include "boxdraw.h" #include "boxdraw.h"
#include "invert.h"
#include "netwmicon.h" #include "netwmicon.h"
#include "openurlonclick.h" #include "openurlonclick.h"
#include "xresources.h" #include "xresources.h"

View file

@ -60,10 +60,7 @@ reload_config(int sig)
die("Can't open display\n"); die("Can't open display\n");
config_init(dpy); config_init(dpy);
if (sig != -1) { xloadcols();
/* Called due to a SIGUSR1 */ redraw();
xloadcols(); XCloseDisplay(dpy);
redraw();
}
signal(SIGUSR1, reload_config);
} }

View file

@ -1,58 +0,0 @@
#ifndef SIXEL_H
#define SIXEL_H
#define DECSIXEL_PARAMS_MAX 16
#define DECSIXEL_PALETTE_MAX 1024
#define DECSIXEL_PARAMVALUE_MAX 65535
#define DECSIXEL_WIDTH_MAX 4096
#define DECSIXEL_HEIGHT_MAX 4096
typedef unsigned short sixel_color_no_t;
typedef unsigned int sixel_color_t;
typedef struct sixel_image_buffer {
sixel_color_no_t *data;
int width;
int height;
sixel_color_t palette[DECSIXEL_PALETTE_MAX];
sixel_color_no_t ncolors;
int palette_modified;
int use_private_register;
} sixel_image_t;
typedef enum parse_state {
PS_ESC = 1, /* ESC */
PS_DECSIXEL = 2, /* DECSIXEL body part ", $, -, ? ... ~ */
PS_DECGRA = 3, /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
PS_DECGRI = 4, /* DECGRI Graphics Repeat Introducer ! Pn Ch */
PS_DECGCI = 5, /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
} parse_state_t;
typedef struct parser_context {
parse_state_t state;
int pos_x;
int pos_y;
int max_x;
int max_y;
int attributed_pan;
int attributed_pad;
int attributed_ph;
int attributed_pv;
int repeat_count;
int color_index;
int bgindex;
int grid_width;
int grid_height;
int param;
int nparams;
int params[DECSIXEL_PARAMS_MAX];
sixel_image_t image;
} sixel_state_t;
int sixel_parser_init(sixel_state_t *st, sixel_color_t fgcolor, sixel_color_t bgcolor, unsigned char use_private_register, int cell_width, int cell_height);
int sixel_parser_parse(sixel_state_t *st, unsigned char *p, size_t len);
int sixel_parser_set_default_color(sixel_state_t *st);
int sixel_parser_finalize(sixel_state_t *st, unsigned char *pixels);
void sixel_parser_deinit(sixel_state_t *st);
#endif

View file

@ -22,7 +22,6 @@
#include "sixel.h"
#if defined(__linux) #if defined(__linux)
#include <pty.h> #include <pty.h>
@ -56,7 +55,6 @@ enum term_mode {
MODE_ECHO = 1 << 4, MODE_ECHO = 1 << 4,
MODE_PRINT = 1 << 5, MODE_PRINT = 1 << 5,
MODE_UTF8 = 1 << 6, MODE_UTF8 = 1 << 6,
MODE_SIXEL = 1 << 7,
}; };
enum cursor_movement { enum cursor_movement {
@ -88,7 +86,6 @@ enum escape_state {
ESC_STR_END = 16, /* a final string was encountered */ ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */ ESC_TEST = 32, /* Enter in test mode */
ESC_UTF8 = 64, ESC_UTF8 = 64,
ESC_DCS =128,
}; };
typedef struct { typedef struct {
@ -142,6 +139,8 @@ static void csihandle(void);
static void readcolonargs(char **, int, int[][CAR_PER_ARG]); static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
static void csiparse(void); static void csiparse(void);
static void csireset(void); static void csireset(void);
static void osc4_color_response(int num);
static void osc_color_response(int index, int num);
static int eschandle(uchar); static int eschandle(uchar);
static void strdump(void); static void strdump(void);
static void strhandle(void); static void strhandle(void);
@ -166,7 +165,7 @@ static void tputtab(int);
static void tputc(Rune); static void tputc(Rune);
static void treset(void); static void treset(void);
static void tscrollup(int, int, int); static void tscrollup(int, int, int);
static void tscrolldown(int, int, int); static void tscrolldown(int, int);
static void tsetattr(const int *, int); static void tsetattr(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int); static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int); static void tsetdirt(int, int);
@ -200,9 +199,7 @@ static CSIEscape csiescseq;
static STREscape strescseq; static STREscape strescseq;
static int iofd = 1; static int iofd = 1;
static int cmdfd; static int cmdfd;
static int csdfd;
static pid_t pid; static pid_t pid;
sixel_state_t sixel_st;
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
@ -329,25 +326,10 @@ utf8validate(Rune *u, size_t i)
return i; return i;
} }
static const char base64_digits[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
char char
base64dec_getc(const char **src) base64dec_getc(const char **src)
{ {
while (**src && !isprint(**src)) while (**src && !isprint((unsigned char)**src))
(*src)++; (*src)++;
return **src ? *((*src)++) : '='; /* emulate padding if string ends */ return **src ? *((*src)++) : '='; /* emulate padding if string ends */
} }
@ -357,6 +339,13 @@ base64dec(const char *src)
{ {
size_t in_len = strlen(src); size_t in_len = strlen(src);
char *result, *dst; char *result, *dst;
static const char base64_digits[256] = {
[43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
if (in_len % 4) if (in_len % 4)
in_len += 4 - (in_len % 4); in_len += 4 - (in_len % 4);
@ -705,23 +694,12 @@ sigchld(int a)
int stat; int stat;
pid_t p; pid_t p;
if ((p = waitpid((extpipeactive ? -1 : pid), &stat, WNOHANG)) < 0) if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
if (pid != p) { if (pid != p)
if (!extpipeactive)
return;
if (p == 0 && wait(&stat) < 0)
die("wait: %s\n", strerror(errno));
/* reinstall sigchld handler */
signal(SIGCHLD, sigchld);
extpipeactive = 0;
return; return;
}
close(csdfd);
if (WIFEXITED(stat) && WEXITSTATUS(stat)) if (WIFEXITED(stat) && WEXITSTATUS(stat))
die("child exited with status %d\n", WEXITSTATUS(stat)); die("child exited with status %d\n", WEXITSTATUS(stat));
@ -758,7 +736,6 @@ int
ttynew(const char *line, char *cmd, const char *out, char **args) ttynew(const char *line, char *cmd, const char *out, char **args)
{ {
int m, s; int m, s;
struct sigaction sa;
if (out) { if (out) {
term.mode |= MODE_PRINT; term.mode |= MODE_PRINT;
@ -796,8 +773,6 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
dup2(s, 2); dup2(s, 2);
if (ioctl(s, TIOCSCTTY, NULL) < 0) if (ioctl(s, TIOCSCTTY, NULL) < 0)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
close(s);
close(m);
if (s > 2) if (s > 2)
close(s); close(s);
#ifdef __OpenBSD__ #ifdef __OpenBSD__
@ -813,11 +788,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
#endif #endif
close(s); close(s);
cmdfd = m; cmdfd = m;
csdfd = s; signal(SIGCHLD, sigchld);
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = sigchld;
sigaction(SIGCHLD, &sa, NULL);
break; break;
} }
return cmdfd; return cmdfd;
@ -831,7 +802,7 @@ ttyread(void)
int ret, written; int ret, written;
/* append read bytes to unprocessed bytes */ /* append read bytes to unprocessed bytes */
ret = twrite_aborted ? 1 : read(cmdfd, buf+buflen, LEN(buf)-buflen); ret = read(cmdfd, buf+buflen, LEN(buf)-buflen);
switch (ret) { switch (ret) {
case 0: case 0:
@ -839,7 +810,7 @@ ttyread(void)
case -1: case -1:
die("couldn't read from shell: %s\n", strerror(errno)); die("couldn't read from shell: %s\n", strerror(errno));
default: default:
buflen += twrite_aborted ? 0 : ret; buflen += ret;
written = twrite(buf, buflen, 0); written = twrite(buf, buflen, 0);
buflen -= written; buflen -= written;
/* keep any incomplete UTF-8 byte sequence for the next call */ /* keep any incomplete UTF-8 byte sequence for the next call */
@ -1002,7 +973,6 @@ tsetdirtattr(int attr)
void void
tfulldirt(void) tfulldirt(void)
{ {
tsync_end();
tsetdirt(0, term.row-1); tsetdirt(0, term.row-1);
} }
@ -1024,7 +994,6 @@ void
treset(void) treset(void)
{ {
uint i; uint i;
ImageList *im;
term.c = (TCursor){{ term.c = (TCursor){{
.mode = ATTR_NULL, .mode = ATTR_NULL,
@ -1044,11 +1013,9 @@ treset(void)
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
tmoveto(0, 0); tmoveto(0, 0);
tcursor(CURSOR_SAVE); tcursor(CURSOR_SAVE);
tclearregion(0, 0, term.col-1, term.row-1); tclearregion(0, 0, term.maxcol-1, term.row-1);
tswapscreen(); tswapscreen();
} }
for (im = term.images; im; im = im->next)
im->should_delete = 1;
} }
void void
@ -1063,33 +1030,23 @@ void
tswapscreen(void) tswapscreen(void)
{ {
Line *tmp = term.line; Line *tmp = term.line;
ImageList *im = term.images;
term.line = term.alt; term.line = term.alt;
term.alt = tmp; term.alt = tmp;
term.images = term.images_alt;
term.images_alt = im;
term.mode ^= MODE_ALTSCREEN; term.mode ^= MODE_ALTSCREEN;
tfulldirt(); tfulldirt();
} }
void void
tscrolldown(int orig, int n, int copyhist) tscrolldown(int orig, int n)
{ {
int i; int i;
Line temp; Line temp;
LIMIT(n, 0, term.bot-orig+1); LIMIT(n, 0, term.bot-orig+1);
if (copyhist) {
term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
temp = term.hist[term.histi];
term.hist[term.histi] = term.line[term.bot];
term.line[term.bot] = temp;
}
tsetdirt(orig, term.bot-n); tsetdirt(orig, term.bot-n);
tclearregion(0, term.bot-n+1, term.col-1, term.bot); tclearregion(0, term.bot-n+1, term.maxcol-1, term.bot);
for (i = term.bot; i >= orig+n; i--) { for (i = term.bot; i >= orig+n; i--) {
temp = term.line[i]; temp = term.line[i];
@ -1097,7 +1054,6 @@ tscrolldown(int orig, int n, int copyhist)
term.line[i-n] = temp; term.line[i-n] = temp;
} }
scroll_images(n);
if (term.scr == 0) if (term.scr == 0)
selscroll(orig, n); selscroll(orig, n);
@ -1111,17 +1067,20 @@ tscrollup(int orig, int n, int copyhist)
LIMIT(n, 0, term.bot-orig+1); LIMIT(n, 0, term.bot-orig+1);
if (copyhist) { if (copyhist && !IS_SET(MODE_ALTSCREEN)) {
term.histi = (term.histi + 1) % HISTSIZE; for (i = 0; i < n; i++) {
temp = term.hist[term.histi]; term.histi = (term.histi + 1) % HISTSIZE;
term.hist[term.histi] = term.line[orig]; temp = term.hist[term.histi];
term.line[orig] = temp; term.hist[term.histi] = term.line[orig+i];
term.line[orig+i] = temp;
}
term.histn = MIN(term.histn + n, HISTSIZE);
if (term.scr > 0 && term.scr < HISTSIZE)
term.scr = MIN(term.scr + n, HISTSIZE-1);
} }
if (term.scr > 0 && term.scr < HISTSIZE) tclearregion(0, orig, term.maxcol-1, orig+n-1);
term.scr = MIN(term.scr + n, HISTSIZE-1);
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot); tsetdirt(orig+n, term.bot);
for (i = orig; i <= term.bot-n; i++) { for (i = orig; i <= term.bot-n; i++) {
@ -1130,7 +1089,6 @@ tscrollup(int orig, int n, int copyhist)
term.line[i+n] = temp; term.line[i+n] = temp;
} }
scroll_images(-1 * n);
if (term.scr == 0) if (term.scr == 0)
selscroll(orig, -n); selscroll(orig, -n);
@ -1353,7 +1311,7 @@ void
tinsertblankline(int n) tinsertblankline(int n)
{ {
if (BETWEEN(term.c.y, term.top, term.bot)) if (BETWEEN(term.c.y, term.top, term.bot))
tscrolldown(term.c.y, n, 0); tscrolldown(term.c.y, n);
} }
void void
@ -1629,8 +1587,7 @@ tsetmode(int priv, int set, const int *args, int narg)
break; break;
alt = IS_SET(MODE_ALTSCREEN); alt = IS_SET(MODE_ALTSCREEN);
if (alt) { if (alt) {
tclearregion(0, 0, term.col-1, tclearregion(0, 0, term.maxcol-1, term.row-1);
term.row-1);
} }
if (set ^ alt) /* set is always 1 or 0 */ if (set ^ alt) /* set is always 1 or 0 */
tswapscreen(); tswapscreen();
@ -1688,9 +1645,9 @@ tsetmode(int priv, int set, const int *args, int narg)
void void
csihandle(void) csihandle(void)
{ {
char buf[40]; char buffer[40];
int len; int len;
ImageList *im; int maxcol = term.maxcol;
switch (csiescseq.mode[0]) { switch (csiescseq.mode[0]) {
default: default:
@ -1788,30 +1745,49 @@ csihandle(void)
case 'J': /* ED -- Clear screen */ case 'J': /* ED -- Clear screen */
switch (csiescseq.arg[0]) { switch (csiescseq.arg[0]) {
case 0: /* below */ case 0: /* below */
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
if (term.c.y < term.row-1) { if (term.c.y < term.row-1) {
tclearregion(0, term.c.y+1, term.col-1, tclearregion(0, term.c.y+1, maxcol-1,
term.row-1); term.row-1);
} }
break; break;
case 1: /* above */ case 1: /* above */
if (term.c.y > 1) if (term.c.y > 1)
tclearregion(0, 0, term.col-1, term.c.y-1); tclearregion(0, 0, maxcol-1, term.c.y-1);
tclearregion(0, term.c.y, term.c.x, term.c.y); tclearregion(0, term.c.y, term.c.x, term.c.y);
break; break;
case 2: /* screen */ case 2: /* screen */
tclearregion(0, 0, term.col-1, term.row-1); if (!IS_SET(MODE_ALTSCREEN)) {
kscrolldown(&((Arg){ .i = term.scr }));
int n, m, bot = term.bot;
term.bot = term.row-1;
for (n = term.row-1; n >= 0; n--) {
for (m = 0; m < maxcol && term.line[n][m].u == ' ' && !term.line[n][m].mode; m++);
if (m < maxcol) {
tscrollup(0, n+1, 1);
break;
}
}
if (n < term.row-1)
tclearregion(0, 0, maxcol-1, term.row-n-2);
term.bot = bot;
break;
}
tclearregion(0, 0, maxcol-1, term.row-1);
break; break;
case 3: /* all including scrollback */ case 3: /* scrollback */
tclearregion(0, 0, term.col-1, term.row-1); if (!IS_SET(MODE_ALTSCREEN)) {
term.scr = 0;
term.scr = 0; term.histi = 0;
term.histi = 0; term.histn = 0;
for (int i = 0; i < HISTSIZE; i++) Glyph g=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
term.hist[i][0].u = '\0'; for (int i = 0; i < HISTSIZE; i++) {
for (int j = 0; j < maxcol; j++)
for (im = term.images; im; im = im->next) term.hist[i][j] = g;
im->should_delete = 1; }
}
break; break;
default: default:
goto unknown; goto unknown;
@ -1820,24 +1796,24 @@ csihandle(void)
case 'K': /* EL -- Clear line */ case 'K': /* EL -- Clear line */
switch (csiescseq.arg[0]) { switch (csiescseq.arg[0]) {
case 0: /* right */ case 0: /* right */
tclearregion(term.c.x, term.c.y, term.col-1, tclearregion(term.c.x, term.c.y, maxcol-1,
term.c.y); term.c.y);
break; break;
case 1: /* left */ case 1: /* left */
tclearregion(0, term.c.y, term.c.x, term.c.y); tclearregion(0, term.c.y, term.c.x, term.c.y);
break; break;
case 2: /* all */ case 2: /* all */
tclearregion(0, term.c.y, term.col-1, term.c.y); tclearregion(0, term.c.y, maxcol-1, term.c.y);
break; break;
} }
break; break;
case 'S': /* SU -- Scroll <n> line up */ case 'S': /* SU -- Scroll <n> line up */
DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[0], 1);
tscrollup(term.top, csiescseq.arg[0], 1); tscrollup(term.top, csiescseq.arg[0], 0);
break; break;
case 'T': /* SD -- Scroll <n> line down */ case 'T': /* SD -- Scroll <n> line down */
DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[0], 1);
tscrolldown(term.top, csiescseq.arg[0], 1); tscrolldown(term.top, csiescseq.arg[0]);
break; break;
case 'L': /* IL -- Insert <n> blank lines */ case 'L': /* IL -- Insert <n> blank lines */
DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[0], 1);
@ -1875,9 +1851,9 @@ csihandle(void)
break; break;
case 'n': /* DSR Device Status Report (cursor position) */ case 'n': /* DSR Device Status Report (cursor position) */
if (csiescseq.arg[0] == 6) { if (csiescseq.arg[0] == 6) {
len = snprintf(buf, sizeof(buf), "\033[%i;%iR", len = snprintf(buffer, sizeof(buffer), "\033[%i;%iR",
term.c.y+1, term.c.x+1); term.c.y+1, term.c.x+1);
ttywrite(buf, len, 0); ttywrite(buffer, len, 0);
} }
break; break;
case 'r': /* DECSTBM -- Set Scrolling Region */ case 'r': /* DECSTBM -- Set Scrolling Region */
@ -1967,13 +1943,47 @@ csireset(void)
memset(&csiescseq, 0, sizeof(csiescseq)); memset(&csiescseq, 0, sizeof(csiescseq));
} }
void
osc4_color_response(int num)
{
int n;
char buf[32];
unsigned char r, g, b;
if (xgetcolor(num, &r, &g, &b)) {
fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num);
return;
}
n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
num, r, r, g, g, b, b);
ttywrite(buf, n, 1);
}
void
osc_color_response(int index, int num)
{
int n;
char buf[32];
unsigned char r, g, b;
if (xgetcolor(index, &r, &g, &b)) {
fprintf(stderr, "erresc: failed to fetch osc color %d\n", index);
return;
}
n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
num, r, r, g, g, b, b);
ttywrite(buf, n, 1);
}
void void
strhandle(void) strhandle(void)
{ {
char *p = NULL, *dec; char *p = NULL, *dec;
int j, narg, par; int j, narg, par;
ImageList *new_image;
int i;
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
strparse(); strparse();
@ -2007,44 +2017,51 @@ strhandle(void)
} }
} }
return; return;
case 10: /* foreground set */ case 10:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = strescseq.args[1];
if (xsetcolorname(defaultfg, p))
fprintf(stderr, "erresc: invalid foreground color %d\n", p); if (!strcmp(p, "?"))
osc_color_response(defaultfg, 10);
else if (xsetcolorname(defaultfg, p))
fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
else else
redraw(); tfulldirt();
break;
return; return;
case 11: /* background set */ case 11:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = strescseq.args[1];
if (xsetcolorname(defaultbg, p))
fprintf(stderr, "erresc: invalid background color %d\n", p); if (!strcmp(p, "?"))
osc_color_response(defaultbg, 11);
else if (xsetcolorname(defaultbg, p))
fprintf(stderr, "erresc: invalid background color: %s\n", p);
else else
redraw(); tfulldirt();
break;
return; return;
case 12: /* cursor color */ case 12:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = strescseq.args[1];
if (xsetcolorname(defaultcs, p))
fprintf(stderr, "erresc: invalid cursor color %d\n", p); if (!strcmp(p, "?"))
osc_color_response(defaultcs, 12);
else if (xsetcolorname(defaultcs, p))
fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
else else
redraw(); tfulldirt();
break; return;
case 4: /* color set */ case 4: /* color set */
if ((par == 4 && narg < 3) || narg < 2) if ((par == 4 && narg < 3) || narg < 2)
break; break;
p = strescseq.args[((par == 4) ? 2 : 1)]; p = strescseq.args[((par == 4) ? 2 : 1)];
/* FALLTHROUGH */ /* FALLTHROUGH */
case 104: /* color reset, here p = NULL */ case 104: /* color reset */
if (par == 10) if (par == 10)
j = defaultfg; j = defaultfg;
else if (par == 11) else if (par == 11)
@ -2054,7 +2071,9 @@ strhandle(void)
else else
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (xsetcolorname(j, p)) { if (p && !strcmp(p, "?"))
osc4_color_response(j);
else if (xsetcolorname(j, p)) {
if (par == 104 && narg <= 1) if (par == 104 && narg <= 1)
return; /* color reset without parameter */ return; /* color reset without parameter */
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
@ -2062,7 +2081,7 @@ strhandle(void)
} else { } else {
if (j == defaultbg) if (j == defaultbg)
xclearwin(); xclearwin();
redraw(); tfulldirt();
} }
return; return;
} }
@ -2071,44 +2090,6 @@ strhandle(void)
xsettitle(strescseq.args[0], 0); xsettitle(strescseq.args[0], 0);
return; return;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
if (IS_SET(MODE_SIXEL)) {
term.mode &= ~MODE_SIXEL;
new_image = malloc(sizeof(ImageList));
memset(new_image, 0, sizeof(ImageList));
new_image->x = term.c.x;
new_image->y = term.c.y;
new_image->width = sixel_st.image.width;
new_image->height = sixel_st.image.height;
new_image->pixels = malloc(new_image->width * new_image->height * 4);
if (sixel_parser_finalize(&sixel_st, new_image->pixels) != 0) {
perror("sixel_parser_finalize() failed");
sixel_parser_deinit(&sixel_st);
return;
}
sixel_parser_deinit(&sixel_st);
if (term.images) {
ImageList *im;
for (im = term.images; im->next;)
im = im->next;
im->next = new_image;
new_image->prev = im;
} else {
term.images = new_image;
}
for (i = 0; i < (sixel_st.image.height + win.ch-1)/win.ch; ++i) {
int x;
tclearregion(term.c.x, term.c.y, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw, term.c.y);
for (x = term.c.x; x < MIN(term.col, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw); x++)
term.line[term.c.y][x].mode |= ATTR_SIXEL;
tnewline(1);
}
}
/* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */
if (strstr(strescseq.buf, "=1s") == strescseq.buf)
tsync_begin(); /* BSU */
else if (strstr(strescseq.buf, "=2s") == strescseq.buf)
tsync_end(); /* ESU */
return;
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */ case '^': /* PM -- Privacy Message */
return; return;
@ -2302,12 +2283,10 @@ tdectest(char c)
void void
tstrsequence(uchar c) tstrsequence(uchar c)
{ {
strreset();
switch (c) { switch (c) {
case 0x90: /* DCS -- Device Control String */ case 0x90: /* DCS -- Device Control String */
c = 'P'; c = 'P';
term.esc |= ESC_DCS;
break; break;
case 0x9f: /* APC -- Application Program Command */ case 0x9f: /* APC -- Application Program Command */
c = '_'; c = '_';
@ -2319,6 +2298,7 @@ tstrsequence(uchar c)
c = ']'; c = ']';
break; break;
} }
strreset();
strescseq.type = c; strescseq.type = c;
term.esc |= ESC_STR; term.esc |= ESC_STR;
} }
@ -2438,7 +2418,6 @@ eschandle(uchar ascii)
term.esc |= ESC_UTF8; term.esc |= ESC_UTF8;
return 0; return 0;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
term.esc |= ESC_DCS;
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */ case '^': /* PM -- Privacy Message */
case ']': /* OSC -- Operating System Command */ case ']': /* OSC -- Operating System Command */
@ -2471,7 +2450,7 @@ eschandle(uchar ascii)
break; break;
case 'M': /* RI -- Reverse index */ case 'M': /* RI -- Reverse index */
if (term.c.y == term.top) { if (term.c.y == term.top) {
tscrolldown(term.top, 1, 1); tscrolldown(term.top, 1);
} else { } else {
tmoveto(term.c.x, term.c.y-1); tmoveto(term.c.x, term.c.y-1);
} }
@ -2518,7 +2497,7 @@ tputc(Rune u)
Glyph *gp; Glyph *gp;
control = ISCONTROL(u); control = ISCONTROL(u);
if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL)) if (u < 127 || !IS_SET(MODE_UTF8))
{ {
c[0] = u; c[0] = u;
width = len = 1; width = len = 1;
@ -2540,18 +2519,11 @@ tputc(Rune u)
if (term.esc & ESC_STR) { if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 || if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) { ISCONTROLC1(u)) {
term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); term.esc &= ~(ESC_START|ESC_STR);
term.esc |= ESC_STR_END; term.esc |= ESC_STR_END;
goto check_control_code; goto check_control_code;
} }
if (IS_SET(MODE_SIXEL)) {
if (sixel_parser_parse(&sixel_st, (unsigned char *)&u, 1) != 0)
perror("sixel_parser_parse() failed");
return;
}
if (term.esc & ESC_DCS)
goto check_control_code;
if (strescseq.len+len >= strescseq.siz) { if (strescseq.len+len >= strescseq.siz) {
/* /*
@ -2603,15 +2575,6 @@ check_control_code:
csihandle(); csihandle();
} }
return; return;
} else if (term.esc & ESC_DCS) {
csiescseq.buf[csiescseq.len++] = u;
if (BETWEEN(u, 0x40, 0x7E)
|| csiescseq.len >= \
sizeof(csiescseq.buf)-1) {
csiparse();
dcshandle();
}
return;
} else if (term.esc & ESC_UTF8) { } else if (term.esc & ESC_UTF8) {
tdefutf8(u); tdefutf8(u);
} else if (term.esc & ESC_ALTCHARSET) { } else if (term.esc & ESC_ALTCHARSET) {
@ -2654,6 +2617,10 @@ check_control_code:
if (width == 2) { if (width == 2) {
gp->mode |= ATTR_WIDE; gp->mode |= ATTR_WIDE;
if (term.c.x+1 < term.col) { if (term.c.x+1 < term.col) {
if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) {
gp[2].u = ' ';
gp[2].mode &= ~ATTR_WDUMMY;
}
gp[1].u = '\0'; gp[1].u = '\0';
gp[1].mode = ATTR_WDUMMY; gp[1].mode = ATTR_WDUMMY;
} }
@ -2672,11 +2639,9 @@ twrite(const char *buf, int buflen, int show_ctrl)
Rune u; Rune u;
int n; int n;
int su0 = su;
twrite_aborted = 0;
for (n = 0; n < buflen; n += charsize) { for (n = 0; n < buflen; n += charsize) {
if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) if (IS_SET(MODE_UTF8))
{ {
/* process a complete utf8 char */ /* process a complete utf8 char */
charsize = utf8decode(buf + n, &u, buflen - n); charsize = utf8decode(buf + n, &u, buflen - n);
@ -2686,10 +2651,6 @@ twrite(const char *buf, int buflen, int show_ctrl)
u = buf[n] & 0xFF; u = buf[n] & 0xFF;
charsize = 1; charsize = 1;
} }
if (su0 && !su) {
twrite_aborted = 1;
break; // ESU - allow rendering before a new BSU
}
if (show_ctrl && ISCONTROL(u)) { if (show_ctrl && ISCONTROL(u)) {
if (u & 0x80) { if (u & 0x80) {
u &= 0x7f; u &= 0x7f;
@ -2754,12 +2715,11 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
Glyph gc=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
for (i = 0; i < HISTSIZE; i++) { for (i = 0; i < HISTSIZE; i++) {
term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
for (j = mincol; j < col; j++) { for (j = mincol; j < col; j++)
term.hist[i][j] = term.c.attr; term.hist[i][j] = gc;
term.hist[i][j].u = ' ';
}
} }
/* resize each row to new width, zero-pad if needed */ /* resize each row to new width, zero-pad if needed */

View file

@ -43,21 +43,10 @@ enum glyph_attribute {
ATTR_WDUMMY = 1 << 10, ATTR_WDUMMY = 1 << 10,
ATTR_BOXDRAW = 1 << 11, ATTR_BOXDRAW = 1 << 11,
ATTR_LIGA = 1 << 12, ATTR_LIGA = 1 << 12,
ATTR_SIXEL = 1 << 13,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
ATTR_DIRTYUNDERLINE = 1 << 15, ATTR_DIRTYUNDERLINE = 1 << 15,
}; };
typedef struct _ImageList {
struct _ImageList *next, *prev;
unsigned char *pixels;
void *pixmap;
int width;
int height;
int x;
int y;
int should_delete;
} ImageList;
enum drawing_mode { enum drawing_mode {
DRAW_NONE = 0, DRAW_NONE = 0,
@ -120,6 +109,7 @@ typedef struct {
Line *alt; /* alternate screen */ Line *alt; /* alternate screen */
Line hist[HISTSIZE]; /* history buffer */ Line hist[HISTSIZE]; /* history buffer */
int histi; /* history index */ int histi; /* history index */
int histn; /* number of history entries */
int scr; /* scroll back */ int scr; /* scroll back */
int *dirty; /* dirtyness of lines */ int *dirty; /* dirtyness of lines */
TCursor c; /* cursor */ TCursor c; /* cursor */
@ -133,8 +123,6 @@ typedef struct {
int charset; /* current charset */ int charset; /* current charset */
int icharset; /* selected charset for sequence */ int icharset; /* selected charset for sequence */
int *tabs; int *tabs;
ImageList *images; /* sixel images */
ImageList *images_alt; /* sixel images for alternate screen */
Rune lastc; /* last printed char outside of sequence, 0 if control */ Rune lastc; /* last printed char outside of sequence, 0 if control */
} Term; } Term;
@ -175,11 +163,6 @@ typedef struct {
Draw draw; Draw draw;
Visual *vis; Visual *vis;
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
/* Here, we use the term *pointer* to differentiate the cursor
* one sees when hovering the mouse over the terminal from, e.g.,
* a green rectangle where text would be entered. */
Cursor vpointer, bpointer; /* visible and hidden pointers */
int pointerisvisible;
int scr; int scr;
int isfixed; /* is fixed geometry? */ int isfixed; /* is fixed geometry? */
int depth; /* bit depth */ int depth; /* bit depth */
@ -208,7 +191,6 @@ typedef struct {
void (*func)(const Arg *); void (*func)(const Arg *);
const Arg arg; const Arg arg;
uint release; uint release;
int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
} MouseShortcut; } MouseShortcut;
typedef struct { typedef struct {
@ -279,6 +261,9 @@ size_t utf8encode(Rune, char *);
void *xmalloc(size_t); void *xmalloc(size_t);
void *xrealloc(void *, size_t); void *xrealloc(void *, size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
int isboxdraw(Rune); int isboxdraw(Rune);
ushort boxdrawindex(const Glyph *); ushort boxdrawindex(const Glyph *);
#ifdef XFT_VERSION #ifdef XFT_VERSION
@ -300,7 +285,6 @@ extern unsigned int tabspaces;
extern unsigned int defaultfg; extern unsigned int defaultfg;
extern unsigned int defaultbg; extern unsigned int defaultbg;
extern unsigned int defaultcs; extern unsigned int defaultcs;
extern int extpipeactive;
extern const int boxdraw, boxdraw_bold, boxdraw_braille; extern const int boxdraw, boxdraw_bold, boxdraw_braille;
extern float alpha; extern float alpha;

View file

@ -10,7 +10,7 @@ st-mono| simpleterm monocolor,
cbt=\E[Z, cbt=\E[Z,
cvvis=\E[?25h, cvvis=\E[?25h,
civis=\E[?25l, civis=\E[?25l,
clear=\E[H\E[3J, clear=\E[H\E[2J,
cnorm=\E[?12l\E[?25h, cnorm=\E[?12l\E[?25h,
colors#2, colors#2,
cols#80, cols#80,
@ -35,6 +35,7 @@ st-mono| simpleterm monocolor,
el=\E[K, el=\E[K,
el1=\E[1K, el1=\E[1K,
enacs=\E)0, enacs=\E)0,
E3=\E[3J,
flash=\E[?5h$<80/>\E[?5l, flash=\E[?5h$<80/>\E[?5l,
fsl=^G, fsl=^G,
home=\E[H, home=\E[H,

View file

@ -105,6 +105,7 @@ static void selnotify(XEvent *);
static void selclear_(XEvent *); static void selclear_(XEvent *);
static void selrequest(XEvent *); static void selrequest(XEvent *);
static void setsel(char *, Time); static void setsel(char *, Time);
static void sigusr1_reload(int sig);
static int mouseaction(XEvent *, uint); static int mouseaction(XEvent *, uint);
static void mousesel(XEvent *, int); static void mousesel(XEvent *, int);
static void mousereport(XEvent *); static void mousereport(XEvent *);
@ -181,9 +182,10 @@ static char *opt_io = NULL;
static char *opt_line = NULL; static char *opt_line = NULL;
static char *opt_name = NULL; static char *opt_name = NULL;
static char *opt_title = NULL; static char *opt_title = NULL;
static char *opt_dir = NULL;
static int oldbutton = 3; /* button event on startup: 3 = release */ static uint buttons; /* bit field of pressed buttons */
static int cursorblinks = 0; static int cursorblinks = 0;
int borderpx; int borderpx;
static Cursor cursor; static Cursor cursor;
@ -284,12 +286,12 @@ evrow(XEvent *e)
uint uint
buttonmask(uint button) buttonmask(uint button)
{ {
return button == Button1 ? Button1Mask return button == Button1 ? Button1Mask
: button == Button2 ? Button2Mask : button == Button2 ? Button2Mask
: button == Button3 ? Button3Mask : button == Button3 ? Button3Mask
: button == Button4 ? Button4Mask : button == Button4 ? Button4Mask
: button == Button5 ? Button5Mask : button == Button5 ? Button5Mask
: 0; : 0;
} }
int int
@ -314,7 +316,6 @@ mouseaction(XEvent *e, uint release)
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
if (ms->release == release && if (ms->release == release &&
ms->button == e->xbutton.button && ms->button == e->xbutton.button &&
(!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
(match(ms->mod, state) || /* exact or forced */ (match(ms->mod, state) || /* exact or forced */
match(ms->mod, state & ~forcemousemod))) { match(ms->mod, state & ~forcemousemod))) {
ms->func(&(ms->arg)); ms->func(&(ms->arg));
@ -345,61 +346,69 @@ mousesel(XEvent *e, int done)
void void
mousereport(XEvent *e) mousereport(XEvent *e)
{ {
int len, x = evcol(e), y = evrow(e), int len, btn, code;
button = e->xbutton.button, state = e->xbutton.state; int x = evcol(e), y = evrow(e);
int state = e->xbutton.state;
char buf[40]; char buf[40];
static int ox, oy; static int ox, oy;
/* from urxvt */ if (e->type == MotionNotify) {
if (e->xbutton.type == MotionNotify) {
if (x == ox && y == oy) if (x == ox && y == oy)
return; return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return; return;
/* MOUSE_MOTION: no reporting if no button is pressed */ /* MODE_MOUSEMOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
return; return;
button = oldbutton + 32; /* Set btn to lowest-numbered pressed button, or 12 if no
ox = x; * buttons are pressed. */
oy = y; for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
;
code = 32;
} else { } else {
if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { btn = e->xbutton.button;
button = 3; /* Only buttons 1 through 11 can be encoded */
} else { if (btn < 1 || btn > 11)
button -= Button1; return;
if (button >= 7) if (e->type == ButtonRelease) {
button += 128 - 7;
else 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 */ /* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10)) if (IS_SET(MODE_MOUSEX10))
return; return;
if (button == 64 || button == 65) /* Don't send release events for the scroll wheel */
if (btn == 4 || btn == 5)
return; return;
} }
code = 0;
} }
ox = x;
oy = y;
/* Encode btn into code. If no button is pressed for a motion event in
* MODE_MOUSEMANY, then encode it as a release. */
if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
code += 3;
else if (btn >= 8)
code += 128 + btn - 8;
else if (btn >= 4)
code += 64 + btn - 4;
else
code += btn - 1;
if (!IS_SET(MODE_MOUSEX10)) { if (!IS_SET(MODE_MOUSEX10)) {
button += ((state & ShiftMask ) ? 4 : 0) code += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod4Mask ) ? 8 : 0) + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ ((state & ControlMask) ? 16 : 0); + ((state & ControlMask) ? 16 : 0);
} }
if (IS_SET(MODE_MOUSESGR)) { if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
button, x+1, y+1, code, x+1, y+1,
e->xbutton.type == ButtonRelease ? 'm' : 'M'); e->type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) { } else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
32+button, 32+x+1, 32+y+1); 32+code, 32+x+1, 32+y+1);
} else { } else {
return; return;
} }
@ -410,9 +419,13 @@ mousereport(XEvent *e)
void void
bpress(XEvent *e) bpress(XEvent *e)
{ {
int btn = e->xbutton.button;
struct timespec now; struct timespec now;
int snap; int snap;
if (1 <= btn && btn <= 11)
buttons |= 1 << (btn-1);
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
@ -421,7 +434,7 @@ bpress(XEvent *e)
if (mouseaction(e, 0)) if (mouseaction(e, 0))
return; return;
if (e->xbutton.button == Button1) { if (btn == Button1) {
/* /*
* If the user clicks below predefined timeouts specific * If the user clicks below predefined timeouts specific
* snapping behaviour is exposed. * snapping behaviour is exposed.
@ -453,6 +466,7 @@ propnotify(XEvent *e)
xpev->atom == clipboard)) { xpev->atom == clipboard)) {
selnotify(e); selnotify(e);
} }
} }
void void
@ -483,7 +497,8 @@ selnotify(XEvent *e)
return; return;
} }
if (e->type == PropertyNotify && nitems == 0 && rem == 0) { if (e->type == PropertyNotify && nitems == 0 && rem == 0)
{
/* /*
* If there is some PropertyNotify with no data, then * If there is some PropertyNotify with no data, then
* this is the signal of the selection owner that all * this is the signal of the selection owner that all
@ -628,6 +643,13 @@ setsel(char *str, Time t)
clipcopy(NULL); clipcopy(NULL);
} }
void
sigusr1_reload(int sig)
{
reload_config(sig);
signal(SIGUSR1, sigusr1_reload);
}
void void
xsetsel(char *str) xsetsel(char *str)
{ {
@ -637,6 +659,11 @@ xsetsel(char *str)
void void
brelease(XEvent *e) brelease(XEvent *e)
{ {
int btn = e->xbutton.button;
if (1 <= btn && btn <= 11)
buttons &= ~(1 << (btn-1));
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
@ -644,7 +671,7 @@ brelease(XEvent *e)
if (mouseaction(e, 1)) if (mouseaction(e, 1))
return; return;
if (e->xbutton.button == Button1) { if (btn == Button1) {
mousesel(e, 1); mousesel(e, 1);
openUrlOnClick(evcol(e), evrow(e), url_opener); openUrlOnClick(evcol(e), evrow(e), url_opener);
} }
@ -653,15 +680,6 @@ brelease(XEvent *e)
void void
bmotion(XEvent *e) bmotion(XEvent *e)
{ {
if (!xw.pointerisvisible) {
if (win.mode & MODE_MOUSE)
XUndefineCursor(xw.dpy, xw.win);
else
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
xw.pointerisvisible = 1;
if (!IS_SET(MODE_MOUSEMANY))
xsetpointermotion(0);
}
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
@ -774,6 +792,19 @@ xloadcols(void)
loaded = 1; loaded = 1;
} }
int
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
{
if (!BETWEEN(x, 0, dc.collen))
return 1;
*r = dc.col[x].color.red >> 8;
*g = dc.col[x].color.green >> 8;
*b = dc.col[x].color.blue >> 8;
return 0;
}
int int
xsetcolorname(int x, const char *name) xsetcolorname(int x, const char *name)
{ {
@ -805,12 +836,9 @@ xsetcolorname(int x, const char *name)
void void
xclear(int x1, int y1, int x2, int y2) xclear(int x1, int y1, int x2, int y2)
{ {
Color c; XftDrawRect(xw.draw,
c = dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg]; &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
if (invertcolors) { x1, y1, x2-x1, y2-y1);
c = invertedcolor(&c);
}
XftDrawRect(xw.draw, &c, x1, y1, x2-x1, y2-y1);
} }
void void
@ -1098,14 +1126,11 @@ void
xinit(int cols, int rows) xinit(int cols, int rows)
{ {
XGCValues gcvalues; XGCValues gcvalues;
Pixmap blankpm;
Window parent; Window parent;
pid_t thispid = getpid(); pid_t thispid = getpid();
XWindowAttributes attr; XWindowAttributes attr;
XVisualInfo vis; XVisualInfo vis;
if (!(xw.dpy = XOpenDisplay(NULL)))
die("can't open display\n");
xw.scr = XDefaultScreen(xw.dpy); xw.scr = XDefaultScreen(xw.dpy);
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
@ -1175,14 +1200,10 @@ xinit(int cols, int rows)
} }
/* white cursor, black outline */ /* white cursor, black outline */
xw.pointerisvisible = 1; cursor = XcursorLibraryLoadCursor(xw.dpy, mouseshape);
xw.vpointer = XcursorLibraryLoadCursor(xw.dpy, mouseshape); XDefineCursor(xw.dpy, xw.win, cursor);
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1);
xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm,
&xmousefg, &xmousebg, 0, 0);
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
@ -1441,6 +1462,9 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
bg = &dc.col[base.bg]; bg = &dc.col[base.bg];
} }
/* Change basic system colors [0-7] to bright system colors [8-15] */
if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
fg = &dc.col[base.fg + 8];
if (IS_SET(MODE_REVERSE)) { if (IS_SET(MODE_REVERSE)) {
if (fg == &dc.col[defaultfg]) { if (fg == &dc.col[defaultfg]) {
@ -1494,18 +1518,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
if (base.mode & ATTR_INVISIBLE) if (base.mode & ATTR_INVISIBLE)
fg = bg; fg = bg;
if (invertcolors) {
revfg = invertedcolor(fg);
revbg = invertedcolor(bg);
fg = &revfg;
bg = &revbg;
}
if (dmode & DRAW_BG) { if (dmode & DRAW_BG) {
/* Intelligent cleaning up of the borders. */ /* Intelligent cleaning up of the borders. */
if (x == 0) { if (x == 0) {
xclear(0, (y == 0)? 0 : winy, win.vborderpx, xclear(0, (y == 0)? 0 : winy, win.hborderpx,
winy + win.ch + winy + win.ch +
((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
} }
@ -1514,7 +1532,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
} }
if (y == 0) if (y == 0)
xclear(winx, 0, winx + width, win.hborderpx); xclear(winx, 0, winx + width, win.vborderpx);
if (winy + win.ch >= win.vborderpx + win.th) if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h); xclear(winx, winy + win.ch, winx + width, win.h);
@ -1574,9 +1592,8 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
// Underline Style // Underline Style
if (base.ustyle != 3) { if (base.ustyle != 3) {
//XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1);
XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx, XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx,
winy + dc.font.ascent + 1, width, wlw); winy + dc.font.ascent * chscale + 1, width, wlw);
} else if (base.ustyle == 3) { } else if (base.ustyle == 3) {
int ww = win.cw;//width; int ww = win.cw;//width;
int wh = dc.font.descent - wlw/2 - 1;//r.height/7; int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
@ -1888,7 +1905,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
} }
if (base.mode & ATTR_STRUCK) { if (base.mode & ATTR_STRUCK) {
XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent / 3, XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3,
width, 1); width, 1);
} }
} }
@ -2088,8 +2105,6 @@ xfreetitlestack(void)
int int
xstartdraw(void) xstartdraw(void)
{ {
if (IS_SET(MODE_VISIBLE))
XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
return IS_SET(MODE_VISIBLE); return IS_SET(MODE_VISIBLE);
} }
@ -2135,72 +2150,12 @@ xdrawline(Line line, int x1, int y1, int x2)
void void
xfinishdraw(void) xfinishdraw(void)
{ {
ImageList *im;
int x, y;
int n = 0;
int nlimit = 256;
XRectangle *rects = NULL;
XGCValues gcvalues;
GC gc;
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
win.h, 0, 0); XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
XSetForeground(xw.dpy, dc.gc, XSetForeground(xw.dpy, dc.gc,
dc.col[IS_SET(MODE_REVERSE)? dc.col[IS_SET(MODE_REVERSE)?
defaultfg : defaultbg].pixel); defaultfg : defaultbg].pixel);
for (im = term.images; im; im = im->next) {
if (term.images == NULL) {
/* last image was deleted, bail out */
break;
}
if (im->should_delete) {
delete_image(im);
/* prevent the next iteration from accessing an invalid image pointer */
im = term.images;
if (im == NULL) {
break;
} else {
continue;
}
}
if (!im->pixmap) {
im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, im->width, im->height,
xw.depth
);
XImage ximage = {
.format = ZPixmap,
.data = (char *)im->pixels,
.width = im->width,
.height = im->height,
.xoffset = 0,
.byte_order = LSBFirst,
.bitmap_bit_order = MSBFirst,
.bits_per_pixel = 32,
.bytes_per_line = im->width * 4,
.bitmap_unit = 32,
.bitmap_pad = 32,
.depth = xw.depth
};
XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, im->width, im->height);
free(im->pixels);
im->pixels = NULL;
}
n = 0;
memset(&gcvalues, 0, sizeof(gcvalues));
gc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, 0, 0, im->width, im->height, borderpx + im->x * win.cw, borderpx + im->y * win.ch);
XFreeGC(xw.dpy, gc);
}
free(rects);
drawregion(0, 0, term.col, term.row);
} }
void void
@ -2238,8 +2193,6 @@ unmap(XEvent *ev)
void void
xsetpointermotion(int set) xsetpointermotion(int set)
{ {
if (!set && !xw.pointerisvisible)
return;
MODBIT(xw.attrs.event_mask, set, PointerMotionMask); MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
} }
@ -2250,7 +2203,6 @@ xsetmode(int set, unsigned int flags)
int mode = win.mode; int mode = win.mode;
MODBIT(win.mode, set, flags); MODBIT(win.mode, set, flags);
if ((flags & MODE_MOUSE) if ((flags & MODE_MOUSE)
&& xw.pointerisvisible
) { ) {
if (win.mode & MODE_MOUSE) if (win.mode & MODE_MOUSE)
XUndefineCursor(xw.dpy, xw.win); XUndefineCursor(xw.dpy, xw.win);
@ -2371,11 +2323,6 @@ kpress(XEvent *ev)
Status status; Status status;
Shortcut *bp; Shortcut *bp;
if (xw.pointerisvisible) {
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
xsetpointermotion(1);
xw.pointerisvisible = 0;
}
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
@ -2483,7 +2430,7 @@ run(void)
FD_SET(ttyfd, &rfd); FD_SET(ttyfd, &rfd);
FD_SET(xfd, &rfd); FD_SET(xfd, &rfd);
if (XPending(xw.dpy) || ttyread_pending()) if (XPending(xw.dpy))
timeout = 0; /* existing events might not set xfd */ timeout = 0; /* existing events might not set xfd */
seltv.tv_sec = timeout / 1E3; seltv.tv_sec = timeout / 1E3;
@ -2497,8 +2444,7 @@ run(void)
} }
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
int ttyin = FD_ISSET(ttyfd, &rfd) || ttyread_pending(); if (FD_ISSET(ttyfd, &rfd))
if (ttyin)
ttyread(); ttyread();
xev = 0; xev = 0;
@ -2522,7 +2468,7 @@ run(void)
* maximum latency intervals during `cat huge.txt`, and perfect * maximum latency intervals during `cat huge.txt`, and perfect
* sync with periodic updates from animations/key-repeats/etc. * sync with periodic updates from animations/key-repeats/etc.
*/ */
if (ttyin || xev) if (FD_ISSET(ttyfd, &rfd) || xev)
{ {
if (!drawing) { if (!drawing) {
trigger = now; trigger = now;
@ -2538,17 +2484,6 @@ run(void)
continue; /* we have time, try to find idle */ continue; /* we have time, try to find idle */
} }
if (tinsync(su_timeout)) {
/*
* on synchronized-update draw-suspension: don't reset
* drawing so that we draw ASAP once we can (just after
* ESU). it won't be too soon because we already can
* draw now but we skip. we set timeout > 0 to draw on
* SU-timeout even without new content.
*/
timeout = minlatency;
continue;
}
/* idle detected or maxlatency exhausted -> draw */ /* idle detected or maxlatency exhausted -> draw */
timeout = -1; timeout = -1;
@ -2565,11 +2500,6 @@ run(void)
} }
} }
/* Refresh before drawing */
cresize(0, 0);
redraw();
xhints();
draw(); draw();
XFlush(xw.dpy); XFlush(xw.dpy);
drawing = 0; drawing = 0;
@ -2580,11 +2510,13 @@ void
usage(void) usage(void)
{ {
die("usage: %s [-aiv] [-c class]" die("usage: %s [-aiv] [-c class]"
" [-d path]"
" [-f font] [-g geometry]" " [-f font] [-g geometry]"
" [-n name] [-o file]\n" " [-n name] [-o file]\n"
" [-T title] [-t title] [-w windowid]" " [-T title] [-t title] [-w windowid]"
" [[-e] command [args ...]]\n" " [[-e] command [args ...]]\n"
" %s [-aiv] [-c class]" " %s [-aiv] [-c class]"
" [-d path]"
" [-f font] [-g geometry]" " [-f font] [-g geometry]"
" [-n name] [-o file]\n" " [-n name] [-o file]\n"
" [-T title] [-t title] [-w windowid] -l line" " [-T title] [-t title] [-w windowid] -l line"
@ -2608,6 +2540,9 @@ main(int argc, char *argv[])
case 'c': case 'c':
opt_class = EARGF(usage()); opt_class = EARGF(usage());
break; break;
case 'd':
opt_dir = EARGF(usage());
break;
case 'e': case 'e':
if (argc > 0) if (argc > 0)
--argc, ++argv; --argc, ++argv;
@ -2654,13 +2589,19 @@ run:
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
XSetLocaleModifiers(""); XSetLocaleModifiers("");
reload_config(-1); signal(SIGUSR1, sigusr1_reload);
if (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n");
config_init(xw.dpy);
cols = MAX(cols, 1); cols = MAX(cols, 1);
rows = MAX(rows, 1); rows = MAX(rows, 1);
tnew(cols, rows); tnew(cols, rows);
xinit(cols, rows); xinit(cols, rows);
xsetenv(); xsetenv();
selinit(); selinit();
if (opt_dir && chdir(opt_dir))
die("Can't change to working directory %s\n", opt_dir);
run(); run();
return 0; return 0;