diff options
author | Christoph Lohmann <20h@r-36.net> | 2012-12-28 23:52:04 +0100 |
---|---|---|
committer | Christoph Lohmann <20h@r-36.net> | 2012-12-28 23:52:04 +0100 |
commit | 9c44229c626ea7351a7809540435f40cffb624bc (patch) | |
tree | 5f2e5cec411b3974230e125aa1669d1b42674317 /st.c | |
parent | 082bab29f3551e5cee332832ff767c3fb65a5cbc (diff) | |
download | st-9c44229c626ea7351a7809540435f40cffb624bc.tar.gz st-9c44229c626ea7351a7809540435f40cffb624bc.zip |
Adding fallback support to st.
Diffstat (limited to 'st.c')
-rw-r--r-- | st.c | 201 |
1 files changed, 188 insertions, 13 deletions
@@ -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); | |||
338 | static void xdrawcursor(void); | 340 | static void xdrawcursor(void); |
339 | static void xinit(void); | 341 | static void xinit(void); |
340 | static void xloadcols(void); | 342 | static void xloadcols(void); |
343 | static int xloadfont(Font *, FcPattern *); | ||
344 | static void xloadfonts(char *, int); | ||
341 | static void xresettitle(void); | 345 | static void xresettitle(void); |
342 | static void xseturgency(int); | 346 | static void xseturgency(int); |
343 | static void xsetsel(char*); | 347 | static void xsetsel(char*); |
344 | static void xtermclear(int, int, int, int); | 348 | static void xtermclear(int, int, int, int); |
349 | static void xunloadfonts(void); | ||
345 | static void xresize(int, int); | 350 | static void xresize(int, int); |
346 | 351 | ||
347 | static void expose(XEvent *); | 352 | static void expose(XEvent *); |
@@ -350,7 +355,7 @@ static void unmap(XEvent *); | |||
350 | static char *kmap(KeySym, uint); | 355 | static char *kmap(KeySym, uint); |
351 | static void kpress(XEvent *); | 356 | static void kpress(XEvent *); |
352 | static void cmessage(XEvent *); | 357 | static void cmessage(XEvent *); |
353 | static void cresize(int width, int height); | 358 | static void cresize(int, int); |
354 | static void resize(XEvent *); | 359 | static void resize(XEvent *); |
355 | static void focus(XEvent *); | 360 | static void focus(XEvent *); |
356 | static void brelease(XEvent *); | 361 | static void brelease(XEvent *); |
@@ -373,7 +378,7 @@ static int isfullutf8(char *, int); | |||
373 | static ssize_t xwrite(int, char *, size_t); | 378 | static ssize_t xwrite(int, char *, size_t); |
374 | static void *xmalloc(size_t); | 379 | static void *xmalloc(size_t); |
375 | static void *xrealloc(void *, size_t); | 380 | static void *xrealloc(void *, size_t); |
376 | static void *xcalloc(size_t nmemb, size_t size); | 381 | static void *xcalloc(size_t, size_t); |
377 | 382 | ||
378 | static void (*handler[LASTEvent])(XEvent *) = { | 383 | static void (*handler[LASTEvent])(XEvent *) = { |
379 | [KeyPress] = kpress, | 384 | [KeyPress] = kpress, |
@@ -412,6 +417,28 @@ static char *opt_font = NULL; | |||
412 | static char *usedfont = NULL; | 417 | static char *usedfont = NULL; |
413 | static int usedfontsize = 0; | 418 | static int usedfontsize = 0; |
414 | 419 | ||
420 | /* Font Ring Cache */ | ||
421 | enum { | ||
422 | FRC_NORMAL, | ||
423 | FRC_ITALIC, | ||
424 | FRC_BOLD, | ||
425 | FRC_ITALICBOLD | ||
426 | }; | ||
427 | |||
428 | typedef 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 | |||
439 | static Fontcache frc[256]; | ||
440 | static int frccur = 0, frclen = 0; | ||
441 | |||
415 | ssize_t | 442 | ssize_t |
416 | xwrite(int fd, char *s, size_t len) { | 443 | xwrite(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 | ||
2361 | void | 2399 | void |
2400 | xunloadfonts(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 | |||
2430 | void | ||
2362 | xzoom(const Arg *arg) | 2431 | xzoom(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) { | |||
2459 | void | 2532 | void |
2460 | xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { | 2533 | xdraws(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, |