-
-int
-xgeommasktogravity(int mask) {
- switch(mask & (XNegative|YNegative)) {
- case 0:
- return NorthWestGravity;
- case XNegative:
- return NorthEastGravity;
- case YNegative:
- return SouthWestGravity;
- }
- return SouthEastGravity;
-}
-
-int
-xloadfont(Font *f, FcPattern *pattern) {
- FcPattern *match;
- FcResult result;
-
- match = FcFontMatch(NULL, pattern, &result);
- if(!match)
- return 1;
-
- if(!(f->match = XftFontOpenPattern(xw.dpy, match))) {
- FcPatternDestroy(match);
- return 1;
- }
-
- f->set = NULL;
- f->pattern = FcPatternDuplicate(pattern);
-
- f->ascent = f->match->ascent;
- f->descent = f->match->descent;
- f->lbearing = 0;
- f->rbearing = f->match->max_advance_width;
-
- f->height = f->ascent + f->descent;
- f->width = f->lbearing + f->rbearing;
-
- return 0;
-}
-
-void
-xloadfonts(char *fontstr, double fontsize) {
- FcPattern *pattern;
- FcResult r_sz, r_psz;
- double fontval;
- float ceilf(float);
-
- if(fontstr[0] == '-') {
- pattern = XftXlfdParse(fontstr, False, False);
- } else {
- pattern = FcNameParse((FcChar8 *)fontstr);
- }
-
- if(!pattern)
- die("st: can't open font %s\n", fontstr);
-
- if(fontsize > 1) {
- FcPatternDel(pattern, FC_PIXEL_SIZE);
- FcPatternDel(pattern, FC_SIZE);
- FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
- usedfontsize = fontsize;
- } else {
- r_psz = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval);
- r_sz = FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval);
- if(r_psz == FcResultMatch) {
- usedfontsize = fontval;
- } else if(r_sz == FcResultMatch) {
- usedfontsize = -1;
- } else {
- /*
- * Default font size is 12, if none given. This is to
- * have a known usedfontsize value.
- */
- FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
- usedfontsize = 12;
- }
- defaultfontsize = usedfontsize;
- }
-
- FcConfigSubstitute(0, pattern, FcMatchPattern);
- FcDefaultSubstitute(pattern);
-
- if(xloadfont(&dc.font, pattern))
- die("st: can't open font %s\n", fontstr);
-
- if(usedfontsize < 0) {
- FcPatternGetDouble(dc.font.match->pattern,
- FC_PIXEL_SIZE, 0, &fontval);
- usedfontsize = fontval;
- if(fontsize == 0)
- defaultfontsize = fontval;
- }
-
- /* Setting character width and height. */
- xw.cw = ceilf(dc.font.width * cwscale);
- xw.ch = ceilf(dc.font.height * chscale);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
- if(xloadfont(&dc.ifont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDel(pattern, FC_WEIGHT);
- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
- if(xloadfont(&dc.ibfont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
- if(xloadfont(&dc.bfont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDestroy(pattern);
-}
-
-int
-xloadfontset(Font *f) {
- FcResult result;
-
- if(!(f->set = FcFontSort(0, f->pattern, FcTrue, 0, &result)))
- return 1;
- return 0;
-}
-
-void
-xunloadfont(Font *f) {
- XftFontClose(xw.dpy, f->match);
- FcPatternDestroy(f->pattern);
- if(f->set)
- FcFontSetDestroy(f->set);
-}
-
-void
-xunloadfonts(void) {
- /* Free the loaded fonts in the font cache. */
- while(frclen > 0)
- XftFontClose(xw.dpy, frc[--frclen].font);
-
- xunloadfont(&dc.font);
- xunloadfont(&dc.bfont);
- xunloadfont(&dc.ifont);
- xunloadfont(&dc.ibfont);
-}
-
-void
-xzoom(const Arg *arg) {
- Arg larg;
-
- larg.i = usedfontsize + arg->i;
- xzoomabs(&larg);
-}
-
-void
-xzoomabs(const Arg *arg) {
- xunloadfonts();
- xloadfonts(usedfont, arg->i);
- cresize(0, 0);
- redraw();
- xhints();
-}
-
-void
-xzoomreset(const Arg *arg) {
- Arg larg;
-
- if(defaultfontsize > 0) {
- larg.i = defaultfontsize;
- xzoomabs(&larg);
- }
-}
-
-void
-xinit(void) {
- XGCValues gcvalues;
- Cursor cursor;
- Window parent;
- pid_t thispid = getpid();
-
- if(!(xw.dpy = XOpenDisplay(NULL)))
- die("Can't open display\n");
- xw.scr = XDefaultScreen(xw.dpy);
- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
-
- /* font */
- if(!FcInit())
- die("Could not init fontconfig.\n");
-
- usedfont = (opt_font == NULL)? font : opt_font;
- xloadfonts(usedfont, 0);
-
- /* colors */
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
- xloadcols();
-
- /* adjust fixed window geometry */
- xw.w = 2 * borderpx + term.col * xw.cw;
- xw.h = 2 * borderpx + term.row * xw.ch;
- if(xw.gm & XNegative)
- xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
- if(xw.gm & YNegative)
- xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2;
-
- /* Events */
- xw.attrs.background_pixel = dc.col[defaultbg].pixel;
- xw.attrs.border_pixel = dc.col[defaultbg].pixel;
- xw.attrs.bit_gravity = NorthWestGravity;
- xw.attrs.event_mask = FocusChangeMask | KeyPressMask
- | ExposureMask | VisibilityChangeMask | StructureNotifyMask
- | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
- xw.attrs.colormap = xw.cmap;
-
- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
- parent = XRootWindow(xw.dpy, xw.scr);
- xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
- xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
- xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
- | CWEventMask | CWColormap, &xw.attrs);
-
- memset(&gcvalues, 0, sizeof(gcvalues));
- gcvalues.graphics_exposures = False;
- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
- &gcvalues);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
- DefaultDepth(xw.dpy, xw.scr));
- XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
- XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-
- /* Xft rendering context */
- xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-
- /* input methods */
- if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
- XSetLocaleModifiers("@im=local");
- if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
- XSetLocaleModifiers("@im=");
- if((xw.xim = XOpenIM(xw.dpy,
- NULL, NULL, NULL)) == NULL) {
- die("XOpenIM failed. Could not open input"
- " device.\n");
- }
- }
- }
- xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
- | XIMStatusNothing, XNClientWindow, xw.win,
- XNFocusWindow, xw.win, NULL);
- if(xw.xic == NULL)
- die("XCreateIC failed. Could not obtain input method.\n");
-
- /* white cursor, black outline */
- cursor = XCreateFontCursor(xw.dpy, XC_xterm);
- XDefineCursor(xw.dpy, xw.win, cursor);
- XRecolorCursor(xw.dpy, cursor,
- &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
- &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
-
- xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
- xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
- xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
- XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
-
- xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
- XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
- PropModeReplace, (uchar *)&thispid, 1);
-
- xresettitle();
- XMapWindow(xw.dpy, xw.win);
- xhints();
- XSync(xw.dpy, False);
-}
-
-void
-xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
- int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
- width = charlen * xw.cw, xp, i;
- int frcflags, charexists;
- int u8fl, u8fblen, u8cblen, doesexist;
- char *u8c, *u8fs;
- long unicodep;
- Font *font = &dc.font;
- FcResult fcres;
- FcPattern *fcpattern, *fontpattern;
- FcFontSet *fcsets[] = { NULL };
- FcCharSet *fccharset;
- Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
- XRenderColor colfg, colbg;
- XRectangle r;
- int oneatatime;
-
- frcflags = FRC_NORMAL;
-
- if(base.mode & ATTR_ITALIC) {
- if(base.fg == defaultfg)
- base.fg = defaultitalic;
- font = &dc.ifont;
- frcflags = FRC_ITALIC;
- } else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
- if(base.fg == defaultfg)
- base.fg = defaultitalic;
- font = &dc.ibfont;
- frcflags = FRC_ITALICBOLD;
- } else if(base.mode & ATTR_UNDERLINE) {
- if(base.fg == defaultfg)
- base.fg = defaultunderline;
- }
-
- if(IS_TRUECOL(base.fg)) {
- colfg.alpha = 0xffff;
- colfg.red = TRUERED(base.fg);
- colfg.green = TRUEGREEN(base.fg);
- colfg.blue = TRUEBLUE(base.fg);
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
- fg = &truefg;
- } else {
- fg = &dc.col[base.fg];
- }
-
- if(IS_TRUECOL(base.bg)) {
- colbg.alpha = 0xffff;
- colbg.green = TRUEGREEN(base.bg);
- colbg.red = TRUERED(base.bg);
- colbg.blue = TRUEBLUE(base.bg);
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
- bg = &truebg;
- } else {
- bg = &dc.col[base.bg];
- }
-
- if(base.mode & ATTR_BOLD) {
- /*
- * change basic system colors [0-7]
- * to bright system colors [8-15]
- */
- if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
- fg = &dc.col[base.fg + 8];
-
- if(base.mode & ATTR_ITALIC) {
- font = &dc.ibfont;
- frcflags = FRC_ITALICBOLD;
- } else {
- font = &dc.bfont;
- frcflags = FRC_BOLD;
- }
- }
-
- if(IS_SET(MODE_REVERSE)) {
- if(fg == &dc.col[defaultfg]) {
- fg = &dc.col[defaultbg];
- } else {
- colfg.red = ~fg->color.red;
- colfg.green = ~fg->color.green;
- colfg.blue = ~fg->color.blue;
- colfg.alpha = fg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
- &revfg);
- fg = &revfg;
- }
-
- if(bg == &dc.col[defaultbg]) {
- bg = &dc.col[defaultfg];
- } else {
- colbg.red = ~bg->color.red;
- colbg.green = ~bg->color.green;
- colbg.blue = ~bg->color.blue;
- colbg.alpha = bg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
- &revbg);
- bg = &revbg;
- }
- }
-
- if(base.mode & ATTR_REVERSE) {
- temp = fg;
- fg = bg;
- bg = temp;
- }
-
- if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
- colfg.red = fg->color.red / 2;
- colfg.green = fg->color.green / 2;
- colfg.blue = fg->color.blue / 2;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
- fg = &revfg;
- }
-
- if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
- fg = bg;
-
- if(base.mode & ATTR_INVISIBLE)
- fg = bg;
-
- /* Intelligent cleaning up of the borders. */
- if(x == 0) {
- xclear(0, (y == 0)? 0 : winy, borderpx,
- winy + xw.ch + ((y >= term.row-1)? xw.h : 0));
- }
- if(x + charlen >= term.col) {
- xclear(winx + width, (y == 0)? 0 : winy, xw.w,
- ((y >= term.row-1)? xw.h : (winy + xw.ch)));
- }
- if(y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if(y == term.row-1)
- xclear(winx, winy + xw.ch, winx + width, xw.h);
-
- /* Clean up the region we want to draw to. */
- XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
-
- /* Set the clip region because Xft is sometimes dirty. */
- r.x = 0;
- r.y = 0;
- r.height = xw.ch;
- r.width = width;
- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
-
- for(xp = winx; bytelen > 0;) {
- /*
- * Search for the range in the to be printed string of glyphs
- * that are in the main font. Then print that range. If
- * some glyph is found that is not in the font, do the
- * fallback dance.
- */
- u8fs = s;
- u8fblen = 0;
- u8fl = 0;
- oneatatime = font->width != xw.cw;
- for(;;) {
- u8c = s;
- u8cblen = utf8decode(s, &unicodep, UTF_SIZ);
- s += u8cblen;
- bytelen -= u8cblen;
-
- doesexist = XftCharExists(xw.dpy, font->match, unicodep);
- if(doesexist) {
- u8fl++;
- u8fblen += u8cblen;
- if(!oneatatime && bytelen > 0)
- continue;
- }
-
- if(u8fl > 0) {
- XftDrawStringUtf8(xw.draw, fg,
- font->match, xp,
- winy + font->ascent,
- (FcChar8 *)u8fs,
- u8fblen);
- xp += xw.cw * u8fl;
- }
- break;
- }
- if(doesexist) {
- if(oneatatime)
- continue;
- break;
- }
-
- /* Search the font cache. */
- for(i = 0; i < frclen; i++) {
- charexists = XftCharExists(xw.dpy, frc[i].font, unicodep);
- /* Everything correct. */
- if(charexists && frc[i].flags == frcflags)
- break;
- /* We got a default font for a not found glyph. */
- if(!charexists && frc[i].flags == frcflags \
- && frc[i].unicodep == unicodep) {
- break;
- }
- }
-
- /* Nothing was found. */
- if(i >= frclen) {
- if(!font->set)
- xloadfontset(font);
- fcsets[0] = font->set;
-
- /*
- * Nothing was found in the cache. Now use
- * some dozen of Fontconfig calls to get the
- * font for one single character.
- *
- * Xft and fontconfig are design failures.
- */
- fcpattern = FcPatternDuplicate(font->pattern);
- fccharset = FcCharSetCreate();
-
- FcCharSetAddChar(fccharset, unicodep);
- FcPatternAddCharSet(fcpattern, FC_CHARSET,
- fccharset);
- FcPatternAddBool(fcpattern, FC_SCALABLE,
- FcTrue);
-
- FcConfigSubstitute(0, fcpattern,
- FcMatchPattern);
- FcDefaultSubstitute(fcpattern);
-
- fontpattern = FcFontSetMatch(0, fcsets, 1,
- fcpattern, &fcres);
-
- /*
- * Overwrite or create the new cache entry.
- */
- if(frclen >= LEN(frc)) {
- frclen = LEN(frc) - 1;
- XftFontClose(xw.dpy, frc[frclen].font);
- frc[frclen].unicodep = 0;
- }
-
- frc[frclen].font = XftFontOpenPattern(xw.dpy,
- fontpattern);
- frc[frclen].flags = frcflags;
- frc[frclen].unicodep = unicodep;
-
- i = frclen;
- frclen++;
-
- FcPatternDestroy(fcpattern);
- FcCharSetDestroy(fccharset);
- }
-
- XftDrawStringUtf8(xw.draw, fg, frc[i].font,
- xp, winy + frc[i].font->ascent,
- (FcChar8 *)u8c, u8cblen);
-
- xp += xw.cw * wcwidth(unicodep);
- }
-
- /*
- * This is how the loop above actually should be. Why does the
- * application have to care about font details?
- *
- * I have to repeat: Xft and Fontconfig are design failures.
- */
- /*
- XftDrawStringUtf8(xw.draw, fg, font->set, winx,
- winy + font->ascent, (FcChar8 *)s, bytelen);
- */
-
- if(base.mode & ATTR_UNDERLINE) {
- XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
- width, 1);
- }
-
- if(base.mode & ATTR_STRUCK) {
- XftDrawRect(xw.draw, fg, winx, winy + 2 * font->ascent / 3,
- width, 1);
- }
-
- /* Reset clip to none. */
- XftDrawSetClip(xw.draw, 0);
-}
-
-void
-xdrawcursor(void) {
- static int oldx = 0, oldy = 0;
- int sl, width, curx;
- Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
-
- LIMIT(oldx, 0, term.col-1);
- LIMIT(oldy, 0, term.row-1);
-
- curx = term.c.x;
-
- /* adjust position if in dummy */
- if(term.line[oldy][oldx].mode & ATTR_WDUMMY)
- oldx--;
- if(term.line[term.c.y][curx].mode & ATTR_WDUMMY)
- curx--;
-
- memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
-
- /* remove the old cursor */
- sl = utf8len(term.line[oldy][oldx].c);
- width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;
- xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
- oldy, width, sl);
-
- if(IS_SET(MODE_HIDE))
- return;
-
- /* draw the new one */
- if(xw.state & WIN_FOCUSED) {
- switch (xw.cursor) {
- case 0: /* Blinking Block */
- case 1: /* Blinking Block (Default) */
- case 2: /* Steady Block */
- if(IS_SET(MODE_REVERSE)) {
- g.mode |= ATTR_REVERSE;
- g.fg = defaultcs;
- g.bg = defaultfg;
- }
-
- sl = utf8len(g.c);
- width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
- ? 2 : 1;
- xdraws(g.c, g, term.c.x, term.c.y, width, sl);
- break;
- case 3: /* Blinking Underline */
- case 4: /* Steady Underline */
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + curx * xw.cw,
- borderpx + (term.c.y + 1) * xw.ch - 1,
- xw.cw, 1);
- break;
- case 5: /* Blinking bar */
- case 6: /* Steady bar */
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- 1, xw.ch);
- break;
- }
- } else {
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- xw.cw - 1, 1);
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- 1, xw.ch - 1);
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + (curx + 1) * xw.cw - 1,
- borderpx + term.c.y * xw.ch,
- 1, xw.ch - 1);
- XftDrawRect(xw.draw, &dc.col[defaultcs],
- borderpx + curx * xw.cw,
- borderpx + (term.c.y + 1) * xw.ch - 1,
- xw.cw, 1);
- }
- oldx = curx, oldy = term.c.y;
-}
-
-
-void
-xsettitle(char *p) {
- XTextProperty prop;
-
- Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
- &prop);
- XSetWMName(xw.dpy, xw.win, &prop);
- XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
- XFree(prop.value);
-}
-
-void
-xresettitle(void) {
- xsettitle(opt_title ? opt_title : "st");
-}
-
-void
-redraw(void) {
- tfulldirt();
- draw();
-}
-
-void
-draw(void) {
- drawregion(0, 0, term.col, term.row);
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
- xw.h, 0, 0);
- XSetForeground(xw.dpy, dc.gc,
- dc.col[IS_SET(MODE_REVERSE)?
- defaultfg : defaultbg].pixel);
-}
-
-void
-drawregion(int x1, int y1, int x2, int y2) {
- int ic, ib, x, y, ox, sl;
- Glyph base, new;
- char buf[DRAW_BUF_SIZ];
- bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
- long unicodep;
-
- if(!(xw.state & WIN_VISIBLE))
- return;
-
- for(y = y1; y < y2; y++) {
- if(!term.dirty[y])
- continue;
-
- xtermclear(0, y, term.col, y);
- term.dirty[y] = 0;
- base = term.line[y][0];
- ic = ib = ox = 0;
- for(x = x1; x < x2; x++) {
- new = term.line[y][x];
- if(new.mode == ATTR_WDUMMY)
- continue;
- if(ena_sel && selected(x, y))
- new.mode ^= ATTR_REVERSE;
- if(ib > 0 && (ATTRCMP(base, new)
- || ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
- xdraws(buf, base, ox, y, ic, ib);
- ic = ib = 0;
- }
- if(ib == 0) {
- ox = x;
- base = new;
- }
-
- sl = utf8decode(new.c, &unicodep, UTF_SIZ);
- memcpy(buf+ib, new.c, sl);
- ib += sl;
- ic += (new.mode & ATTR_WIDE)? 2 : 1;
- }
- if(ib > 0)
- xdraws(buf, base, ox, y, ic, ib);
- }
- xdrawcursor();
-}
-
-void
-expose(XEvent *ev) {
- XExposeEvent *e = &ev->xexpose;
-
- if(xw.state & WIN_REDRAW) {
- if(!e->count)
- xw.state &= ~WIN_REDRAW;
- }
- redraw();
-}
-
-void
-visibility(XEvent *ev) {
- XVisibilityEvent *e = &ev->xvisibility;
-
- if(e->state == VisibilityFullyObscured) {
- xw.state &= ~WIN_VISIBLE;
- } else if(!(xw.state & WIN_VISIBLE)) {
- /* need a full redraw for next Expose, not just a buf copy */
- xw.state |= WIN_VISIBLE | WIN_REDRAW;
- }
-}
-
-void
-unmap(XEvent *ev) {
- xw.state &= ~WIN_VISIBLE;
-}
-
-void
-xsetpointermotion(int set) {
- MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
-}
-
-void
-xseturgency(int add) {
- XWMHints *h = XGetWMHints(xw.dpy, xw.win);
-
- MODBIT(h->flags, add, XUrgencyHint);
- XSetWMHints(xw.dpy, xw.win, h);
- XFree(h);
-}
-
-void
-focus(XEvent *ev) {
- XFocusChangeEvent *e = &ev->xfocus;
-
- if(e->mode == NotifyGrab)
- return;
-
- if(ev->type == FocusIn) {
- XSetICFocus(xw.xic);
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- if(IS_SET(MODE_FOCUS))
- ttywrite("\033[I", 3);
- } else {
- XUnsetICFocus(xw.xic);
- xw.state &= ~WIN_FOCUSED;
- if(IS_SET(MODE_FOCUS))
- ttywrite("\033[O", 3);
- }
-}
-
-static inline bool
-match(uint mask, uint state) {
- return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
-}
-
-void
-numlock(const Arg *dummy) {
- term.numlock ^= 1;
-}
-
-char*
-kmap(KeySym k, uint state) {
- Key *kp;
- int i;
-
- /* Check for mapped keys out of X11 function keys. */
- for(i = 0; i < LEN(mappedkeys); i++) {
- if(mappedkeys[i] == k)
- break;
- }
- if(i == LEN(mappedkeys)) {
- if((k & 0xFFFF) < 0xFD00)
- return NULL;
- }
-
- for(kp = key; kp < key + LEN(key); kp++) {
- if(kp->k != k)
- continue;
-
- if(!match(kp->mask, state))
- continue;
-
- if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
- continue;
- if(term.numlock && kp->appkey == 2)
- continue;
-
- if(IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
- continue;
-
- if(IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
- continue;
-
- return kp->s;
- }
-
- return NULL;
-}
-
-void
-kpress(XEvent *ev) {
- XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char buf[32], *customkey;
- int len;
- long c;
- Status status;
- Shortcut *bp;
-
- if(IS_SET(MODE_KBDLOCK))
- return;
-
- len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
- /* 1. shortcuts */
- for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
- if(ksym == bp->keysym && match(bp->mod, e->state)) {
- bp->func(&(bp->arg));
- return;
- }
- }
-
- /* 2. custom keys from config.h */
- if((customkey = kmap(ksym, e->state))) {
- ttysend(customkey, strlen(customkey));
- return;
- }
-
- /* 3. composed string from input method */
- if(len == 0)
- return;
- if(len == 1 && e->state & Mod1Mask) {
- if(IS_SET(MODE_8BIT)) {
- if(*buf < 0177) {
- c = *buf | 0x80;
- len = utf8encode(c, buf, UTF_SIZ);
- }
- } else {
- buf[1] = buf[0];
- buf[0] = '\033';
- len = 2;
- }
- }
- ttysend(buf, len);
-}
-
-
-void
-cmessage(XEvent *e) {
- /*
- * See xembed specs
- * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
- */
- if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
- if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- } else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
- xw.state &= ~WIN_FOCUSED;
- }
- } else if(e->xclient.data.l[0] == xw.wmdeletewin) {
- /* Send SIGHUP to shell */
- kill(pid, SIGHUP);
- exit(EXIT_SUCCESS);
- }
-}
-
-void
-cresize(int width, int height) {
- int col, row;
-
- if(width != 0)
- xw.w = width;
- if(height != 0)
- xw.h = height;
-
- col = (xw.w - 2 * borderpx) / xw.cw;
- row = (xw.h - 2 * borderpx) / xw.ch;
-
- tresize(col, row);
- xresize(col, row);
- ttyresize();
-}
-
-void
-resize(XEvent *e) {
- if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
- return;
-
- cresize(e->xconfigure.width, e->xconfigure.height);
-}
-
-void
-run(void) {
- XEvent ev;
- int w = xw.w, h = xw.h;
- fd_set rfd;
- int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
- struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
- long deltatime;
-
- /* Waiting for window mapping */
- while(1) {
- XNextEvent(xw.dpy, &ev);
- if(XFilterEvent(&ev, None))
- continue;
- if(ev.type == ConfigureNotify) {
- w = ev.xconfigure.width;
- h = ev.xconfigure.height;
- } else if(ev.type == MapNotify) {
- break;
- }
- }
-
- ttynew();
- cresize(w, h);
-
- clock_gettime(CLOCK_MONOTONIC, &last);
- lastblink = last;
-
- for(xev = actionfps;;) {
- FD_ZERO(&rfd);
- FD_SET(cmdfd, &rfd);
- FD_SET(xfd, &rfd);
-
- if(pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
- if(errno == EINTR)
- continue;
- die("select failed: %s\n", strerror(errno));
- }
- if(FD_ISSET(cmdfd, &rfd)) {
- ttyread();
- if(blinktimeout) {
- blinkset = tattrset(ATTR_BLINK);
- if(!blinkset)
- MODBIT(term.mode, 0, MODE_BLINK);
- }
- }
-
- if(FD_ISSET(xfd, &rfd))
- xev = actionfps;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- drawtimeout.tv_sec = 0;
- drawtimeout.tv_nsec = (1000/xfps) * 1E6;
- tv = &drawtimeout;
-
- dodraw = 0;
- if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
- tsetdirtattr(ATTR_BLINK);
- term.mode ^= MODE_BLINK;
- lastblink = now;
- dodraw = 1;
- }
- deltatime = TIMEDIFF(now, last);
- if(deltatime > (xev? (1000/xfps) : (1000/actionfps))
- || deltatime < 0) {
- dodraw = 1;
- last = now;
- }
-
- if(dodraw) {
- while(XPending(xw.dpy)) {
- XNextEvent(xw.dpy, &ev);
- if(XFilterEvent(&ev, None))
- continue;
- if(handler[ev.type])
- (handler[ev.type])(&ev);
- }
-
- draw();
- XFlush(xw.dpy);
-
- if(xev && !FD_ISSET(xfd, &rfd))
- xev--;
- if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
- if(blinkset) {
- if(TIMEDIFF(now, lastblink) \
- > blinktimeout) {
- drawtimeout.tv_nsec = 1000;
- } else {
- drawtimeout.tv_nsec = (1E6 * \
- (blinktimeout - \
- TIMEDIFF(now,
- lastblink)));
- }
- drawtimeout.tv_sec = \
- drawtimeout.tv_nsec / 1E9;
- drawtimeout.tv_nsec %= (long)1E9;
- } else {
- tv = NULL;
- }
- }
- }
- }
-}
-
-void
-usage(void) {
- die("%s " VERSION " (c) 2010-2015 st engineers\n" \
- "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
- " [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
-}
-
-int
-main(int argc, char *argv[]) {
- char *titles;
- uint cols = 80, rows = 24;
-
- xw.l = xw.t = 0;
- xw.isfixed = False;
- xw.cursor = 0;
-
- ARGBEGIN {
- case 'a':
- allowaltscreen = false;
- break;
- case 'c':
- opt_class = EARGF(usage());
- break;
- case 'e':
- /* eat all remaining arguments */
- if(argc > 1) {
- opt_cmd = &argv[1];
- if(argv[1] != NULL && opt_title == NULL) {
- titles = xstrdup(argv[1]);
- opt_title = basename(titles);
- }
- }
- goto run;
- case 'f':
- opt_font = EARGF(usage());
- break;
- case 'g':
- xw.gm = XParseGeometry(EARGF(usage()),
- &xw.l, &xw.t, &cols, &rows);
- break;
- case 'i':
- xw.isfixed = True;
- break;
- case 'o':
- opt_io = EARGF(usage());
- break;
- case 't':
- opt_title = EARGF(usage());
- break;
- case 'w':
- opt_embed = EARGF(usage());
- break;
- case 'v':
- default:
- usage();
- } ARGEND;
-
-run:
- setlocale(LC_CTYPE, "");
- XSetLocaleModifiers("");
- tnew(cols? cols : 1, rows? rows : 1);
- xinit();
- selinit();
- run();
-
- return 0;
-}
-