Add sixel support
Originated from https://gist.github.com/CommandMaker/27ba97427424c06aff54d0a2a91a4ef1
This commit is contained in:
569
x.c
569
x.c
@@ -20,30 +20,8 @@ char *argv0;
|
||||
#include "st.h"
|
||||
#include "win.h"
|
||||
|
||||
/* types used in config.h */
|
||||
typedef struct {
|
||||
uint mod;
|
||||
KeySym keysym;
|
||||
void (*func)(const Arg *);
|
||||
const Arg arg;
|
||||
} Shortcut;
|
||||
|
||||
typedef struct {
|
||||
uint mod;
|
||||
uint button;
|
||||
void (*func)(const Arg *);
|
||||
const Arg arg;
|
||||
uint release;
|
||||
} MouseShortcut;
|
||||
|
||||
typedef struct {
|
||||
KeySym k;
|
||||
uint mask;
|
||||
char *s;
|
||||
/* three-valued logic variables: 0 indifferent, 1 on, -1 off */
|
||||
signed char appkey; /* application keypad */
|
||||
signed char appcursor; /* application cursor */
|
||||
} Key;
|
||||
#include <Imlib2.h>
|
||||
#include "sixel.h"
|
||||
|
||||
/* X modifiers */
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
@@ -55,10 +33,11 @@ static void clipcopy(const Arg *);
|
||||
static void clippaste(const Arg *);
|
||||
static void numlock(const Arg *);
|
||||
static void selpaste(const Arg *);
|
||||
static void ttysend(const Arg *);
|
||||
static void zoom(const Arg *);
|
||||
static void zoomabs(const Arg *);
|
||||
static void zoomreset(const Arg *);
|
||||
static void ttysend(const Arg *);
|
||||
|
||||
|
||||
/* config.h for applying patches and the configuration. */
|
||||
#include "config.h"
|
||||
@@ -73,77 +52,10 @@ static void ttysend(const Arg *);
|
||||
#define TRUEGREEN(x) (((x) & 0xff00))
|
||||
#define TRUEBLUE(x) (((x) & 0xff) << 8)
|
||||
|
||||
typedef XftDraw *Draw;
|
||||
typedef XftColor Color;
|
||||
typedef XftGlyphFontSpec GlyphFontSpec;
|
||||
|
||||
/* Purely graphic info */
|
||||
typedef struct {
|
||||
int tw, th; /* tty width and height */
|
||||
int w, h; /* window width and height */
|
||||
int ch; /* char height */
|
||||
int cw; /* char width */
|
||||
int mode; /* window state/mode flags */
|
||||
int cursor; /* cursor style */
|
||||
} TermWindow;
|
||||
|
||||
typedef struct {
|
||||
Display *dpy;
|
||||
Colormap cmap;
|
||||
Window win;
|
||||
Drawable buf;
|
||||
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
|
||||
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
|
||||
struct {
|
||||
XIM xim;
|
||||
XIC xic;
|
||||
XPoint spot;
|
||||
XVaNestedList spotlist;
|
||||
} ime;
|
||||
Draw draw;
|
||||
Visual *vis;
|
||||
XSetWindowAttributes attrs;
|
||||
int scr;
|
||||
int isfixed; /* is fixed geometry? */
|
||||
int l, t; /* left and top offset */
|
||||
int gm; /* geometry mask */
|
||||
} XWindow;
|
||||
|
||||
typedef struct {
|
||||
Atom xtarget;
|
||||
char *primary, *clipboard;
|
||||
struct timespec tclick1;
|
||||
struct timespec tclick2;
|
||||
} XSelection;
|
||||
|
||||
/* Font structure */
|
||||
#define Font Font_
|
||||
typedef struct {
|
||||
int height;
|
||||
int width;
|
||||
int ascent;
|
||||
int descent;
|
||||
int badslant;
|
||||
int badweight;
|
||||
short lbearing;
|
||||
short rbearing;
|
||||
XftFont *match;
|
||||
FcFontSet *set;
|
||||
FcPattern *pattern;
|
||||
} Font;
|
||||
|
||||
/* Drawing Context */
|
||||
typedef struct {
|
||||
Color *col;
|
||||
size_t collen;
|
||||
Font font, bfont, ifont, ibfont;
|
||||
GC gc;
|
||||
} DC;
|
||||
|
||||
static inline ushort sixd_to_16bit(int);
|
||||
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
||||
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
|
||||
static void xdrawglyph(Glyph, int, int);
|
||||
void xdrawglyph(Glyph, int, int);
|
||||
static void xclear(int, int, int, int);
|
||||
static int xgeommasktogravity(int);
|
||||
static int ximopen(Display *);
|
||||
@@ -172,7 +84,6 @@ static void cmessage(XEvent *);
|
||||
static void resize(XEvent *);
|
||||
static void focus(XEvent *);
|
||||
static uint buttonmask(uint);
|
||||
static int mouseaction(XEvent *, uint);
|
||||
static void brelease(XEvent *);
|
||||
static void bpress(XEvent *);
|
||||
static void bmotion(XEvent *);
|
||||
@@ -181,6 +92,7 @@ static void selnotify(XEvent *);
|
||||
static void selclear_(XEvent *);
|
||||
static void selrequest(XEvent *);
|
||||
static void setsel(char *, Time);
|
||||
static int mouseaction(XEvent *, uint);
|
||||
static void mousesel(XEvent *, int);
|
||||
static void mousereport(XEvent *);
|
||||
static char *kmap(KeySym, uint);
|
||||
@@ -216,10 +128,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
|
||||
};
|
||||
|
||||
/* Globals */
|
||||
static DC dc;
|
||||
static XWindow xw;
|
||||
static XSelection xsel;
|
||||
static TermWindow win;
|
||||
Term term;
|
||||
DC dc;
|
||||
XWindow xw;
|
||||
XSelection xsel;
|
||||
TermWindow win;
|
||||
|
||||
/* Font Ring Cache */
|
||||
enum {
|
||||
@@ -254,6 +167,7 @@ static char *opt_title = NULL;
|
||||
|
||||
static uint buttons; /* bit field of pressed buttons */
|
||||
|
||||
|
||||
void
|
||||
clipcopy(const Arg *dummy)
|
||||
{
|
||||
@@ -279,17 +193,24 @@ clippaste(const Arg *dummy)
|
||||
xw.win, CurrentTime);
|
||||
}
|
||||
|
||||
void
|
||||
numlock(const Arg *dummy)
|
||||
{
|
||||
win.mode ^= MODE_NUMLOCK;
|
||||
}
|
||||
|
||||
void
|
||||
selpaste(const Arg *dummy)
|
||||
{
|
||||
|
||||
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
||||
xw.win, CurrentTime);
|
||||
}
|
||||
|
||||
void
|
||||
numlock(const Arg *dummy)
|
||||
ttysend(const Arg *arg)
|
||||
{
|
||||
win.mode ^= MODE_NUMLOCK;
|
||||
ttywrite(arg->s, strlen(arg->s), 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -298,14 +219,31 @@ zoom(const Arg *arg)
|
||||
Arg larg;
|
||||
|
||||
larg.f = usedfontsize + arg->f;
|
||||
zoomabs(&larg);
|
||||
if (larg.f >= 1.0)
|
||||
zoomabs(&larg);
|
||||
}
|
||||
|
||||
void
|
||||
zoomabs(const Arg *arg)
|
||||
{
|
||||
int i;
|
||||
ImageList *im;
|
||||
|
||||
xunloadfonts();
|
||||
xloadfonts(usedfont, arg->f);
|
||||
|
||||
/* delete old pixmaps so that xfinishdraw() can create new scaled ones */
|
||||
for (im = term.images, i = 0; i < 2; i++, im = term.images_alt) {
|
||||
for (; im; im = im->next) {
|
||||
if (im->pixmap)
|
||||
XFreePixmap(xw.dpy, (Drawable)im->pixmap);
|
||||
if (im->clipmask)
|
||||
XFreePixmap(xw.dpy, (Drawable)im->clipmask);
|
||||
im->pixmap = NULL;
|
||||
im->clipmask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cresize(0, 0);
|
||||
redraw();
|
||||
xhints();
|
||||
@@ -322,12 +260,6 @@ zoomreset(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ttysend(const Arg *arg)
|
||||
{
|
||||
ttywrite(arg->s, strlen(arg->s), 1);
|
||||
}
|
||||
|
||||
int
|
||||
evcol(XEvent *e)
|
||||
{
|
||||
@@ -344,6 +276,40 @@ evrow(XEvent *e)
|
||||
return y / win.ch;
|
||||
}
|
||||
|
||||
uint
|
||||
buttonmask(uint button)
|
||||
{
|
||||
return button == Button1 ? Button1Mask
|
||||
: button == Button2 ? Button2Mask
|
||||
: button == Button3 ? Button3Mask
|
||||
: button == Button4 ? Button4Mask
|
||||
: button == Button5 ? Button5Mask
|
||||
: 0;
|
||||
}
|
||||
|
||||
int
|
||||
mouseaction(XEvent *e, uint release)
|
||||
{
|
||||
MouseShortcut *ms;
|
||||
int screen = tisaltscr() ? S_ALT : S_PRI;
|
||||
|
||||
/* ignore Button<N>mask for Button<N> - it's set on release */
|
||||
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
|
||||
|
||||
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
||||
if (ms->release == release &&
|
||||
ms->button == e->xbutton.button &&
|
||||
(!ms->screen || (ms->screen == screen)) &&
|
||||
(match(ms->mod, state) || /* exact or forced */
|
||||
match(ms->mod, state & ~forcemousemod))) {
|
||||
ms->func(&(ms->arg));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mousesel(XEvent *e, int done)
|
||||
{
|
||||
@@ -378,6 +344,7 @@ mousereport(XEvent *e)
|
||||
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
|
||||
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
|
||||
return;
|
||||
|
||||
/* Set btn to lowest-numbered pressed button, or 12 if no
|
||||
* buttons are pressed. */
|
||||
for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
|
||||
@@ -433,38 +400,6 @@ mousereport(XEvent *e)
|
||||
ttywrite(buf, len, 0);
|
||||
}
|
||||
|
||||
uint
|
||||
buttonmask(uint button)
|
||||
{
|
||||
return button == Button1 ? Button1Mask
|
||||
: button == Button2 ? Button2Mask
|
||||
: button == Button3 ? Button3Mask
|
||||
: button == Button4 ? Button4Mask
|
||||
: button == Button5 ? Button5Mask
|
||||
: 0;
|
||||
}
|
||||
|
||||
int
|
||||
mouseaction(XEvent *e, uint release)
|
||||
{
|
||||
MouseShortcut *ms;
|
||||
|
||||
/* ignore Button<N>mask for Button<N> - it's set on release */
|
||||
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
|
||||
|
||||
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
||||
if (ms->release == release &&
|
||||
ms->button == e->xbutton.button &&
|
||||
(match(ms->mod, state) || /* exact or forced */
|
||||
match(ms->mod, state & ~forcemousemod))) {
|
||||
ms->func(&(ms->arg));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bpress(XEvent *e)
|
||||
{
|
||||
@@ -500,6 +435,7 @@ bpress(XEvent *e)
|
||||
xsel.tclick1 = now;
|
||||
|
||||
selstart(evcol(e), evrow(e), snap);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,6 +451,7 @@ propnotify(XEvent *e)
|
||||
xpev->atom == clipboard)) {
|
||||
selnotify(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -545,7 +482,8 @@ selnotify(XEvent *e)
|
||||
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
|
||||
* this is the signal of the selection owner that all
|
||||
@@ -686,6 +624,7 @@ setsel(char *str, Time t)
|
||||
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
|
||||
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
|
||||
selclear();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -709,13 +648,17 @@ brelease(XEvent *e)
|
||||
|
||||
if (mouseaction(e, 1))
|
||||
return;
|
||||
if (btn == Button1)
|
||||
|
||||
if (btn == Button1) {
|
||||
mousesel(e, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
bmotion(XEvent *e)
|
||||
{
|
||||
|
||||
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
|
||||
mousereport(e);
|
||||
return;
|
||||
@@ -736,7 +679,7 @@ cresize(int width, int height)
|
||||
|
||||
col = (win.w - 2 * borderpx) / win.cw;
|
||||
row = (win.h - 2 * borderpx) / win.ch;
|
||||
col = MAX(1, col);
|
||||
col = MAX(2, col);
|
||||
row = MAX(1, row);
|
||||
|
||||
tresize(col, row);
|
||||
@@ -752,7 +695,8 @@ xresize(int col, int row)
|
||||
|
||||
XFreePixmap(xw.dpy, xw.buf);
|
||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
DefaultDepth(xw.dpy, xw.scr));
|
||||
DefaultDepth(xw.dpy, xw.scr)
|
||||
);
|
||||
XftDrawChange(xw.draw, xw.buf);
|
||||
xclear(0, 0, win.w, win.h);
|
||||
|
||||
@@ -856,6 +800,12 @@ xclear(int x1, int y1, int x2, int y2)
|
||||
x1, y1, x2-x1, y2-y1);
|
||||
}
|
||||
|
||||
void
|
||||
xclearwin(void)
|
||||
{
|
||||
xclear(0, 0, win.w, win.h);
|
||||
}
|
||||
|
||||
void
|
||||
xhints(void)
|
||||
{
|
||||
@@ -907,6 +857,60 @@ xgeommasktogravity(int mask)
|
||||
return SouthEastGravity;
|
||||
}
|
||||
|
||||
int
|
||||
ximopen(Display *dpy)
|
||||
{
|
||||
XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
|
||||
XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
|
||||
|
||||
xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
|
||||
if (xw.ime.xim == NULL)
|
||||
return 0;
|
||||
|
||||
if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
|
||||
fprintf(stderr, "XSetIMValues: "
|
||||
"Could not set XNDestroyCallback.\n");
|
||||
|
||||
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
|
||||
NULL);
|
||||
|
||||
if (xw.ime.xic == NULL) {
|
||||
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
|
||||
XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, xw.win,
|
||||
XNDestroyCallback, &icdestroy,
|
||||
NULL);
|
||||
}
|
||||
if (xw.ime.xic == NULL)
|
||||
fprintf(stderr, "XCreateIC: Could not create input context.\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ximinstantiate(Display *dpy, XPointer client, XPointer call)
|
||||
{
|
||||
if (ximopen(dpy))
|
||||
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ximdestroy(XIM xim, XPointer client, XPointer call)
|
||||
{
|
||||
xw.ime.xim = NULL;
|
||||
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
XFree(xw.ime.spotlist);
|
||||
}
|
||||
|
||||
int
|
||||
xicdestroy(XIC xim, XPointer client, XPointer call)
|
||||
{
|
||||
xw.ime.xic = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
xloadfont(Font *f, FcPattern *pattern)
|
||||
{
|
||||
@@ -1062,6 +1066,7 @@ xunloadfont(Font *f)
|
||||
void
|
||||
xunloadfonts(void)
|
||||
{
|
||||
|
||||
/* Free the loaded fonts in the font cache. */
|
||||
while (frclen > 0)
|
||||
XftFontClose(xw.dpy, frc[--frclen].font);
|
||||
@@ -1072,60 +1077,6 @@ xunloadfonts(void)
|
||||
xunloadfont(&dc.ibfont);
|
||||
}
|
||||
|
||||
int
|
||||
ximopen(Display *dpy)
|
||||
{
|
||||
XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
|
||||
XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
|
||||
|
||||
xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
|
||||
if (xw.ime.xim == NULL)
|
||||
return 0;
|
||||
|
||||
if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
|
||||
fprintf(stderr, "XSetIMValues: "
|
||||
"Could not set XNDestroyCallback.\n");
|
||||
|
||||
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
|
||||
NULL);
|
||||
|
||||
if (xw.ime.xic == NULL) {
|
||||
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
|
||||
XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, xw.win,
|
||||
XNDestroyCallback, &icdestroy,
|
||||
NULL);
|
||||
}
|
||||
if (xw.ime.xic == NULL)
|
||||
fprintf(stderr, "XCreateIC: Could not create input context.\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ximinstantiate(Display *dpy, XPointer client, XPointer call)
|
||||
{
|
||||
if (ximopen(dpy))
|
||||
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ximdestroy(XIM xim, XPointer client, XPointer call)
|
||||
{
|
||||
xw.ime.xim = NULL;
|
||||
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
XFree(xw.ime.spotlist);
|
||||
}
|
||||
|
||||
int
|
||||
xicdestroy(XIC xim, XPointer client, XPointer call)
|
||||
{
|
||||
xw.ime.xic = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
xinit(int cols, int rows)
|
||||
{
|
||||
@@ -1138,6 +1089,7 @@ xinit(int cols, int rows)
|
||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("can't open display\n");
|
||||
xw.scr = XDefaultScreen(xw.dpy);
|
||||
|
||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
|
||||
/* font */
|
||||
@@ -1165,7 +1117,8 @@ xinit(int cols, int rows)
|
||||
xw.attrs.bit_gravity = NorthWestGravity;
|
||||
xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
|
||||
| ExposureMask | VisibilityChangeMask | StructureNotifyMask
|
||||
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
|
||||
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
|
||||
;
|
||||
xw.attrs.colormap = xw.cmap;
|
||||
|
||||
root = XRootWindow(xw.dpy, xw.scr);
|
||||
@@ -1180,6 +1133,7 @@ xinit(int cols, int rows)
|
||||
|
||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||
gcvalues.graphics_exposures = False;
|
||||
|
||||
dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
|
||||
&gcvalues);
|
||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
@@ -1196,7 +1150,7 @@ xinit(int cols, int rows)
|
||||
/* input methods */
|
||||
if (!ximopen(xw.dpy)) {
|
||||
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
ximinstantiate, NULL);
|
||||
}
|
||||
|
||||
/* white cursor, black outline */
|
||||
@@ -1240,6 +1194,7 @@ xinit(int cols, int rows)
|
||||
xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
|
||||
if (xsel.xtarget == None)
|
||||
xsel.xtarget = XA_STRING;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1249,7 +1204,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
ushort mode, prevmode = USHRT_MAX;
|
||||
Font *font = &dc.font;
|
||||
int frcflags = FRC_NORMAL;
|
||||
float runewidth = win.cw;
|
||||
float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
|
||||
Rune rune;
|
||||
FT_UInt glyphidx;
|
||||
FcResult fcres;
|
||||
@@ -1258,7 +1213,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
FcCharSet *fccharset;
|
||||
int i, f, numspecs = 0;
|
||||
|
||||
for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
|
||||
for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i)
|
||||
{
|
||||
/* Fetch rune and mode for current glyph. */
|
||||
rune = glyphs[i].u;
|
||||
mode = glyphs[i].mode;
|
||||
@@ -1314,8 +1270,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
/* Nothing was found. Use fontconfig to find matching font. */
|
||||
if (f >= frclen) {
|
||||
if (!font->set)
|
||||
font->set = FcFontSort(0, font->pattern,
|
||||
1, 0, &fcres);
|
||||
font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
|
||||
fcsets[0] = font->set;
|
||||
|
||||
/*
|
||||
@@ -1329,16 +1284,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
fccharset = FcCharSetCreate();
|
||||
|
||||
FcCharSetAddChar(fccharset, rune);
|
||||
FcPatternAddCharSet(fcpattern, FC_CHARSET,
|
||||
fccharset);
|
||||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
|
||||
|
||||
FcConfigSubstitute(0, fcpattern,
|
||||
FcMatchPattern);
|
||||
FcConfigSubstitute(0, fcpattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(fcpattern);
|
||||
|
||||
fontpattern = FcFontSetMatch(0, fcsets, 1,
|
||||
fcpattern, &fcres);
|
||||
fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
|
||||
|
||||
/* Allocate memory for the new cache entry. */
|
||||
if (frclen >= frccap) {
|
||||
@@ -1346,8 +1298,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
frc = xrealloc(frc, frccap * sizeof(Fontcache));
|
||||
}
|
||||
|
||||
frc[frclen].font = XftFontOpenPattern(xw.dpy,
|
||||
fontpattern);
|
||||
frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
|
||||
if (!frc[frclen].font)
|
||||
die("XftFontOpenPattern failed seeking fallback font: %s\n",
|
||||
strerror(errno));
|
||||
@@ -1375,11 +1326,11 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
}
|
||||
|
||||
void
|
||||
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
|
||||
{
|
||||
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y
|
||||
) {
|
||||
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
|
||||
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
|
||||
width = charlen * win.cw;
|
||||
int width = charlen * win.cw;
|
||||
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch;
|
||||
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
||||
XRenderColor colfg, colbg;
|
||||
XRectangle r;
|
||||
@@ -1482,6 +1433,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
||||
xclear(winx, winy + win.ch, winx + width, win.h);
|
||||
|
||||
/* Clean up the region we want to draw to. */
|
||||
|
||||
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
|
||||
|
||||
/* Set the clip region because Xft is sometimes dirty. */
|
||||
@@ -1513,10 +1465,11 @@ void
|
||||
xdrawglyph(Glyph g, int x, int y)
|
||||
{
|
||||
int numspecs;
|
||||
XftGlyphFontSpec spec;
|
||||
XftGlyphFontSpec *specs = xw.specbuf;
|
||||
|
||||
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
|
||||
xdrawglyphfontspecs(&spec, g, numspecs, x, y);
|
||||
numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y);
|
||||
xdrawglyphfontspecs(specs, g, numspecs, x, y
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1527,6 +1480,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
/* remove the old cursor */
|
||||
if (selected(ox, oy))
|
||||
og.mode ^= ATTR_REVERSE;
|
||||
|
||||
xdrawglyph(og, ox, oy);
|
||||
|
||||
if (IS_SET(MODE_HIDE))
|
||||
@@ -1535,7 +1489,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
/*
|
||||
* Select the right color for the right mode.
|
||||
*/
|
||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
|
||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE
|
||||
;
|
||||
|
||||
if (IS_SET(MODE_REVERSE)) {
|
||||
g.mode |= ATTR_REVERSE;
|
||||
@@ -1555,6 +1510,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
g.fg = defaultbg;
|
||||
g.bg = defaultcs;
|
||||
}
|
||||
|
||||
drawcol = dc.col[g.bg];
|
||||
}
|
||||
|
||||
@@ -1564,13 +1520,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
case 7: /* st extension */
|
||||
g.u = 0x2603; /* snowman (U+2603) */
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Blinking Block */
|
||||
case 1: /* Blinking Block (Default) */
|
||||
case 2: /* Steady Block */
|
||||
case 0: /* Blinking block */
|
||||
case 1: /* Blinking block (default) */
|
||||
case 2: /* Steady block */
|
||||
xdrawglyph(g, cx, cy);
|
||||
break;
|
||||
case 3: /* Blinking Underline */
|
||||
case 4: /* Steady Underline */
|
||||
case 3: /* Blinking underline */
|
||||
case 4: /* Steady underline */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + (cy + 1) * win.ch - \
|
||||
@@ -1624,7 +1580,7 @@ xseticontitle(char *p)
|
||||
p = opt_title;
|
||||
|
||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop) != Success)
|
||||
&prop) != Success)
|
||||
return;
|
||||
XSetWMIconName(xw.dpy, xw.win, &prop);
|
||||
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
|
||||
@@ -1641,7 +1597,7 @@ xsettitle(char *p)
|
||||
p = opt_title;
|
||||
|
||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop) != Success)
|
||||
&prop) != Success)
|
||||
return;
|
||||
XSetWMName(xw.dpy, xw.win, &prop);
|
||||
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
|
||||
@@ -1659,6 +1615,7 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||
{
|
||||
int i, x, ox, numspecs;
|
||||
Glyph base, new;
|
||||
|
||||
XftGlyphFontSpec *specs = xw.specbuf;
|
||||
|
||||
numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
|
||||
@@ -1683,16 +1640,132 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||
}
|
||||
if (i > 0)
|
||||
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
xfinishdraw(void)
|
||||
{
|
||||
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
|
||||
win.h, 0, 0);
|
||||
XSetForeground(xw.dpy, dc.gc,
|
||||
dc.col[IS_SET(MODE_REVERSE)?
|
||||
defaultfg : defaultbg].pixel);
|
||||
ImageList *im, *next;
|
||||
Imlib_Image origin, scaled;
|
||||
XGCValues gcvalues;
|
||||
GC gc = NULL;
|
||||
int width, height;
|
||||
int del, desty, mode, x1, x2, xend;
|
||||
int bw = borderpx, bh = borderpx;
|
||||
Line line;
|
||||
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
|
||||
/* do not draw or process the image, if it is not visible */
|
||||
if (im->x >= term.col || im->y >= term.row || im->y < 0)
|
||||
continue;
|
||||
|
||||
/* scale the image */
|
||||
width = MAX(im->width * win.cw / im->cw, 1);
|
||||
height = MAX(im->height * win.ch / im->ch, 1);
|
||||
if (!im->pixmap) {
|
||||
im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, width, height,
|
||||
DefaultDepth(xw.dpy, xw.scr)
|
||||
);
|
||||
if (!im->pixmap)
|
||||
continue;
|
||||
if (win.cw == im->cw && win.ch == im->ch) {
|
||||
XImage ximage = {
|
||||
.format = ZPixmap,
|
||||
.data = (char *)im->pixels,
|
||||
.width = im->width,
|
||||
.height = im->height,
|
||||
.xoffset = 0,
|
||||
.byte_order = sixelbyteorder,
|
||||
.bitmap_bit_order = MSBFirst,
|
||||
.bits_per_pixel = 32,
|
||||
.bytes_per_line = im->width * 4,
|
||||
.bitmap_unit = 32,
|
||||
.bitmap_pad = 32,
|
||||
.depth = 24
|
||||
};
|
||||
XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
|
||||
if (im->transparent)
|
||||
im->clipmask = (void *)sixel_create_clipmask((char *)im->pixels, width, height);
|
||||
} else {
|
||||
origin = imlib_create_image_using_data(im->width, im->height, (DATA32 *)im->pixels);
|
||||
if (!origin)
|
||||
continue;
|
||||
imlib_context_set_image(origin);
|
||||
imlib_image_set_has_alpha(1);
|
||||
imlib_context_set_anti_alias(im->transparent ? 0 : 1); /* anti-aliasing messes up the clip mask */
|
||||
scaled = imlib_create_cropped_scaled_image(0, 0, im->width, im->height, width, height);
|
||||
imlib_free_image_and_decache();
|
||||
if (!scaled)
|
||||
continue;
|
||||
imlib_context_set_image(scaled);
|
||||
imlib_image_set_has_alpha(1);
|
||||
XImage ximage = {
|
||||
.format = ZPixmap,
|
||||
.data = (char *)imlib_image_get_data_for_reading_only(),
|
||||
.width = width,
|
||||
.height = height,
|
||||
.xoffset = 0,
|
||||
.byte_order = sixelbyteorder,
|
||||
.bitmap_bit_order = MSBFirst,
|
||||
.bits_per_pixel = 32,
|
||||
.bytes_per_line = width * 4,
|
||||
.bitmap_unit = 32,
|
||||
.bitmap_pad = 32,
|
||||
.depth = 24
|
||||
};
|
||||
XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
|
||||
if (im->transparent)
|
||||
im->clipmask = (void *)sixel_create_clipmask((char *)imlib_image_get_data_for_reading_only(), width, height);
|
||||
imlib_free_image_and_decache();
|
||||
}
|
||||
}
|
||||
|
||||
/* create GC */
|
||||
if (!gc) {
|
||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||
gcvalues.graphics_exposures = False;
|
||||
gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues);
|
||||
}
|
||||
|
||||
/* set the clip mask */
|
||||
desty = bh + im->y * win.ch;
|
||||
if (im->clipmask) {
|
||||
XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask);
|
||||
XSetClipOrigin(xw.dpy, gc, bw + im->x * win.cw, desty);
|
||||
}
|
||||
|
||||
/* draw only the parts of the image that are not erased */
|
||||
line = term.line[im->y] + im->x;
|
||||
xend = MIN(im->x + im->cols, term.col);
|
||||
for (del = 1, x1 = im->x; x1 < xend; x1 = x2) {
|
||||
mode = line->mode & ATTR_SIXEL;
|
||||
for (x2 = x1 + 1; x2 < xend; x2++) {
|
||||
if (((++line)->mode & ATTR_SIXEL) != mode)
|
||||
break;
|
||||
}
|
||||
if (mode) {
|
||||
XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc,
|
||||
(x1 - im->x) * win.cw, 0,
|
||||
MIN((x2 - x1) * win.cw, width - (x1 - im->x) * win.cw), height,
|
||||
bw + x1 * win.cw, desty);
|
||||
del = 0;
|
||||
}
|
||||
}
|
||||
if (im->clipmask)
|
||||
XSetClipMask(xw.dpy, gc, None);
|
||||
|
||||
/* if all the parts are erased, we can delete the entire image */
|
||||
if (del && im->x + im->cols <= term.col)
|
||||
delete_image(im);
|
||||
}
|
||||
if (gc)
|
||||
XFreeGC(xw.dpy, gc);
|
||||
|
||||
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
||||
XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1844,7 +1917,7 @@ kpress(XEvent *ev)
|
||||
XKeyEvent *e = &ev->xkey;
|
||||
KeySym ksym = NoSymbol;
|
||||
char buf[64], *customkey;
|
||||
int len;
|
||||
int len, screen;
|
||||
Rune c;
|
||||
Status status;
|
||||
Shortcut *bp;
|
||||
@@ -1859,9 +1932,13 @@ kpress(XEvent *ev)
|
||||
} else {
|
||||
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
||||
}
|
||||
|
||||
screen = tisaltscr() ? S_ALT : S_PRI;
|
||||
|
||||
/* 1. shortcuts */
|
||||
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
||||
if (ksym == bp->keysym && match(bp->mod, e->state)) {
|
||||
if (ksym == bp->keysym && match(bp->mod, e->state) &&
|
||||
(!bp->screen || bp->screen == screen)) {
|
||||
bp->func(&(bp->arg));
|
||||
return;
|
||||
}
|
||||
@@ -1914,6 +1991,7 @@ cmessage(XEvent *e)
|
||||
void
|
||||
resize(XEvent *e)
|
||||
{
|
||||
|
||||
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
|
||||
return;
|
||||
|
||||
@@ -1992,7 +2070,8 @@ run(void)
|
||||
* maximum latency intervals during `cat huge.txt`, and perfect
|
||||
* sync with periodic updates from animations/key-repeats/etc.
|
||||
*/
|
||||
if (FD_ISSET(ttyfd, &rfd) || xev) {
|
||||
if (FD_ISSET(ttyfd, &rfd) || xev)
|
||||
{
|
||||
if (!drawing) {
|
||||
trigger = now;
|
||||
drawing = 1;
|
||||
@@ -2005,7 +2084,8 @@ run(void)
|
||||
|
||||
/* idle detected or maxlatency exhausted -> draw */
|
||||
timeout = -1;
|
||||
if (blinktimeout && tattrset(ATTR_BLINK)) {
|
||||
if (blinktimeout && tattrset(ATTR_BLINK))
|
||||
{
|
||||
timeout = blinktimeout - TIMEDIFF(now, lastblink);
|
||||
if (timeout <= 0) {
|
||||
if (-timeout > blinktimeout) /* start visible */
|
||||
@@ -2026,14 +2106,16 @@ run(void)
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
|
||||
" [-n name] [-o file]\n"
|
||||
" [-T title] [-t title] [-w windowid]"
|
||||
" [[-e] command [args ...]]\n"
|
||||
" %s [-aiv] [-c class] [-f font] [-g geometry]"
|
||||
" [-n name] [-o file]\n"
|
||||
" [-T title] [-t title] [-w windowid] -l line"
|
||||
" [stty_args ...]\n", argv0, argv0);
|
||||
die("usage: %s [-aiv] [-c class]"
|
||||
" [-f font] [-g geometry]"
|
||||
" [-n name] [-o file]\n"
|
||||
" [-T title] [-t title] [-w windowid]"
|
||||
" [[-e] command [args ...]]\n"
|
||||
" %s [-aiv] [-c class]"
|
||||
" [-f font] [-g geometry]"
|
||||
" [-n name] [-o file]\n"
|
||||
" [-T title] [-t title] [-w windowid] -l line"
|
||||
" [stty_args ...]\n", argv0, argv0);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -2096,6 +2178,7 @@ run:
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
XSetLocaleModifiers("");
|
||||
|
||||
cols = MAX(cols, 1);
|
||||
rows = MAX(rows, 1);
|
||||
tnew(cols, rows);
|
||||
|
Reference in New Issue
Block a user