1 /* TTY-specific Lisp objects.
2 Copyright (C) 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995, 1996 Ben Wing.
4 Copyright (C) 2007, 2008 Nelson Ferreira
6 This file is part of SXEmacs
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 /* Synched up with: Not in FSF. */
27 #include "console-tty.h"
28 #include "ui/insdel.h"
29 #include "objects-tty.h"
31 #include "ui/device.h"
32 #include "mule/mule-charset.h"
36 /* Term => ( color => '(index bold) ) */
37 Lisp_Object Vterm_color_alias_slist;
39 /* Term => ( [r g b] => '(index bold) ) */
40 Lisp_Object Vterm_color_map_slist;
43 Lisp_Object Qx_nearest_color;
45 static inline Lisp_Object
46 get_term_color_alias_slist( Lisp_Object sym_term, unsigned create )
47 __attribute__((always_inline));
49 static inline Lisp_Object
50 get_term_color_alias_slist( Lisp_Object sym_term, unsigned create )
52 Lisp_Object color_slist = Qnil;
54 if ( EQ(Vterm_color_alias_slist,Qnil) ) {
55 Vterm_color_alias_slist = make_skiplist();
57 assert(SKIPLISTP(Vterm_color_alias_slist));
58 color_slist = get_skiplist(XSKIPLIST(Vterm_color_alias_slist),
61 if ( EQ(color_slist,Qnil) ) {
63 color_slist = make_skiplist();
66 assert(SKIPLISTP(color_slist));
71 static inline Lisp_Object
72 get_term_color_map_slist( Lisp_Object sym_term, unsigned create )
73 __attribute__((always_inline));
74 static inline Lisp_Object
75 get_term_color_map_slist( Lisp_Object sym_term, unsigned create )
77 Lisp_Object map_slist = Qnil;
79 if ( EQ(Vterm_color_map_slist,Qnil) ) {
80 Vterm_color_map_slist = make_skiplist();
82 assert(SKIPLISTP(Vterm_color_map_slist));
83 map_slist = get_skiplist(XSKIPLIST(Vterm_color_map_slist),
86 if ( EQ(map_slist,Qnil) ) {
88 map_slist = make_skiplist();
91 assert(SKIPLISTP(map_slist));
98 DEFUN("register-tty-color-index", Fregister_tty_color_index, 6, 7, 0, /*
99 Register COLOR as recognized by TERM with index IDX and RED, GREEN and BLUE
101 RED, GREEN and BLUE is expected to be in the range 0 through 65535
103 (term,color,idx,red,green,blue,bold))
105 Lisp_Object sym_term = Qnil;
106 Lisp_Object sym_color = Qnil;
107 Lisp_Object rgb_tuple = Qnil;
108 Lisp_Object idx_tuple = Qnil;
109 Lisp_Object map_slist = Qnil;
110 Lisp_Object color_slist = Qnil;
112 /* Validating the parameter types */
114 CHECK_INT_OR_FLOAT(red);
115 CHECK_INT_OR_FLOAT(green);
116 CHECK_INT_OR_FLOAT(blue);
119 /* term and color can be given as symbols or strings.
120 if given as strings we auto-intern them
122 if( RECORD_TYPEP(term, lrecord_type_symbol) ) {
124 } else if ( RECORD_TYPEP(term, lrecord_type_string) ) {
125 sym_term = Fintern(term,Qnil);
127 dead_wrong_type_argument(Qstringp,term);
129 if( RECORD_TYPEP(color, lrecord_type_symbol) ) {
131 } else if ( RECORD_TYPEP(color, lrecord_type_string) ) {
132 sym_color = Fintern(color,Qnil);
134 dead_wrong_type_argument(Qstringp,color);
137 color_slist = get_term_color_alias_slist(sym_term, 1);
138 map_slist = get_term_color_map_slist(sym_term, 1);
140 /* Updating the skiplists
142 rgb_tuple = make_vector(3,Qnil);
143 Faset(rgb_tuple, make_int(0), red);
144 Faset(rgb_tuple, make_int(1), green);
145 Faset(rgb_tuple, make_int(2), blue);
147 { /* Build the index tuple */
148 Lisp_Object list_args[2];
152 idx_tuple = Flist(2, list_args);
155 /* Add the color alias */
156 put_skiplist( XSKIPLIST(color_slist),sym_color,idx_tuple);
157 put_skiplist( XSKIPLIST(Vterm_color_alias_slist),
159 /* Add the index rgb */
160 put_skiplist( XSKIPLIST(map_slist),rgb_tuple,idx_tuple);
161 put_skiplist( XSKIPLIST(Vterm_color_map_slist),
167 static Lisp_Object tty_slist_keyname_accum( Lisp_Object key, Lisp_Object val, void* accum)
169 Lisp_Object *result = (Lisp_Object*)accum;
170 *result = Fcons(Fsymbol_name(key), *result);
174 static Lisp_Object tty_slist_key_accum( Lisp_Object key, Lisp_Object val, void* accum)
176 Lisp_Object *result = (Lisp_Object*)accum;
177 *result = Fcons(key, *result);
181 static Lisp_Object nearest_color_slist( Lisp_Object sym_color, Lisp_Object slist )
183 Lisp_Object rgblist = Qnil;
184 Lisp_Object result = Qnil;
186 map2_skiplist(XSKIPLIST(slist), tty_slist_key_accum, &rgblist );
187 result = call2_trapping_errors( "Error_nearest_color",
189 sym_color, rgblist );
194 DEFUN("find-tty-color", Ffind_tty_color, 1, 3, 0, /*
195 Look up COLOR in the list of registered TTY colors for DEVICE or NEAREST.
196 DEVICE defaults to the selected device if omitted.
197 If it is found, return a list (INDEX BOLD) used to set the foreground to the color.
198 If it is not found, return nil.
199 If NEAREST is non-nil and an exact match was not found, find and return
200 the nearest available color.
202 (color,device,nearest))
204 Lisp_Object result = Qnil;
205 Lisp_Object console = Qnil;
206 Lisp_Object color_slist = Qnil;
207 Lisp_Object default_color_slist = Qnil;
208 Lisp_Object default_term_slist = Qnil;
209 Lisp_Object this_term_slist = Qnil;
210 Lisp_Object sym_color =Qnil;
211 Lisp_Object sym_term = Qnil;
213 if ( EQ(device,Qnil) ) {
214 device = Fselected_device(Qnil);
216 console=Fdevice_console(device);
217 if ( ! CONSOLEP(console) || ! CONSOLE_TYPE_P (XCONSOLE (console), tty) )
218 dead_wrong_type_argument(Qconsolep,console);
221 if( RECORD_TYPEP(color, lrecord_type_symbol) ) {
223 } else if ( RECORD_TYPEP(color, lrecord_type_string) ) {
224 sym_color = Fintern(color,Qnil);
226 dead_wrong_type_argument(Qstringp,color);
229 /* First check if there is a term-specific map */
230 this_term_slist = color_slist = CONSOLE_TTY_DATA(console)->term_cmap;
231 if ( ! EQ(color_slist,Qnil) ) {
232 result = Fget_skiplist(color_slist, sym_color, Qnil);
234 if ( EQ(result,Qnil) ) {
235 /* If not, let's try the term */
236 default_term_slist = color_slist =
237 get_term_color_alias_slist(
238 CONSOLE_TTY_DATA(console)->terminal_type,0);
239 if ( ! EQ(color_slist,Qnil) ) {
240 result = Fget_skiplist(color_slist, sym_color, Qnil);
243 if ( EQ(result,Qnil) ) {
244 /* Last resort: the default based on the colors */
246 int sz = snprintf(term_name,sizeof(term_name),"default-%d-color",
247 CONSOLE_TTY_DATA(console)->maxcolors);
248 assert(sz >= 0 && (size_t)sz < sizeof(term_name));
249 sym_term = Fintern(make_string((Bufbyte*)term_name,strlen(term_name)),Qnil);
250 default_color_slist = color_slist = get_term_color_alias_slist(sym_term,0);
251 if ( ! EQ(color_slist,Qnil) ) {
252 result = Fget_skiplist(color_slist, sym_color, Qnil);
255 if ( EQ(result,Qnil) && ! EQ(nearest, Qnil) ) {
256 Lisp_Object color_alist = Qnil;
257 Lisp_Object default_color_alist = Qnil;
258 Lisp_Object default_term_alist = Qnil;
259 Lisp_Object this_term_alist = Qnil;
260 Lisp_Object nearest_rgb = Qnil;
263 /* Lets build the supreme list :) Starting with the
264 * default color, then terminal name, then specific
265 * tty. This way we get actual override of color defs
266 * in the more specific definitions.
268 /* NOTE: sym_term was filled above... */
269 default_color_alist = color_alist = get_term_color_map_slist(sym_term,0);
270 args[0] = color_alist;
271 default_term_alist = args[1] =
272 get_term_color_map_slist(CONSOLE_TTY_DATA(console)->terminal_type,0);
273 if ( ! EQ(args[1],Qnil) ) {
274 color_alist = Fnconc(2,args);
275 args[0] = color_alist;
277 this_term_alist = args[1] = CONSOLE_TTY_DATA(console)->term_crgb;
278 if ( ! EQ(args[1],Qnil) ) {
279 color_alist = Fnconc(2,args);
281 if ( ! EQ(color_alist,Qnil) ) {
282 nearest_rgb = nearest_color_slist( sym_color, color_alist );
284 if ( ! EQ(nearest_rgb, Qnil) ) {
285 /* Let's find out where this result comes from ;-) */
287 if ( ! EQ(this_term_alist, Qnil) ) {
288 result = Fget_skiplist(this_term_alist, nearest_rgb, Qnil);
289 if ( ! EQ(result, Qnil) ) {
290 put_skiplist( XSKIPLIST(this_term_slist),sym_color,result);
291 CONSOLE_TTY_DATA(console)->term_cmap = this_term_slist;
295 if ( ! cached && ! EQ(default_term_alist, Qnil) &&
296 ! EQ(default_term_slist, Qnil) ) {
297 result = Fget_skiplist(default_term_alist, nearest_rgb, Qnil);
298 if ( ! EQ(result, Qnil) ) {
299 put_skiplist( XSKIPLIST(default_term_slist),sym_color,result);
300 put_skiplist( XSKIPLIST(Vterm_color_alias_slist),
301 CONSOLE_TTY_DATA(console)->terminal_type,
306 if ( ! cached && ! EQ(default_color_alist, Qnil) &&
307 ! EQ(default_color_slist, Qnil) ) {
308 result = Fget_skiplist(default_color_alist, nearest_rgb, Qnil);
309 if ( ! EQ(result, Qnil) ) {
310 put_skiplist( XSKIPLIST(default_color_slist),sym_color,result);
311 put_skiplist( XSKIPLIST(Vterm_color_alias_slist),
312 sym_term, default_color_slist);
323 DEFUN("tty-registered-color-list", Ftty_registered_color_list, 0, 1, 0, /*
324 Return a list of the registered TTY colors FOR DEVICE.
325 DEVICE defaults to the selected device if omitted.
329 Lisp_Object result = Qnil;
330 Lisp_Object console = Qnil;
331 Lisp_Object color_slist = Qnil;
333 if ( ! EQ(device,Qnil) ) {
334 device = Fselected_device(Qnil);
336 console=Fdevice_console(device);
337 /* First check if there is a term-specific map */
338 color_slist = CONSOLE_TTY_DATA(console)->term_cmap;
339 if ( EQ(color_slist,Qnil) ) {
340 /* If not, let's try the term */
341 color_slist = get_term_color_alias_slist(
342 CONSOLE_TTY_DATA(console)->terminal_type,0);
344 if ( EQ(color_slist,Qnil) ) {
345 /* Last resort: the default based on the colors */
347 Lisp_Object sym_term;
348 int sz = snprintf(term_name,sizeof(term_name),"default-%d-color",
349 CONSOLE_TTY_DATA(console)->maxcolors);
350 assert(sz>=0 && (size_t)sz < sizeof(term_name));
351 sym_term = Fintern(make_string((Bufbyte*)term_name,strlen(term_name)),Qnil);
352 color_slist = get_term_color_alias_slist(sym_term,0);
354 if ( ! EQ(color_slist,Qnil) ) {
355 map2_skiplist(XSKIPLIST(color_slist), tty_slist_keyname_accum, &result );
362 tty_initialize_color_instance(Lisp_Color_Instance * c, Lisp_Object name,
363 Lisp_Object device, Error_behavior errb)
365 /* This function does not GC */
367 Lisp_Object sym_color;
369 if( RECORD_TYPEP(name, lrecord_type_symbol) ) {
371 } else if ( RECORD_TYPEP(name, lrecord_type_string) ) {
372 sym_color = Fintern(name,Qnil);
374 dead_wrong_type_argument(Qstringp,name);
377 result = Ffind_tty_color( sym_color, device, Qt);
384 /* Don't allocate the data until we're sure that we will succeed. */
385 c->data = xnew(struct tty_color_instance_data);
390 COLOR_INSTANCE_TTY_SYMBOL(c) = sym_color;
394 static void tty_mark_color_instance(Lisp_Color_Instance * c)
396 if ( TTY_COLOR_INSTANCE_DATA(c) )
397 mark_object(COLOR_INSTANCE_TTY_SYMBOL(c));
401 tty_print_color_instance(Lisp_Color_Instance * c,
402 Lisp_Object printcharfun, int escapeflag)
406 static void tty_finalize_color_instance(Lisp_Color_Instance * c)
413 tty_color_instance_equal(Lisp_Color_Instance * c1,
414 Lisp_Color_Instance * c2, int depth)
416 return (EQ(COLOR_INSTANCE_TTY_SYMBOL(c1),
417 COLOR_INSTANCE_TTY_SYMBOL(c2)));
420 static unsigned long tty_color_instance_hash(Lisp_Color_Instance * c, int depth)
422 return LISP_HASH(COLOR_INSTANCE_TTY_SYMBOL(c));
425 static int tty_valid_color_name_p(struct device *d, Lisp_Object color)
427 return (!NILP(Ffind_tty_color( color, wrap_object(d), Qt)));
431 tty_initialize_font_instance(Lisp_Font_Instance * f, Lisp_Object name,
432 Lisp_Object device, Error_behavior errb)
434 Bufbyte *str = XSTRING_DATA(name);
435 Lisp_Object charset = Qnil;
437 if (strncmp((const char *)str, "normal", 6))
445 charset = Ffind_charset(intern((const char *)str));
453 /* Don't allocate the data until we're sure that we will succeed. */
454 f->data = xnew(struct tty_font_instance_data);
455 FONT_INSTANCE_TTY_CHARSET(f) = charset;
457 if (CHARSETP(charset))
458 f->width = XCHARSET_COLUMNS(charset);
463 f->proportional_p = 0;
464 f->ascent = f->height = 1;
470 static void tty_mark_font_instance(Lisp_Font_Instance * f)
472 mark_object(FONT_INSTANCE_TTY_CHARSET(f));
476 tty_print_font_instance(Lisp_Font_Instance * f,
477 Lisp_Object printcharfun, int escapeflag)
481 static void tty_finalize_font_instance(Lisp_Font_Instance * f)
487 static Lisp_Object tty_list_fonts(Lisp_Object pattern, Lisp_Object device)
489 return list1(build_string("normal"));
495 tty_font_spec_matches_charset(struct device *d, Lisp_Object charset,
496 const Bufbyte * nonreloc, Lisp_Object reloc,
497 Bytecount offset, Bytecount length)
499 const Bufbyte *the_nonreloc = nonreloc;
502 the_nonreloc = XSTRING_DATA(reloc);
503 fixup_internal_substring(nonreloc, reloc, offset, &length);
511 the_nonreloc += offset;
513 if (UNBOUNDP(charset))
514 return !memchr(the_nonreloc, '/', length);
515 the_nonreloc = (const Bufbyte *)memchr(the_nonreloc, '/', length);
520 Lisp_String *s = symbol_name(XSYMBOL(XCHARSET_NAME(charset)));
521 return !strcmp((const char *)the_nonreloc,
522 (const char *)string_data(s));
526 /* find a font spec that matches font spec FONT and also matches
527 (the registry of) CHARSET. */
529 tty_find_charset_font(Lisp_Object device, Lisp_Object font, Lisp_Object charset)
531 Bufbyte *fontname = XSTRING_DATA(font);
533 if (strchr((const char *)fontname, '/')) {
534 if (tty_font_spec_matches_charset(XDEVICE(device), charset, 0,
540 if (UNBOUNDP(charset))
543 return concat3(font, build_string("/"),
544 Fsymbol_name(XCHARSET_NAME(charset)));
549 /************************************************************************/
551 /************************************************************************/
553 void syms_of_objects_tty(void)
555 DEFSUBR(Fregister_tty_color_index);
556 DEFSUBR(Ffind_tty_color);
557 DEFSUBR(Ftty_registered_color_list);
558 defsymbol(&Qx_nearest_color, "x-nearest-color");
561 void console_type_create_objects_tty(void)
564 CONSOLE_HAS_METHOD(tty, initialize_color_instance);
565 CONSOLE_HAS_METHOD(tty, mark_color_instance);
566 CONSOLE_HAS_METHOD(tty, print_color_instance);
567 CONSOLE_HAS_METHOD(tty, finalize_color_instance);
568 CONSOLE_HAS_METHOD(tty, color_instance_equal);
569 CONSOLE_HAS_METHOD(tty, color_instance_hash);
570 CONSOLE_HAS_METHOD(tty, valid_color_name_p);
572 CONSOLE_HAS_METHOD(tty, initialize_font_instance);
573 CONSOLE_HAS_METHOD(tty, mark_font_instance);
574 CONSOLE_HAS_METHOD(tty, print_font_instance);
575 CONSOLE_HAS_METHOD(tty, finalize_font_instance);
576 CONSOLE_HAS_METHOD(tty, list_fonts);
578 CONSOLE_HAS_METHOD(tty, font_spec_matches_charset);
579 CONSOLE_HAS_METHOD(tty, find_charset_font);
583 void vars_of_objects_tty(void)
585 DEFVAR_LISP("term-color-alias-slist", &Vterm_color_alias_slist /*
586 Term => ( color => '(index bold) )
588 DEFVAR_LISP("term-color-map-slist", &Vterm_color_map_slist /*
589 Term => ( [r g b] => '(index bold) )
592 staticpro(&Vterm_color_alias_slist);
593 staticpro(&Vterm_color_map_slist);
595 Vterm_color_alias_slist = Qnil;
596 Vterm_color_map_slist = Qnil;