-
-/*
- * Absolute coordinates.
- */
-void
-xclear(int x1, int y1, int x2, int y2) {
-       XftDrawRect(xw.draw,
-                       &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
-                       x1, y1, x2-x1, y2-y1);
-}
-
-void
-xhints(void) {
-       XClassHint class = {opt_class ? opt_class : termname, termname};
-       XWMHints wm = {.flags = InputHint, .input = 1};
-       XSizeHints *sizeh = NULL;
-
-       sizeh = XAllocSizeHints();
-
-       sizeh->flags = PSize | PResizeInc | PBaseSize;
-       sizeh->height = xw.h;
-       sizeh->width = xw.w;
-       sizeh->height_inc = xw.ch;
-       sizeh->width_inc = xw.cw;
-       sizeh->base_height = 2 * borderpx;
-       sizeh->base_width = 2 * borderpx;
-       if(xw.isfixed == True) {
-               sizeh->flags |= PMaxSize | PMinSize;
-               sizeh->min_width = sizeh->max_width = xw.w;
-               sizeh->min_height = sizeh->max_height = xw.h;
-       }
-       if(xw.gm & (XValue|YValue)) {
-               sizeh->flags |= USPosition | PWinGravity;
-               sizeh->x = xw.l;
-               sizeh->y = xw.t;
-               sizeh->win_gravity = xgeommasktogravity(xw.gm);
-       }
-
-       XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
-                       &class);
-       XFree(sizeh);
-}
-
-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;
-       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 {
-               if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
-                               FcResultMatch) {
-                       usedfontsize = fontval;
-               } else if(FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
-                               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);
-}
-
-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.f = usedfontsize + arg->f;
-       xzoomabs(&larg);
-}
-
-void
-xzoomabs(const Arg *arg) {
-       xunloadfonts();
-       xloadfonts(usedfont, arg->f);
-       cresize(0, 0);
-       redraw();
-       xhints();
-}
-
-void
-xzoomreset(const Arg *arg) {
-       Arg larg;
-
-       if(defaultfontsize > 0) {
-               larg.f = 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);
-}
-
-int
-xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
-{
-       float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
-       ushort mode, prevmode = USHRT_MAX;
-       Font *font = &dc.font;
-       int frcflags = FRC_NORMAL;
-       float runewidth = xw.cw;
-       Rune rune;
-       FT_UInt glyphidx;
-       FcResult fcres;
-       FcPattern *fcpattern, *fontpattern;
-       FcFontSet *fcsets[] = { NULL };
-       FcCharSet *fccharset;
-       int i, f, numspecs = 0;
-
-       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;
-
-               /* Skip dummy wide-character spacing. */
-               if(mode == ATTR_WDUMMY)
-                       continue;
-
-               /* Determine font for glyph if different from previous glyph. */
-               if(prevmode != mode) {
-                       prevmode = mode;
-                       font = &dc.font;
-                       frcflags = FRC_NORMAL;
-                       runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
-                       if((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
-                               font = &dc.ibfont;
-                               frcflags = FRC_ITALICBOLD;
-                       } else if(mode & ATTR_ITALIC) {
-                               font = &dc.ifont;
-                               frcflags = FRC_ITALIC;
-                       } else if(mode & ATTR_BOLD) {
-                               font = &dc.bfont;
-                               frcflags = FRC_BOLD;
-                       }
-                       yp = winy + font->ascent;
-               }
-
-               /* Lookup character index with default font. */
-               glyphidx = XftCharIndex(xw.dpy, font->match, rune);
-               if(glyphidx) {
-                       specs[numspecs].font = font->match;
-                       specs[numspecs].glyph = glyphidx;
-                       specs[numspecs].x = (short)xp;
-                       specs[numspecs].y = (short)yp;
-                       xp += runewidth;
-                       numspecs++;
-                       continue;
-               }
-
-               /* Fallback on font cache, search the font cache for match. */
-               for(f = 0; f < frclen; f++) {
-                       glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
-                       /* Everything correct. */
-                       if(glyphidx && frc[f].flags == frcflags)
-                               break;
-                       /* We got a default font for a not found glyph. */
-                       if(!glyphidx && frc[f].flags == frcflags
-                                       && frc[f].unicodep == rune) {
-                               break;
-                       }
-               }
-
-               /* Nothing was found. Use fontconfig to find matching font. */
-               if(f >= frclen) {
-                       if(!font->set)
-                               font->set = FcFontSort(0, font->pattern,
-                                                      FcTrue, 0, &fcres);
-                       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, rune);
-                       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 = rune;
-
-                       glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
-
-                       f = frclen;
-                       frclen++;
-
-                       FcPatternDestroy(fcpattern);
-                       FcCharSetDestroy(fccharset);
-               }
-
-               specs[numspecs].font = frc[f].font;
-               specs[numspecs].glyph = glyphidx;
-               specs[numspecs].x = (short)xp;
-               specs[numspecs].y = (short)(winy + frc[f].font->ascent);
-               xp += runewidth;
-               numspecs++;
-       }
-
-       return numspecs;
-}
-
-void
-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 * xw.cw, winy = borderpx + y * xw.ch,
-           width = charlen * xw.cw;
-       Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-       XRenderColor colfg, colbg;
-       XRectangle r;
-
-       /* Determine foreground and background colors based on mode. */
-       if(base.fg == defaultfg) {
-               if(base.mode & ATTR_ITALIC)
-                       base.fg = defaultitalic;
-               else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
-                       base.fg = defaultitalic;
-               else if(base.mode & ATTR_UNDERLINE)
-                       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];
-       }
-
-       /* 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(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_BOLD_FAINT) == ATTR_FAINT) {
-               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);
-
-       /* Render the glyphs. */
-       XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
-
-       /* Render underline and strikethrough. */
-       if(base.mode & ATTR_UNDERLINE) {
-               XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
-                               width, 1);
-       }
-
-       if(base.mode & ATTR_STRUCK) {
-               XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
-                               width, 1);
-       }
-
-       /* Reset clip to none. */
-       XftDrawSetClip(xw.draw, 0);
-}
-
-void
-xdrawglyph(Glyph g, int x, int y) {
-       int numspecs;
-       XftGlyphFontSpec spec;
-       numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
-       xdrawglyphfontspecs(&spec, g, numspecs, x, y);
-}
-
-void
-xdrawcursor(void) {
-       static int oldx = 0, oldy = 0;
-       int 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--;
-
-       g.u = term.line[term.c.y][term.c.x].u;
-
-       /* remove the old cursor */
-       xdrawglyph(term.line[oldy][oldx], oldx, oldy);
-
-       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;
-                                       }
-
-                               g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
-                               xdrawglyph(g, term.c.x, term.c.y);
-                               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 - cursorthickness,
-                                               xw.cw, cursorthickness);
-                               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,
-                                               cursorthickness, 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 i, x, y, ox, numspecs;
-       Glyph base, new;
-       XftGlyphFontSpec* specs;
-       bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-
-       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;
-
-               specs = term.specbuf;
-               numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
-
-               i = ox = 0;
-               for(x = x1; x < x2 && i < numspecs; x++) {
-                       new = term.line[y][x];
-                       if(new.mode == ATTR_WDUMMY)
-                               continue;
-                       if(ena_sel && selected(x, y))
-                               new.mode ^= ATTR_REVERSE;
-                       if(i > 0 && ATTRCMP(base, new)) {
-                               xdrawglyphfontspecs(specs, base, i, ox, y);
-                               specs += i;
-                               numspecs -= i;
-                               i = 0;
-                       }
-                       if(i == 0) {
-                               ox = x;
-                               base = new;
-                       }
-                       i++;
-               }
-               if(i > 0)
-                       xdrawglyphfontspecs(specs, base, i, ox, y);
-       }
-       xdrawcursor();
-}
-
-void
-expose(XEvent *ev) {
-       redraw();
-}
-
-void
-visibility(XEvent *ev) {
-       XVisibilityEvent *e = &ev->xvisibility;
-
-       MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
-}
-
-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);
-       }
-}
-
-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;
-       Rune 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);
-                       }
-               } 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(0);
-       }
-}
-
-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 */
-       do {
-               XNextEvent(xw.dpy, &ev);
-               /*
-                * XFilterEvent is required to be called after you using XOpenIM,
-                * this is not unnecessary.It does not only filter the key event,
-                * but some clientmessage for input method as well.
-                */
-               if(XFilterEvent(&ev, None))
-                       continue;
-               if(ev.type == ConfigureNotify) {
-                       w = ev.xconfigure.width;
-                       h = ev.xconfigure.height;
-               }
-       } while(ev.type != MapNotify);
-
-       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 * 1E6)/ xfps;
-               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 > 1000 / (xev ? xfps : actionfps)) {
-                       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 ...] [command ...]\n"
-       "       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-       "          [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
-       argv0);
-}
-
-int
-main(int argc, char *argv[]) {
-       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':
-               if(argc > 0)
-                       --argc, ++argv;
-               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 'l':
-               opt_line = EARGF(usage());
-               break;
-       case 't':
-               opt_title = EARGF(usage());
-               break;
-       case 'w':
-               opt_embed = EARGF(usage());
-               break;
-       case 'v':
-       default:
-               usage();
-       } ARGEND;
-
-run:
-       if(argc > 0) {
-               /* eat all remaining arguments */
-               opt_cmd = argv;
-               if(!opt_title && !opt_line)
-                       opt_title = basename(xstrdup(argv[0]));
-       }
-       setlocale(LC_CTYPE, "");
-       XSetLocaleModifiers("");
-       tnew(MAX(cols, 1), MAX(rows, 1));
-       xinit();
-       selinit();
-       run();
-
-       return 0;
-}
-