Skip to content

Commit f2a180d

Browse files
committed
Determine the value of inline_img_protocol based on the invoking terminal
* Compile out enable_inline_img ifndef USE_IMAGE * Add enable_inline_img_config for configuration; leave enable_inline_img for state * Make auto-selection of inline_img_protocol the default value of enable_inline_img_config
1 parent ee66aab commit f2a180d

File tree

7 files changed

+165
-8
lines changed

7 files changed

+165
-8
lines changed

display.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -530,12 +530,14 @@ drawAnchorCursor0(Buffer *buf, AnchorList *al, int hseq, int prevhseq,
530530
int start_pos = an->start.pos;
531531
int end_pos = an->end.pos;
532532
for (i = an->start.pos; i < an->end.pos; i++) {
533-
if (enable_inline_image && (l->propBuf[i] & PE_IMAGE)) {
533+
#ifdef USE_IMAGE
534+
if (enable_inline_image && (l->propBuf[i] & PE_IMAGE)) {
534535
if (start_pos == i)
535536
start_pos = i + 1;
536537
else if (end_pos == an->end.pos)
537538
end_pos = i - 1;
538539
}
540+
#endif
539541
if (l->propBuf[i] & (PE_IMAGE | PE_ANCHOR | PE_FORM)) {
540542
if (active)
541543
l->propBuf[i] |= PE_ACTIVE;

fm.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,14 @@ extern int REV_LB[];
317317
#define EOL(l) (&(l)->ptr[(l)->length])
318318
#define IS_EOL(p,l) ((p)==&(l)->ptr[(l)->length])
319319

320+
#ifdef USE_IMAGE
321+
#define INLINE_IMG_AUTO -1
320322
#define INLINE_IMG_NONE 0
321323
#define INLINE_IMG_OSC5379 1
322324
#define INLINE_IMG_SIXEL 2
323325
#define INLINE_IMG_ITERM2 3
324326
#define INLINE_IMG_KITTY 4
327+
#endif
325328

326329
/*
327330
* Types.
@@ -940,7 +943,10 @@ global char *CurrentKeyData;
940943
global char *CurrentCmdData;
941944
global char *w3m_reqlog;
942945
extern char *w3m_version;
943-
extern int enable_inline_image;
946+
#ifdef USE_IMAGE
947+
global unsigned char enable_inline_image init(INLINE_IMG_NONE);
948+
global signed char enable_inline_image_config init(INLINE_IMG_AUTO);
949+
#endif
944950

945951
#define DUMP_BUFFER 0x01
946952
#define DUMP_HEAD 0x02

image.c

+42-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ static int image_index = 0;
1616

1717
/* display image */
1818

19-
typedef struct _termialImage {
19+
typedef struct _terminalImage {
2020
ImageCache *cache;
2121
short x;
2222
short y;
@@ -34,10 +34,15 @@ static pid_t Imgdisplay_pid = 0;
3434
static int openImgdisplay(void);
3535
static void closeImgdisplay(void);
3636
static int getCharSize(void);
37+
static int inline_img_protocol_autodetect(void);
3738

3839
void
3940
initImage()
4041
{
42+
enable_inline_image = enable_inline_image_config == INLINE_IMG_AUTO
43+
? inline_img_protocol_autodetect()
44+
: enable_inline_image_config;
45+
4146
if (activeImage)
4247
return;
4348
if (getCharSize())
@@ -133,6 +138,37 @@ openImgdisplay()
133138
return FALSE;
134139
}
135140

141+
static int
142+
inline_img_protocol_autodetect(void)
143+
{
144+
int result;
145+
const char *env_term, *konsole_version;
146+
147+
if ((env_term = getenv("TERM"))) {
148+
if (strcmp(env_term, "xterm-kitty") == 0)
149+
return INLINE_IMG_KITTY;
150+
if (strcmp(env_term, "xterm-ghostty") == 0)
151+
return INLINE_IMG_KITTY;
152+
/* yaft doesn't correctly respond to \e[c, but is sixel-capable
153+
* anyway. Thanks to hackerb9/lsix */
154+
if (strncmp(env_term, "yaft", 4) == 0)
155+
return INLINE_IMG_SIXEL;
156+
}
157+
158+
if ((konsole_version = getenv("KONSOLE_VERSION"))
159+
&& strcmp(konsole_version, "220770") >= 0)
160+
return INLINE_IMG_KITTY;
161+
162+
if ((result = img_protocol_test_for_sixel()) != INLINE_IMG_NONE)
163+
return result;
164+
165+
/* If mlterm too old to support sixel, probably supports older OSC5379 */
166+
if (env_term && strncmp(env_term, "mlterm", 6) == 0)
167+
return INLINE_IMG_OSC5379;
168+
169+
return INLINE_IMG_NONE;
170+
}
171+
136172
static void
137173
closeImgdisplay(void)
138174
{
@@ -256,6 +292,11 @@ drawImage(void)
256292
put_image_iterm2(url, x, y, sw, sh);
257293
} else if (enable_inline_image == INLINE_IMG_KITTY) {
258294
put_image_kitty(url, x, y, i->width, i->height, i->sx, i->sy, sw * pixel_per_char, sh * pixel_per_line_i, sw, sh);
295+
#ifdef DEBUG
296+
} else {
297+
fprintf(stderr, "Unrecognised inline image protocol: %d\n",
298+
enable_inline_image);
299+
#endif
259300
}
260301

261302
continue ;

main.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ static int searchKeyNum(void);
127127
#define help() fusage(stdout, 0)
128128
#define usage() fusage(stderr, 1)
129129

130-
int enable_inline_image;
131-
132130
static void
133131
fversion(FILE * f)
134132
{
@@ -719,13 +717,13 @@ main(int argc, char **argv)
719717
set_pixel_per_line = TRUE;
720718
}
721719
}
722-
#endif
723720
else if (!strcmp("-ri", argv[i])) {
724721
enable_inline_image = INLINE_IMG_OSC5379;
725722
}
726723
else if (!strcmp("-sixel", argv[i])) {
727724
enable_inline_image = INLINE_IMG_SIXEL;
728725
}
726+
#endif
729727
else if (!strcmp("-num", argv[i]))
730728
showLineNum = TRUE;
731729
else if (!strcmp("-no-proxy", argv[i]))
@@ -6006,11 +6004,13 @@ deleteFiles()
60066004
}
60076005
while ((f = popText(fileToDelete)) != NULL) {
60086006
unlink(f);
6007+
#ifdef USE_IMAGE
60096008
if (enable_inline_image == INLINE_IMG_SIXEL && strcmp(f+strlen(f)-4, ".gif") == 0) {
60106009
Str firstframe = Strnew_charp(f);
60116010
Strcat_charp(firstframe, "-1");
60126011
unlink(firstframe->ptr);
60136012
}
6013+
#endif
60146014
}
60156015
}
60166016

rc.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static struct sel_c graphic_char_str[] = {
377377

378378
#ifdef USE_IMAGE
379379
static struct sel_c inlineimgstr[] = {
380+
{N_S(INLINE_IMG_AUTO), N_("auto-select protocol")},
380381
{N_S(INLINE_IMG_NONE), N_("external command")},
381382
{N_S(INLINE_IMG_OSC5379), N_("OSC 5379 (mlterm)")},
382383
{N_S(INLINE_IMG_SIXEL), N_("sixel (img2sixel)")},
@@ -449,7 +450,7 @@ struct param_ptr params1[] = {
449450
CMT_EXT_IMAGE_VIEWER, NULL},
450451
{"image_scale", P_SCALE, PI_TEXT, (void *)&image_scale, CMT_IMAGE_SCALE,
451452
NULL},
452-
{"inline_img_protocol", P_INT, PI_SEL_C, (void *)&enable_inline_image,
453+
{"inline_img_protocol", P_CHARINT, PI_SEL_C, (void *)&enable_inline_image_config,
453454
CMT_INLINE_IMG_PROTOCOL, (void *)inlineimgstr},
454455
{"imgdisplay", P_STRING, PI_TEXT, (void *)&Imgdisplay, CMT_IMGDISPLAY,
455456
NULL},
@@ -1313,7 +1314,7 @@ sync_with_option(void)
13131314
init_migemo();
13141315
#endif
13151316
#ifdef USE_IMAGE
1316-
if (fmInitialized && (displayImage || enable_inline_image))
1317+
if (fmInitialized && (displayImage || enable_inline_image_config))
13171318
initImage();
13181319
#else
13191320
displayImage = FALSE; /* XXX */

terms.c

+106
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,112 @@ put_image_sixel(char *url, int x, int y, int w, int h, int sx, int sy, int sw, i
856856
MOVE(Currentbuf->cursorY,Currentbuf->cursorX);
857857
}
858858

859+
static int
860+
have_img2sixel(void)
861+
{
862+
pid_t child_pid;
863+
int wstatus;
864+
865+
if (getenv("W3M_IMG2SIXEL"))
866+
return TRUE;
867+
868+
switch (child_pid = fork()) {
869+
case -1:
870+
return FALSE;
871+
case 0:
872+
close(STDOUT_FILENO);
873+
close(STDERR_FILENO);
874+
execlp("img2sixel", "img2sixel", "--version", NULL);
875+
/* if exec fails */
876+
_exit(-1);
877+
default:
878+
return
879+
#ifdef HAVE_WAITPID
880+
waitpid(child_pid, &wstatus, 0) != -1
881+
#else
882+
wait(&wstatus) != -1
883+
#endif
884+
&& WIFEXITED(wstatus)
885+
&& WEXITSTATUS(wstatus) == 0;
886+
}
887+
}
888+
889+
/*
890+
* NB: in theory, user input could be snarfed up with the read(2); in practice,
891+
* only museum pieces have such low latency, so we should get the device
892+
* attributes (and only the device attributes) immediately. If ever this becomes
893+
* an issue (which it won't), ungetch(3) can be used on any extraneous input
894+
*/
895+
int
896+
img_protocol_test_for_sixel(void)
897+
{
898+
static const char errstr[] = "Can't get terminal attributes";
899+
size_t response_size = 256, len = 0;
900+
char *response = GC_MALLOC_ATOMIC(response_size);
901+
902+
/* request tty send primary device attributes */
903+
write(tty, "\033[c", 3);
904+
905+
/* loop until we get the whole response */
906+
for (; response; response = GC_REALLOC(response, response_size *= 2)) {
907+
ssize_t nchars_read;
908+
int nret;
909+
fd_set fds;
910+
/* wait 0.2s (from get_pixel_per_char()) for input */
911+
struct timeval timeout = { 0, 0.2 * 1000000 };
912+
FD_ZERO(&fds);
913+
FD_SET(tty, &fds);
914+
if ((nret = select(tty + 1, &fds, NULL, NULL, &timeout)) <= 0) {
915+
fprintf(stderr, "%s: %s\n",
916+
errstr, nret == 0 ? "timed out" : strerror(errno));
917+
return INLINE_IMG_NONE;
918+
}
919+
920+
nchars_read = read(tty, response + len, response_size - len - 1);
921+
if (nchars_read < 0) {
922+
perror(errstr);
923+
return INLINE_IMG_NONE;
924+
}
925+
926+
/* first useful iteration; validate response */
927+
if (nchars_read + len >= 3 && memcmp(response, "\033[?", 3) != 0) {
928+
fputs("Malformed terminal attributes\n", stderr);
929+
return INLINE_IMG_NONE;
930+
}
931+
932+
/* NUL-terminate the terminal response */
933+
{
934+
char *ptr = memchr(response + len, 'c', nchars_read);
935+
if (ptr) {
936+
ptr[1] = '\0';
937+
break;
938+
}
939+
}
940+
941+
/* if we can't find 'c', then the response is incomplete; try again */
942+
len += (size_t)nchars_read;
943+
}
944+
945+
/* separate the response parameters by ';' and look for '4' */
946+
if (response) {
947+
char *ptr = response;
948+
while ((ptr = strchr(ptr, ';'))) {
949+
if (*++ptr != '4')
950+
continue;
951+
switch (*++ptr) {
952+
case ';':
953+
case 'c':
954+
if (have_img2sixel())
955+
return INLINE_IMG_SIXEL;
956+
}
957+
}
958+
} else
959+
perror(errstr);
960+
961+
/* default */
962+
return INLINE_IMG_NONE;
963+
}
964+
859965
int
860966
get_pixel_per_cell(int *ppc, int *ppl)
861967
{

terms.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extern void put_image_osc5379(char *url, int x, int y, int w, int h, int sx, int
3535
extern void put_image_sixel(char *url, int x, int y, int w, int h, int sx, int sy, int sw, int sh, int n_terminal_image);
3636
extern void put_image_iterm2(char *url, int x, int y, int w, int h);
3737
extern void put_image_kitty(char *url, int x, int y, int w, int h, int sx, int sy, int sw, int sh, int c, int r);
38+
extern int img_protocol_test_for_sixel(void);
3839
extern int get_pixel_per_cell(int *ppc, int *ppl);
3940
#endif
4041

0 commit comments

Comments
 (0)