aboutsummaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
authorChristoph Lohmann <20h@r-36.net>2012-12-28 23:52:04 +0100
committerChristoph Lohmann <20h@r-36.net>2012-12-28 23:52:04 +0100
commit9c44229c626ea7351a7809540435f40cffb624bc (patch)
tree5f2e5cec411b3974230e125aa1669d1b42674317 /st.c
parent082bab29f3551e5cee332832ff767c3fb65a5cbc (diff)
downloadst-9c44229c626ea7351a7809540435f40cffb624bc.tar.gz
st-9c44229c626ea7351a7809540435f40cffb624bc.zip
Adding fallback support to st.
Diffstat (limited to 'st.c')
-rw-r--r--st.c201
1 files changed, 188 insertions, 13 deletions
diff --git a/st.c b/st.c
index 8074df9..a440959 100644
--- a/st.c
+++ b/st.c
@@ -275,7 +275,9 @@ typedef struct {
275 int descent; 275 int descent;
276 short lbearing; 276 short lbearing;
277 short rbearing; 277 short rbearing;
278 XftFont *set; 278 XftFont *match;
279 FcFontSet *set;
280 FcPattern *pattern;
279} Font; 281} Font;
280 282
281/* Drawing Context */ 283/* Drawing Context */
@@ -338,10 +340,13 @@ static void xclear(int, int, int, int);
338static void xdrawcursor(void); 340static void xdrawcursor(void);
339static void xinit(void); 341static void xinit(void);
340static void xloadcols(void); 342static void xloadcols(void);
343static int xloadfont(Font *, FcPattern *);
344static void xloadfonts(char *, int);
341static void xresettitle(void); 345static void xresettitle(void);
342static void xseturgency(int); 346static void xseturgency(int);
343static void xsetsel(char*); 347static void xsetsel(char*);
344static void xtermclear(int, int, int, int); 348static void xtermclear(int, int, int, int);
349static void xunloadfonts(void);
345static void xresize(int, int); 350static void xresize(int, int);
346 351
347static void expose(XEvent *); 352static void expose(XEvent *);
@@ -350,7 +355,7 @@ static void unmap(XEvent *);
350static char *kmap(KeySym, uint); 355static char *kmap(KeySym, uint);
351static void kpress(XEvent *); 356static void kpress(XEvent *);
352static void cmessage(XEvent *); 357static void cmessage(XEvent *);
353static void cresize(int width, int height); 358static void cresize(int, int);
354static void resize(XEvent *); 359static void resize(XEvent *);
355static void focus(XEvent *); 360static void focus(XEvent *);
356static void brelease(XEvent *); 361static void brelease(XEvent *);
@@ -373,7 +378,7 @@ static int isfullutf8(char *, int);
373static ssize_t xwrite(int, char *, size_t); 378static ssize_t xwrite(int, char *, size_t);
374static void *xmalloc(size_t); 379static void *xmalloc(size_t);
375static void *xrealloc(void *, size_t); 380static void *xrealloc(void *, size_t);
376static void *xcalloc(size_t nmemb, size_t size); 381static void *xcalloc(size_t, size_t);
377 382
378static void (*handler[LASTEvent])(XEvent *) = { 383static void (*handler[LASTEvent])(XEvent *) = {
379 [KeyPress] = kpress, 384 [KeyPress] = kpress,
@@ -412,6 +417,28 @@ static char *opt_font = NULL;
412static char *usedfont = NULL; 417static char *usedfont = NULL;
413static int usedfontsize = 0; 418static int usedfontsize = 0;
414 419
420/* Font Ring Cache */
421enum {
422 FRC_NORMAL,
423 FRC_ITALIC,
424 FRC_BOLD,
425 FRC_ITALICBOLD
426};
427
428typedef struct {
429 XftFont *font;
430 long c;
431 int flags;
432} Fontcache;
433
434/*
435 * Fontcache is a ring buffer, with frccur as current position and frclen as
436 * the current length of used elements.
437 */
438
439static Fontcache frc[256];
440static int frccur = 0, frclen = 0;
441
415ssize_t 442ssize_t
416xwrite(int fd, char *s, size_t len) { 443xwrite(int fd, char *s, size_t len) {
417 size_t aux = len; 444 size_t aux = len;
@@ -2282,20 +2309,28 @@ xloadfont(Font *f, FcPattern *pattern) {
2282 FcPattern *match; 2309 FcPattern *match;
2283 FcResult result; 2310 FcResult result;
2284 2311
2285 match = XftFontMatch(xw.dpy, xw.scr, pattern, &result); 2312 match = FcFontMatch(NULL, pattern, &result);
2286 if(!match) 2313 if(!match)
2287 return 1; 2314 return 1;
2288 if(!(f->set = XftFontOpenPattern(xw.dpy, match))) { 2315
2316 if(!(f->set = FcFontSort(0, match, FcTrue, 0, &result))) {
2317 FcPatternDestroy(match);
2318 return 1;
2319 }
2320
2321 if(!(f->match = XftFontOpenPattern(xw.dpy, match))) {
2289 FcPatternDestroy(match); 2322 FcPatternDestroy(match);
2290 return 1; 2323 return 1;
2291 } 2324 }
2292 2325
2293 f->ascent = f->set->ascent; 2326 f->pattern = FcPatternDuplicate(pattern);
2294 f->descent = f->set->descent; 2327
2328 f->ascent = f->match->ascent;
2329 f->descent = f->match->descent;
2295 f->lbearing = 0; 2330 f->lbearing = 0;
2296 f->rbearing = f->set->max_advance_width; 2331 f->rbearing = f->match->max_advance_width;
2297 2332
2298 f->height = f->set->height; 2333 f->height = f->match->height;
2299 f->width = f->lbearing + f->rbearing; 2334 f->width = f->lbearing + f->rbearing;
2300 2335
2301 return 0; 2336 return 0;
@@ -2334,6 +2369,9 @@ xloadfonts(char *fontstr, int fontsize) {
2334 } 2369 }
2335 } 2370 }
2336 2371
2372 FcConfigSubstitute(0, pattern, FcMatchPattern);
2373 FcDefaultSubstitute(pattern);
2374
2337 if(xloadfont(&dc.font, pattern)) 2375 if(xloadfont(&dc.font, pattern))
2338 die("st: can't open font %s\n", fontstr); 2376 die("st: can't open font %s\n", fontstr);
2339 2377
@@ -2359,8 +2397,40 @@ xloadfonts(char *fontstr, int fontsize) {
2359} 2397}
2360 2398
2361void 2399void
2400xunloadfonts(void)
2401{
2402 int i, ip;
2403
2404 /*
2405 * Free the loaded fonts in the font cache. This is done backwards
2406 * from the frccur.
2407 */
2408 for (i = 0, ip = frccur; i < frclen; i++, ip--) {
2409 if (ip <= 0)
2410 ip = LEN(frc) - 1;
2411 XftFontClose(xw.dpy, frc[ip].font);
2412 }
2413 frccur = 0;
2414 frclen = 0;
2415
2416 XftFontClose(xw.dpy, dc.font.match);
2417 FcPatternDestroy(dc.font.pattern);
2418 FcFontSetDestroy(dc.font.set);
2419 XftFontClose(xw.dpy, dc.bfont.match);
2420 FcPatternDestroy(dc.bfont.pattern);
2421 FcFontSetDestroy(dc.bfont.set);
2422 XftFontClose(xw.dpy, dc.ifont.match);
2423 FcPatternDestroy(dc.ifont.pattern);
2424 FcFontSetDestroy(dc.ifont.set);
2425 XftFontClose(xw.dpy, dc.ibfont.match);
2426 FcPatternDestroy(dc.ibfont.pattern);
2427 FcFontSetDestroy(dc.ibfont.set);
2428}
2429
2430void
2362xzoom(const Arg *arg) 2431xzoom(const Arg *arg)
2363{ 2432{
2433 xunloadfonts();
2364 xloadfonts(usedfont, usedfontsize + arg->i); 2434 xloadfonts(usedfont, usedfontsize + arg->i);
2365 cresize(0, 0); 2435 cresize(0, 0);
2366 draw(); 2436 draw();
@@ -2379,6 +2449,9 @@ xinit(void) {
2379 xw.vis = XDefaultVisual(xw.dpy, xw.scr); 2449 xw.vis = XDefaultVisual(xw.dpy, xw.scr);
2380 2450
2381 /* font */ 2451 /* font */
2452 if (!FcInit())
2453 die("Could not init fontconfig.\n");
2454
2382 usedfont = (opt_font == NULL)? font : opt_font; 2455 usedfont = (opt_font == NULL)? font : opt_font;
2383 xloadfonts(usedfont, 0); 2456 xloadfonts(usedfont, 0);
2384 2457
@@ -2459,13 +2532,22 @@ xinit(void) {
2459void 2532void
2460xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { 2533xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
2461 int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, 2534 int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
2462 width = charlen * xw.cw; 2535 width = charlen * xw.cw, u8clen, xp, i, frp, frcflags;
2536 long u8char;
2537 char *u8c;
2463 Font *font = &dc.font; 2538 Font *font = &dc.font;
2539 XftFont *sfont;
2540 FcResult fcres;
2541 FcPattern *fcpattern, *fontpattern;
2542 FcFontSet *fcsets[] = { NULL };
2543 FcCharSet *fccharset;
2464 XGlyphInfo extents; 2544 XGlyphInfo extents;
2465 Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg], 2545 Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
2466 *temp, revfg, revbg; 2546 *temp, revfg, revbg;
2467 XRenderColor colfg, colbg; 2547 XRenderColor colfg, colbg;
2468 2548
2549 frcflags = FRC_NORMAL;
2550
2469 if(base.mode & ATTR_BOLD) { 2551 if(base.mode & ATTR_BOLD) {
2470 if(BETWEEN(base.fg, 0, 7)) { 2552 if(BETWEEN(base.fg, 0, 7)) {
2471 /* basic system colors */ 2553 /* basic system colors */
@@ -2484,12 +2566,17 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
2484 * 252 - 255 – brightest colors in greyscale 2566 * 252 - 255 – brightest colors in greyscale
2485 */ 2567 */
2486 font = &dc.bfont; 2568 font = &dc.bfont;
2569 frcflags = FRC_BOLD;
2487 } 2570 }
2488 2571
2489 if(base.mode & ATTR_ITALIC) 2572 if(base.mode & ATTR_ITALIC) {
2490 font = &dc.ifont; 2573 font = &dc.ifont;
2491 if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) 2574 frcflags = FRC_ITALIC;
2575 }
2576 if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
2492 font = &dc.ibfont; 2577 font = &dc.ibfont;
2578 frcflags = FRC_ITALICBOLD;
2579 }
2493 2580
2494 if(IS_SET(MODE_REVERSE)) { 2581 if(IS_SET(MODE_REVERSE)) {
2495 if(fg == &dc.col[defaultfg]) { 2582 if(fg == &dc.col[defaultfg]) {
@@ -2521,7 +2608,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
2521 bg = temp; 2608 bg = temp;
2522 } 2609 }
2523 2610
2524 XftTextExtentsUtf8(xw.dpy, font->set, (FcChar8 *)s, bytelen, 2611 /* Width of the whole string that should be printed. */
2612 XftTextExtentsUtf8(xw.dpy, font->match, (FcChar8 *)s, bytelen,
2525 &extents); 2613 &extents);
2526 width = extents.xOff; 2614 width = extents.xOff;
2527 2615
@@ -2539,9 +2627,96 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
2539 if(y == term.row-1) 2627 if(y == term.row-1)
2540 xclear(winx, winy + xw.ch, winx + width, xw.h); 2628 xclear(winx, winy + xw.ch, winx + width, xw.h);
2541 2629
2630 /* Clean up the region we want to draw to. */
2542 XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch); 2631 XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
2632
2633 /*
2634 * Step through all UTF-8 characters one by one and search in the font
2635 * cache ring buffer, whether there was some font found to display the
2636 * unicode value of that UTF-8 character.
2637 */
2638 fcsets[0] = font->set;
2639 for (xp = winx; bytelen > 0; ) {
2640 u8c = s;
2641 u8clen = utf8decode(s, &u8char);
2642 s += u8clen;
2643 bytelen -= u8clen;
2644
2645 sfont = font->match;
2646 /*
2647 * Only check the font cache or load new fonts, if the
2648 * characters is not represented in main font.
2649 */
2650 if (!XftCharExists(xw.dpy, font->match, u8char)) {
2651 frp = frccur;
2652 /* Search the font cache. */
2653 for (i = 0; i < frclen; i++, frp--) {
2654 if (frp <= 0)
2655 frp = LEN(frc) - 1;
2656
2657 if (frc[frp].c == u8char
2658 && frc[frp].flags == frcflags) {
2659 break;
2660 }
2661 }
2662 if (i >= frclen) {
2663 /*
2664 * Nothing was found in the cache. Now use
2665 * some dozen of Fontconfig calls to get the
2666 * font for one single character.
2667 */
2668 fcpattern = FcPatternDuplicate(font->pattern);
2669 fccharset = FcCharSetCreate();
2670
2671 FcCharSetAddChar(fccharset, u8char);
2672 FcPatternAddCharSet(fcpattern, FC_CHARSET,
2673 fccharset);
2674 FcPatternAddBool(fcpattern, FC_SCALABLE,
2675 FcTrue);
2676
2677 FcConfigSubstitute(0, fcpattern,
2678 FcMatchPattern);
2679 FcDefaultSubstitute(fcpattern);
2680
2681 fontpattern = FcFontSetMatch(0, fcsets,
2682 FcTrue, fcpattern, &fcres);
2683
2684 frccur++;
2685 frclen++;
2686 if (frccur >= LEN(frc))
2687 frccur = 0;
2688 if (frclen >= LEN(frc)) {
2689 frclen = LEN(frc);
2690 XftFontClose(xw.dpy, frc[frccur].font);
2691 }
2692
2693 /*
2694 * Overwrite or create the new cache entry
2695 * entry.
2696 */
2697 frc[frccur].font = XftFontOpenPattern(xw.dpy,
2698 fontpattern);
2699 frc[frccur].c = u8char;
2700 frc[frccur].flags = frcflags;
2701
2702 FcPatternDestroy(fcpattern);
2703 FcCharSetDestroy(fccharset);
2704
2705 frp = frccur;
2706 }
2707 sfont = frc[frp].font;
2708 }
2709
2710 XftDrawStringUtf8(xw.draw, fg, sfont, xp, winy + sfont->ascent,
2711 (FcChar8 *)u8c, u8clen);
2712
2713 xp += font->width;
2714 }
2715
2716 /*
2543 XftDrawStringUtf8(xw.draw, fg, font->set, winx, 2717 XftDrawStringUtf8(xw.draw, fg, font->set, winx,
2544 winy + font->ascent, (FcChar8 *)s, bytelen); 2718 winy + font->ascent, (FcChar8 *)s, bytelen);
2719 */
2545 2720
2546 if(base.mode & ATTR_UNDERLINE) { 2721 if(base.mode & ATTR_UNDERLINE) {
2547 XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1, 2722 XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,