aboutsummaryrefslogtreecommitdiff
path: root/x.c
diff options
context:
space:
mode:
Diffstat (limited to 'x.c')
-rw-r--r--x.c569
1 files changed, 326 insertions, 243 deletions
diff --git a/x.c b/x.c
index d73152b..0366726 100644
--- a/x.c
+++ b/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)
{
@@ -280,16 +194,23 @@ clippaste(const Arg *dummy)
}
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);
@@ -857,6 +801,12 @@ xclear(int x1, int y1, int x2, int y2)
}
void
+xclearwin(void)
+{
+ xclear(0, 0, win.w, win.h);
+}
+
+void
xhints(void)
{
XClassHint class = {opt_name ? opt_name : termname,
@@ -908,6 +858,60 @@ xgeommasktogravity(int mask)
}
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)
{
FcPattern *configured;
@@ -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);