source: libcaca/trunk/caca/driver_slang.c @ 548

Last change on this file since 548 was 548, checked in by Sam Hocevar, 15 years ago
  • Split event.c into the appropriate driver_*.c files.
  • Property svn:keywords set to Id
File size: 12.3 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file driver_slang.c
13 *  \version \$Id: driver_slang.c 548 2006-03-08 09:28:41Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
15 *  \brief SLang driver
16 *
17 *  This file contains the libcaca SLang input and output driver
18 */
19
20#include "config.h"
21
22#if defined(USE_SLANG)
23
24#if defined(HAVE_SLANG_SLANG_H)
25#   include <slang/slang.h>
26#else
27#   include <slang.h>
28#endif
29
30#include <stdio.h> /* BUFSIZ */
31#include <string.h>
32#include <stdlib.h>
33#if defined(HAVE_UNISTD_H)
34#   include <unistd.h>
35#endif
36#include <stdarg.h>
37
38#if defined(HAVE_SIGNAL_H)
39#   include <signal.h>
40#endif
41
42#include "caca.h"
43#include "caca_internals.h"
44#include "cucul.h"
45#include "cucul_internals.h"
46
47/*
48 * Global variables
49 */
50
51/* Tables generated by test/optipal.c */
52static int const slang_palette[2*16*16] =
53{
54     1,  0,   2,  0,   3,  0,   4,  0,   5,  0,   6,  0,   7,  0,   8,  0,
55     9,  0,  10,  0,  11,  0,  12,  0,  13,  0,  14,  0,  15,  0,   0,  8,
56     8,  7,   7,  8,  15,  7,   7, 15,  15,  9,   9, 15,   1,  9,   9,  1,
57     7,  9,   9,  7,   8,  1,   1,  8,   0,  1,  15, 10,  10, 15,   2, 10,
58    10,  2,   7, 10,  10,  7,   8,  2,   2,  8,   0,  2,  15, 11,  11, 15,
59     3, 11,  11,  3,   7, 11,  11,  7,   8,  3,   3,  8,   0,  3,  15, 12,
60    12, 15,   4, 12,  12,  4,   7, 12,  12,  7,   8,  4,   4,  8,   0,  4,
61    15, 13,  13, 15,   5, 13,  13,  5,   7, 13,  13,  7,   8,  5,   5,  8,
62     0,  5,  15, 14,  14, 15,   6, 14,  14,  6,   7, 14,  14,  7,   8,  6,
63     6,  8,   0,  6,   4,  6,   6,  4,  12, 14,  14, 12,   6,  2,   2,  6,
64    14, 10,  10, 14,   2,  3,   3,  2,  10, 11,  11, 10,   3,  1,   1,  3,
65    11,  9,   9, 11,   1,  5,   5,  1,   9, 13,  13,  9,   5,  4,   4,  5,
66    13, 12,  12, 13,   4, 14,   6, 12,  12,  6,  14,  4,   6, 10,   2, 14,
67    14,  2,  10,  6,   2, 11,   3, 10,  10,  3,  11,  2,   3,  9,   1, 11,
68    11,  1,   9,  3,   1, 13,   5,  9,   9,  5,  13,  1,   5, 12,   4, 13,
69    13,  4,  12,  5,   0,  7,   0, 15,  15,  8,   8, 15,  15,  1,   7,  1,
70     1,  6,   2,  5,   3,  4,   4,  3,   5,  2,   6,  1,   0,  0,   1,  1,
71     9,  6,  10,  5,  11,  4,  12,  3,  13,  2,  14,  1,   2,  2,   3,  3,
72     4,  4,   5,  5,   6,  6,   7,  7,  14,  9,   1, 15,   8,  9,   8,  8,
73     9,  9,   1,  7,   0,  9,   9,  8,   6,  9,  13, 10,   2, 15,   8, 10,
74     7,  2,  15,  2,   2,  7,   0, 10,  10,  8,   5, 10,  12, 11,   3, 15,
75     8, 11,   7,  3,  15,  3,   3,  7,   0, 11,  11,  8,   4, 11,  11, 12,
76     4, 15,   8, 12,   7,  4,  15,  4,   4,  7,   0, 12,  12,  8,   3, 12,
77    10, 13,   5, 15,   8, 13,   7,  5,  15,  5,   5,  7,   0, 13,  13,  8,
78     2, 13,   9, 14,   6, 15,   8, 14,   7,  6,  15,  6,   6,  7,   0, 14,
79    14,  8,   1, 14,   5,  6,   2,  4,  13, 14,  10, 12,   4,  2,   3,  6,
80    12, 10,  11, 14,   6,  3,   1,  2,  14, 11,   9, 10,   2,  1,   5,  3,
81    10,  9,  13, 11,   3,  5,   4,  1,  11, 13,  12,  9,   1,  4,   6,  5,
82     9, 12,  14, 13,   5, 14,   2, 12,  13,  6,  10,  4,   4, 10,   3, 14,
83    12,  2,  11,  6,   6, 11,   1, 10,  14,  3,   9,  2,   2,  9,   5, 11,
84    10,  1,  13,  3,   3, 13,   4,  9,  11,  5,  12,  1,   1, 12,   6, 13,
85     9,  4,  14,  5,  10, 10,  11, 11,  12, 12,  13, 13,  14, 14,  15, 15,
86};
87
88static int const slang_assoc[16*16] =
89{
90    134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
91    28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
92    37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
93    46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
94    55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
95    64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
96    73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
97    122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
98    15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
99    154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
100    163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
101    172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
102    181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
103    190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
104    199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
105    123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
106};
107
108/*
109 * Local functions
110 */
111static void slang_init_palette(void);
112
113#if defined(HAVE_SIGNAL)
114static RETSIGTYPE sigwinch_handler(int);
115static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
116#endif
117
118static int slang_init_graphics(caca_t *kk)
119{
120#if defined(HAVE_SIGNAL)
121    sigwinch_kk = kk;
122    signal(SIGWINCH, sigwinch_handler);
123#endif
124
125    /* Initialise slang library */
126    SLsig_block_signals();
127    SLtt_get_terminfo();
128
129    if(SLkp_init() == -1)
130    {
131        SLsig_unblock_signals();
132        return -1;
133    }
134
135    SLang_init_tty(-1, 0, 1);
136
137    if(SLsmg_init_smg() == -1)
138    {
139        SLsig_unblock_signals();
140        return -1;
141    }
142
143    SLsig_unblock_signals();
144
145    SLsmg_cls();
146    SLtt_set_cursor_visibility(0);
147    SLkp_define_keysym("\e[M", 1001);
148    SLtt_set_mouse_mode(1, 0);
149    SLsmg_refresh();
150
151    /* Disable scrolling so that hashmap scrolling optimization code
152     * does not cause ugly refreshes due to slow terminals */
153    SLtt_Term_Cannot_Scroll = 1;
154
155    slang_init_palette();
156
157    /* Disable alt charset support so that we get a chance to have all
158     * 256 colour pairs */
159    SLtt_Has_Alt_Charset = 0;
160
161    cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
162
163    return 0;
164}
165
166static int slang_end_graphics(caca_t *kk)
167{
168    SLtt_set_mouse_mode(0, 0);
169    SLtt_set_cursor_visibility(1);
170    SLang_reset_tty();
171    SLsmg_reset_smg();
172
173    return 0;
174}
175
176static int slang_set_window_title(caca_t *kk, char const *title)
177{
178    /* FIXME */
179    return 0;
180}
181
182static unsigned int slang_get_window_width(caca_t *kk)
183{
184    /* Fallback to a 6x10 font */
185    return kk->qq->width * 6;
186}
187
188static unsigned int slang_get_window_height(caca_t *kk)
189{
190    /* Fallback to a 6x10 font */
191    return kk->qq->height * 10;
192}
193
194static void slang_display(caca_t *kk)
195{
196    int x, y;
197    uint8_t *attr = kk->qq->attr;
198    uint32_t *chars = kk->qq->chars;
199    for(y = 0; y < (int)kk->qq->height; y++)
200    {
201        SLsmg_gotorc(y, 0);
202        for(x = kk->qq->width; x--; )
203        {
204#if defined(OPTIMISE_SLANG_PALETTE)
205            /* If foreground == background, just don't use this colour
206             * pair, and print a space instead of the real character. */
207            uint8_t fgcolor = *attr & 0xf;
208            uint8_t bgcolor = *attr >> 4;
209            if(fgcolor != bgcolor)
210            {
211                SLsmg_set_color(slang_assoc[*attr++]);
212                SLsmg_write_char(*chars++ & 0x7f);
213            }
214            else
215            {
216                if(fgcolor == CUCUL_COLOR_BLACK)
217                    fgcolor = CUCUL_COLOR_WHITE;
218                else if(fgcolor == CUCUL_COLOR_WHITE
219                         || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
220                    fgcolor = CUCUL_COLOR_BLACK;
221                else
222                    fgcolor = CUCUL_COLOR_WHITE;
223                SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
224                SLsmg_write_char(' ');
225                chars++;
226                attr++;
227            }
228#else
229            SLsmg_set_color(*attr++);
230            SLsmg_write_char(*chars++ & 0x7f);
231#endif
232        }
233    }
234    SLsmg_refresh();
235}
236
237static void slang_handle_resize(caca_t *kk, unsigned int *new_width,
238                                            unsigned int *new_height)
239{
240    SLtt_get_screen_size();
241    *new_width = SLtt_Screen_Cols;
242    *new_height = SLtt_Screen_Rows;
243
244    if(*new_width != kk->qq->width || *new_height != kk->qq->height)
245        SLsmg_reinit_smg();
246}
247
248static unsigned int slang_get_event(caca_t *kk)
249{
250    unsigned int event;
251    int intkey;
252
253    if(kk->resize_event)
254    {
255        kk->resize_event = 0;
256        kk->resize = 1;
257        return CACA_EVENT_RESIZE;
258    }
259
260    if(!SLang_input_pending(0))
261        return CACA_EVENT_NONE;
262
263    /* We first use SLang_getkey() to see whether Esc was pressed
264     * alone, then (if it wasn't) we unget the key and use SLkp_getkey()
265     * instead, so that escape sequences are interpreted. */
266    intkey = SLang_getkey();
267
268    if(intkey != 0x1b /* Esc */ || SLang_input_pending(0))
269    {
270        SLang_ungetkey(intkey);
271        intkey = SLkp_getkey();
272    }
273
274    /* If the key was ASCII, return it immediately */
275    if(intkey < 0x100)
276    {
277        return CACA_EVENT_KEY_PRESS | intkey;
278    }
279
280    if(intkey == 0x3e9)
281    {
282        int button = (SLang_getkey() - ' ' + 1) & 0xf;
283        unsigned int x = SLang_getkey() - '!';
284        unsigned int y = SLang_getkey() - '!';
285        _push_event(kk, CACA_EVENT_MOUSE_PRESS | button);
286        _push_event(kk, CACA_EVENT_MOUSE_RELEASE | button);
287
288        if(kk->mouse_x == x && kk->mouse_y == y)
289            return _pop_event(kk);
290
291        kk->mouse_x = x;
292        kk->mouse_y = y;
293
294        return CACA_EVENT_MOUSE_MOTION | (kk->mouse_x << 12) | kk->mouse_y;
295    }
296
297    event = CACA_EVENT_KEY_PRESS;
298
299    switch(intkey)
300    {
301        case SL_KEY_UP: return event | CACA_KEY_UP;
302        case SL_KEY_DOWN: return event | CACA_KEY_DOWN;
303        case SL_KEY_LEFT: return event | CACA_KEY_LEFT;
304        case SL_KEY_RIGHT: return event | CACA_KEY_RIGHT;
305
306        case SL_KEY_IC: return event | CACA_KEY_INSERT;
307        case SL_KEY_DELETE: return event | CACA_KEY_DELETE;
308        case SL_KEY_HOME: return event | CACA_KEY_HOME;
309        case SL_KEY_END: return event | CACA_KEY_END;
310        case SL_KEY_PPAGE: return event | CACA_KEY_PAGEUP;
311        case SL_KEY_NPAGE: return event | CACA_KEY_PAGEDOWN;
312
313        case SL_KEY_F(1): return event | CACA_KEY_F1;
314        case SL_KEY_F(2): return event | CACA_KEY_F2;
315        case SL_KEY_F(3): return event | CACA_KEY_F3;
316        case SL_KEY_F(4): return event | CACA_KEY_F4;
317        case SL_KEY_F(5): return event | CACA_KEY_F5;
318        case SL_KEY_F(6): return event | CACA_KEY_F6;
319        case SL_KEY_F(7): return event | CACA_KEY_F7;
320        case SL_KEY_F(8): return event | CACA_KEY_F8;
321        case SL_KEY_F(9): return event | CACA_KEY_F9;
322        case SL_KEY_F(10): return event | CACA_KEY_F10;
323        case SL_KEY_F(11): return event | CACA_KEY_F11;
324        case SL_KEY_F(12): return event | CACA_KEY_F12;
325    }
326
327    return CACA_EVENT_NONE;
328}
329
330/*
331 * XXX: following functions are local
332 */
333
334static void slang_init_palette(void)
335{
336    /* See SLang ref., 5.4.4. */
337    static char *slang_colors[16] =
338    {
339        /* Standard colours */
340        "black",
341        "blue",
342        "green",
343        "cyan",
344        "red",
345        "magenta",
346        "brown",
347        "lightgray",
348        /* Bright colours */
349        "gray",
350        "brightblue",
351        "brightgreen",
352        "brightcyan",
353        "brightred",
354        "brightmagenta",
355        "yellow",
356        "white",
357    };
358
359#if defined(OPTIMISE_SLANG_PALETTE)
360    int i;
361
362    for(i = 0; i < 16 * 16; i++)
363        SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
364                                slang_colors[slang_palette[i * 2 + 1]]);
365#else
366    int fg, bg;
367
368    for(bg = 0; bg < 16; bg++)
369        for(fg = 0; fg < 16; fg++)
370        {
371            int i = fg + 16 * bg;
372            SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
373        }
374#endif
375}
376
377#if defined(HAVE_SIGNAL)
378static RETSIGTYPE sigwinch_handler(int sig)
379{
380    sigwinch_kk->resize_event = 1;
381
382    signal(SIGWINCH, sigwinch_handler);;
383}
384#endif
385
386/*
387 * Driver initialisation
388 */
389
390void slang_init_driver(caca_t *kk)
391{
392    kk->driver.driver = CACA_DRIVER_SLANG;
393
394    kk->driver.init_graphics = slang_init_graphics;
395    kk->driver.end_graphics = slang_end_graphics;
396    kk->driver.set_window_title = slang_set_window_title;
397    kk->driver.get_window_width = slang_get_window_width;
398    kk->driver.get_window_height = slang_get_window_height;
399    kk->driver.display = slang_display;
400    kk->driver.handle_resize = slang_handle_resize;
401    kk->driver.get_event = slang_get_event;
402}
403
404#endif /* USE_SLANG */
405
Note: See TracBrowser for help on using the repository browser.