Ignore:
Timestamp:
Jun 27, 2007, 7:40:14 PM (12 years ago)
Author:
Sam Hocevar
Message:
  • X11 driver improvements courtesy of Ben Wiley Sittler. Reworked them a bit myself, too.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcaca/trunk/caca/driver_x11.c

    r1462 r1775  
    11/*
    22 *  libcaca       Colour ASCII-Art library
    3  *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
     3 *  Copyright (c) 2002-2007 Sam Hocevar <sam@zoy.org>
     4 *                2007 Ben Wiley Sittler <bsittler@gmail.com>
    45 *                All Rights Reserved
    56 *
     
    3132#include <stdio.h> /* BUFSIZ */
    3233#include <stdlib.h>
     34#include <string.h>
    3335
    3436#include "caca.h"
     
    4143 */
    4244static int x11_error_handler(Display *, XErrorEvent *);
     45static void x11_put_glyph(caca_display_t *, int, int, int, int, int,
     46                          uint32_t, uint32_t);
    4347
    4448struct driver_private
     
    6064    Bool autorepeat;
    6165#endif
     66    uint32_t max_char;
    6267};
     68
     69#define UNICODE_XLFD_SUFFIX "-iso10646-1"
     70#define LATIN_1_XLFD_SUFFIX "-iso8859-1"
    6371
    6472static int x11_init_graphics(caca_display_t *dp)
     
    100108    for( ; ; parser++)
    101109    {
     110        unsigned int font_max_char;
     111
    102112        if(!*parser)
    103113        {
     
    118128        }
    119129
     130        if((strlen(*parser) > sizeof(UNICODE_XLFD_SUFFIX))
     131             && !strcasecmp(*parser + strlen(*parser)
     132                          - strlen(UNICODE_XLFD_SUFFIX), UNICODE_XLFD_SUFFIX))
     133            dp->drv.p->max_char = 0xffff;
     134        else if((strlen(*parser) > sizeof(LATIN_1_XLFD_SUFFIX))
     135                 && !strcasecmp(*parser + strlen(*parser)
     136                        - strlen(LATIN_1_XLFD_SUFFIX), LATIN_1_XLFD_SUFFIX))
     137            dp->drv.p->max_char = 0xff;
     138        else
     139            dp->drv.p->max_char = 0x7f;
     140
     141        font_max_char =
     142            (((unsigned int)dp->drv.p->font_struct->max_byte1) << 8)
     143             | dp->drv.p->font_struct->max_char_or_byte2;
     144        if(font_max_char && (font_max_char < dp->drv.p->max_char))
     145            dp->drv.p->max_char = font_max_char;
     146
    120147        break;
    121148    }
     
    123150    /* Reset the default X11 error handler */
    124151    XSetErrorHandler(old_error_handler);
    125 
    126     dp->drv.p->font_width = dp->drv.p->font_struct->max_bounds.width;
     152   
     153    dp->drv.p->font_width = 0;
     154    if(dp->drv.p->font_struct->per_char
     155        && !dp->drv.p->font_struct->min_byte1
     156        && dp->drv.p->font_struct->min_char_or_byte2 <= 0x21
     157        && dp->drv.p->font_struct->max_char_or_byte2 >= 0x7e)
     158    {
     159        for(i = 0x21; i < 0x7f; i++)
     160        {
     161            int cw = dp->drv.p->font_struct->per_char[i
     162                           - dp->drv.p->font_struct->min_char_or_byte2].width;
     163            if(cw > dp->drv.p->font_width)
     164                dp->drv.p->font_width = cw;
     165        }
     166    }
     167
     168    if(!dp->drv.p->font_width)
     169        dp->drv.p->font_width = dp->drv.p->font_struct->max_bounds.width;
     170
    127171    dp->drv.p->font_height = dp->drv.p->font_struct->max_bounds.ascent
    128172                         + dp->drv.p->font_struct->max_bounds.descent;
     
    174218        XEvent xevent;
    175219        XNextEvent(dp->drv.p->dpy, &xevent);
    176         if (xevent.type == MapNotify)
     220        if(xevent.type == MapNotify)
    177221            break;
    178222    }
     
    259303                           dp->drv.p->colors[bg]);
    260304            XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->gc,
    261                            x * dp->drv.p->font_width, y * dp->drv.p->font_height,
    262                            len * dp->drv.p->font_width, dp->drv.p->font_height);
     305                           x * dp->drv.p->font_width,
     306                           y * dp->drv.p->font_height,
     307                           len * dp->drv.p->font_width,
     308                           dp->drv.p->font_height);
    263309        }
    264310    }
     
    270316                                    - dp->drv.p->font_offset;
    271317        uint32_t *chars = dp->cv->chars + y * dp->cv->width;
    272 
    273         for(x = 0; x < dp->cv->width; x++, chars++)
    274         {
    275             uint32_t *attrs = dp->cv->attrs + x + y * dp->cv->width;
    276 
    277             /* Underline */
    278             if(*attrs & CUCUL_UNDERLINE)
    279                 XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    280                                    dp->drv.p->gc,
    281                                    x * dp->drv.p->font_width,
    282                                    (y + 1) * dp->drv.p->font_height - 1,
    283                                    dp->drv.p->font_width, 1);
    284 
    285             /* Skip spaces */
    286             if(*chars <= 0x00000020)
    287                 continue;
    288 
    289             if(*chars == CUCUL_MAGIC_FULLWIDTH)
    290                 continue;
    291 
     318        uint32_t *attrs = dp->cv->attrs + y * dp->cv->width;
     319
     320        for(x = 0; x < dp->cv->width; x++, chars++, attrs++)
     321        {
    292322            XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
    293323                           dp->drv.p->colors[_cucul_attr_to_rgb12fg(*attrs)]);
    294324
    295             /* Plain ASCII, no problem. */
    296             if(*chars > 0x00000020 && *chars < 0x00000080)
    297             {
    298                 char ch = (uint8_t)*chars;
    299                 XDrawString(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->gc,
    300                             x * dp->drv.p->font_width, yoff, &ch, 1);
    301                 continue;
    302             }
    303 
    304             /* We want to be able to print a few special Unicode characters
    305              * such as the CP437 gradients and half blocks. For unknown
    306              * characters, just print '?'. */
    307             switch(*chars)
    308             {
    309                 case 0x000000b7: /* · */
    310                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    311                                    dp->drv.p->gc,
    312                                    x * dp->drv.p->font_width
    313                                      + dp->drv.p->font_width / 2,
    314                                    y * dp->drv.p->font_height
    315                                      + dp->drv.p->font_height / 2, 2, 2);
    316                     break;
    317                 case 0x00002500: /* ─ */
    318                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    319                                    dp->drv.p->gc,
    320                                    x * dp->drv.p->font_width,
    321                                    y * dp->drv.p->font_height
    322                                      + dp->drv.p->font_height / 2 + 1,
    323                                    dp->drv.p->font_width, 1);
    324                     break;
    325                 case 0x00002580: /* ▀ */
    326                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    327                                    dp->drv.p->gc,
    328                                    x * dp->drv.p->font_width,
    329                                    y * dp->drv.p->font_height,
    330                                    dp->drv.p->font_width,
    331                                    dp->drv.p->font_height / 2);
    332                     break;
    333                 case 0x00002584: /* ▄ */
    334                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    335                                    dp->drv.p->gc,
    336                                    x * dp->drv.p->font_width,
    337                                    (y + 1) * dp->drv.p->font_height
    338                                            - dp->drv.p->font_height / 2,
    339                                    dp->drv.p->font_width,
    340                                    dp->drv.p->font_height / 2);
    341                     break;
    342                 case 0x00002588: /* █ */
    343                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    344                                    dp->drv.p->gc,
    345                                    x * dp->drv.p->font_width,
    346                                    y * dp->drv.p->font_height,
    347                                    dp->drv.p->font_width,
    348                                    dp->drv.p->font_height);
    349                     break;
    350                 case 0x0000258c: /* ▌ */
    351                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    352                                    dp->drv.p->gc,
    353                                    x * dp->drv.p->font_width,
    354                                    y * dp->drv.p->font_height,
    355                                    dp->drv.p->font_width / 2,
    356                                    dp->drv.p->font_height);
    357                     break;
    358                 case 0x00002590: /* ▐ */
    359                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    360                                    dp->drv.p->gc,
    361                                    (x + 1) * dp->drv.p->font_width
    362                                            - dp->drv.p->font_width / 2,
    363                                    y * dp->drv.p->font_height,
    364                                    dp->drv.p->font_width / 2,
    365                                    dp->drv.p->font_height);
    366                     break;
    367                 case 0x000025a0: /* ■ */
    368                     XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
    369                                    dp->drv.p->gc,
    370                                    x * dp->drv.p->font_width,
    371                                    y * dp->drv.p->font_height
    372                                      + dp->drv.p->font_height / 4,
    373                                    dp->drv.p->font_width,
    374                                    dp->drv.p->font_height / 2);
    375                     break;
    376                 case 0x00002593: /* ▓ */
    377                 case 0x00002592: /* ▒ */
    378                 case 0x00002591: /* ░ */
    379                 {
    380                     /* FIXME: this sucks utterly */
    381                     int i, j, k = *chars - 0x00002591;
    382                     for(j = dp->drv.p->font_height; j--; )
    383                         for(i = dp->drv.p->font_width; i--; )
    384                     {
    385                         if(((i + 2 * (j & 1)) & 3) > k)
    386                             continue;
    387 
    388                         XDrawPoint(dp->drv.p->dpy, dp->drv.p->pixmap,
    389                                    dp->drv.p->gc,
    390                                    x * dp->drv.p->font_width + i,
    391                                    y * dp->drv.p->font_height + j);
    392                     }
    393                     break;
    394                 }
    395                 default:
    396                 {
    397                     char ch;
    398                     ch = '?';
    399                     XDrawString(dp->drv.p->dpy, dp->drv.p->pixmap,
    400                                 dp->drv.p->gc,
    401                                 x * dp->drv.p->font_width, yoff, &ch, 1);
    402                     break;
    403                 }
    404             }
     325            x11_put_glyph(dp, x * dp->drv.p->font_width,
     326                          y * dp->drv.p->font_height, yoff,
     327                          dp->drv.p->font_width, dp->drv.p->font_height,
     328                          *attrs, *chars);
    405329        }
    406330    }
     
    623547}
    624548
     549static void x11_put_glyph(caca_display_t *dp, int x, int y, int yoff,
     550                          int w, int h, uint32_t attr, uint32_t ch)
     551{
     552    Display *dpy = dp->drv.p->dpy;
     553    Pixmap px = dp->drv.p->pixmap;
     554    GC gc = dp->drv.p->gc;
     555    int fw;
     556    XChar2b ch16;
     557
     558    /* Underline */
     559    if(attr & CUCUL_UNDERLINE)
     560        XFillRectangle(dpy, px, gc, x, y + h - 1, w, 1);
     561
     562    /* Skip spaces and magic stuff */
     563    if(ch <= 0x00000020)
     564        return;
     565
     566    if(ch == CUCUL_MAGIC_FULLWIDTH)
     567        return;
     568
     569    fw = w;
     570    if(cucul_utf32_is_fullwidth(ch))
     571        fw *= 2;
     572
     573    /* We want to be able to print a few special Unicode characters
     574     * such as the CP437 gradients and half blocks. For unknown
     575     * characters, print what cucul_utf32_to_ascii() returns. */
     576
     577    if(ch >= 0x2500 && ch <= 0x256c)
     578    {
     579        static uint8_t const udlr[] =
     580        {
     581            /* 0x2500 - 0x250f: ─ . │ . . . . . . . . . ┌ . . . */
     582            0x05, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
     583            0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
     584            /* 0x2510 - 0x251f: ┐ . . . └ . . . ┘ . . . ├ . . . */
     585            0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
     586            0x44, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
     587            /* 0x2520 - 0x252f: . . . . ┤ . . . . . . . ┬ . . . */
     588            0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
     589            0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
     590            /* 0x2530 - 0x253f: . . . . ┴ . . . . . . . ┼ . . . */
     591            0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
     592            0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
     593            /* 0x2540 - 0x254f: . . . . . . . . . . . . . . . . */
     594            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     595            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     596            /* 0x2550 - 0x255f: ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ */
     597            0x0a, 0xa0, 0x12, 0x21, 0x22, 0x18, 0x24, 0x28,
     598            0x42, 0x81, 0x82, 0x48, 0x84, 0x88, 0x52, 0xa1,
     599            /* 0x2560 - 0x256c: ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ */
     600            0xa2, 0x58, 0xa4, 0xa8, 0x1a, 0x25, 0x2a, 0x4a,
     601            0x85, 0x8a, 0x5a, 0xa5, 0xaa,
     602        };
     603
     604        uint16_t D = udlr[ch - 0x2500];
     605
     606        if(!D)
     607            goto next_try;
     608
     609        if(D & 0x04)
     610            XFillRectangle(dpy, px, gc, x, y + h / 2, fw / 2 + 1, 1);
     611
     612        if(D & 0x01)
     613            XFillRectangle(dpy, px, gc,
     614                           x + fw / 2, y + h / 2, (fw + 1) / 2, 1);
     615
     616        if(D & 0x40)
     617            XFillRectangle(dpy, px, gc, x + fw / 2, y, 1, h / 2 + 1);
     618
     619        if(D & 0x10)
     620            XFillRectangle(dpy, px, gc, x + fw / 2, y + h / 2, 1, (h + 1) / 2);
     621
     622#define STEPIF(a,b) (D&(a)?-1:(D&(b))?1:0)
     623
     624        if(D & 0x08)
     625        {
     626            XFillRectangle(dpy, px, gc, x, y - 1 + h / 2,
     627                           fw / 2 + 1 + STEPIF(0xc0,0x20), 1);
     628            XFillRectangle(dpy, px, gc, x, y + 1 + h / 2,
     629                           fw / 2 + 1 + STEPIF(0x30,0x80), 1);
     630        }
     631
     632        if(D & 0x02)
     633        {
     634            XFillRectangle(dpy, px, gc, x - STEPIF(0xc0,0x20) + fw / 2,
     635                           y - 1 + h / 2, (fw + 1) / 2 + STEPIF(0xc0,0x20), 1);
     636            XFillRectangle(dpy, px, gc, x - STEPIF(0x30,0x80) + fw / 2,
     637                           y + 1 + h / 2, (fw + 1) / 2 + STEPIF(0x30,0x80), 1);
     638        }
     639
     640        if(D & 0x80)
     641        {
     642            XFillRectangle(dpy, px, gc, x - 1 + fw / 2, y,
     643                           1, h / 2 + 1 + STEPIF(0x0c,0x02));
     644            XFillRectangle(dpy, px, gc, x + 1 + fw / 2, y,
     645                           1, h / 2 + 1 + STEPIF(0x03,0x08));
     646        }
     647
     648        if(D & 0x20)
     649        {
     650            XFillRectangle(dpy, px, gc, x - 1 + fw / 2,
     651                           y - STEPIF(0x0c,0x02) + h / 2,
     652                           1, (h + 1) / 2 + STEPIF(0x0c,0x02));
     653            XFillRectangle(dpy, px, gc, x + 1 + fw / 2,
     654                           y - STEPIF(0x03,0x08) + h / 2,
     655                           1, (h + 1) / 2 + STEPIF(0x03,0x08));
     656        }
     657
     658        return;
     659    }
     660next_try:
     661
     662    switch(ch)
     663    {
     664        case 0x000000b7: /* · */
     665        case 0x00002219: /* ∙ */
     666        case 0x000030fb: /* ・ */
     667            XFillRectangle(dpy, px, gc, x + fw / 2 - 1, y + h / 2 - 1, 2, 2);
     668            return;
     669
     670        case 0x00002261: /* ≡ */
     671            XFillRectangle(dpy, px, gc, x + 1, y - 2 + h / 2, fw - 1, 1);
     672            XFillRectangle(dpy, px, gc, x + 1, y + h / 2, fw - 1, 1);
     673            XFillRectangle(dpy, px, gc, x + 1, y + 2 + h / 2, fw - 1, 1);
     674            return;
     675
     676        case 0x00002580: /* ▀ */
     677            XFillRectangle(dpy, px, gc, x, y, fw, h / 2);
     678            return;
     679
     680        case 0x00002584: /* ▄ */
     681            XFillRectangle(dpy, px, gc, x, y + h - h / 2, fw, h / 2);
     682            return;
     683
     684        case 0x00002588: /* █ */
     685        case 0x000025ae: /* ▮ */
     686            XFillRectangle(dpy, px, gc, x, y, fw, h);
     687            return;
     688
     689        case 0x0000258c: /* ▌ */
     690            XFillRectangle(dpy, px, gc, x, y, fw / 2, h);
     691            return;
     692
     693        case 0x00002590: /* ▐ */
     694            XFillRectangle(dpy, px, gc, x + fw - fw / 2, y, fw / 2, h);
     695            return;
     696
     697        case 0x000025a0: /* ■ */
     698        case 0x000025ac: /* ▬ */
     699            XFillRectangle(dpy, px, gc, x, y + h / 4, fw, h / 2);
     700            return;
     701
     702        case 0x00002593: /* ▓ */
     703        case 0x00002592: /* ▒ */
     704        case 0x00002591: /* ░ */
     705        {
     706            /* FIXME: this sucks utterly */
     707            int i, j, k = ch - 0x00002591;
     708            for(j = h; j--; )
     709                for(i = fw; i--; )
     710            {
     711                if(((i + 2 * (j & 1)) & 3) > k)
     712                    continue;
     713
     714                XDrawPoint(dpy, px, gc, x + i, y + j);
     715            }
     716            return;
     717        }
     718
     719        case 0x000025cb: /* ○ */
     720        case 0x00002022: /* • */
     721        case 0x000025cf: /* ● */
     722        {
     723            int d, xo, yo;
     724
     725            d = fw;
     726            if(h < fw)
     727                d = h;
     728            if(d < 1)
     729                d = 1;
     730            xo = (fw - d) / 2;
     731            yo = (h - d) / 2;
     732            if(ch == 0x000025cb)
     733                XDrawArc(dpy, px, gc, x + xo, y + yo, d, d, 0, 64 * 360);
     734            else
     735                XFillArc(dpy, px, gc, x + xo, y + yo, d, d, 0, 64 * 360);
     736            return;
     737        }
     738    }
     739
     740    if(ch >= 0x00000020 && ch <= dp->drv.p->max_char)
     741    {
     742        /* ascii, latin-1 or unicode font (might draw a blank square) */
     743        ch16.byte1 = (ch) >> 8;
     744        ch16.byte2 = (ch) & 0xff;
     745    }
     746    else
     747    {
     748        ch16.byte1 = 0;
     749        ch16.byte2 = cucul_utf32_to_ascii(ch);
     750    }
     751
     752    XDrawString16(dpy, px, gc, x + (ch16.byte1 ? 0 : (fw - w) / 2), yoff, &ch16, 1);
     753}
     754
    625755/*
    626756 * Driver initialisation
Note: See TracChangeset for help on using the changeset viewer.