1 /* `dir', `vdir' and `ls' directory listing programs for GNU.
2 Copyright (C) 85, 88, 90, 91, 1995-2004 Free Software Foundation, Inc.
3
4 lscolors.c -- Taken from ls.c and modified for viewglob's purposes.
5 Copyright (C) 2004, 2005 Stephen Bach
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /* Written by Richard Stallman and David MacKenzie. */
22
23 /* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
24 Flaherty <dennisf@denix.elk.miles.com> based on original patches by
25 Greg Lee <lee@uhunix.uhcc.hawaii.edu>. */
26
27
28 #include "common.h"
29 #include "lscolors.h"
30 #include <string.h>
31 #include <pango/pango.h>
32 #include <gdk/gdk.h>
33 #include <math.h>
34
35 /* Null is a valid character in a color indicator (think about Epson
36 printers, for example) so we have to use a length/buffer string
37 type. */
38 struct bin_str {
39 size_t len; /* Number of bytes */
40 const char *string; /* Pointer to the same */
41 GString* gstr; /* Progress. */
42 };
43
44 struct color_ext_type
45 {
46 struct bin_str ext; /* The extension we're looking for. */
47 struct bin_str seq; /* The sequence to output when we do. */
48 TermTextAttr tta; /* The sequence in TermTextAttr form. */
49 struct color_ext_type *next; /* Next in list */
50 };
51
52
53 static void create_termtextattrs(void);
54 static void create_pangoattrlists(gint size_modifier);
55 static void termtextattr_init(TermTextAttr* tta);
56 static void termtextattr_copy(TermTextAttr* dest, TermTextAttr* src);
57 static void termtextattr_check_reverse(TermTextAttr* tta);
58 static gboolean are_equal(TermTextAttr* a, TermTextAttr* b);
59 static TermTextAttr* scan_types_for_equivalency(TermTextAttr* tta);
60 static TermTextAttr* scan_exts_for_equivalency(TermTextAttr* tta);
61 static void parse_codes(struct bin_str* s, TermTextAttr* attr);
62 static PangoAttrList* create_pango_list(TermTextAttr* tta, gint size_modifier);
63
64 /* Terminal colours map to the following. */
65
66 static GdkColor map[] = {
67 /* These work best on a light background */
68 { 0, 0x0000, 0x0000, 0x0000 }, /* TCC_NONE (not used) */
69 { 0, 0x0000, 0x0000, 0x0000 }, /* TCC_BLACK */
70 { 0, 0xc1c1, 0x1111, 0x2525 }, /* TCC_RED */
71 { 0, 0x5050, 0x8888, 0x1e1e }, /* TCC_GREEN */
72 { 0, 0xc4c4, 0xb4b4, 0x0000 }, /* TCC_YELLOW */
73 { 0, 0x1616, 0x6262, 0xa2a2 }, /* TCC_BLUE */
74 { 0, 0xefef, 0x7070, 0x9a9a }, /* TCC_MAGENTA */
75 { 0, 0x2c2c, 0xa3a3, 0xa4a4 }, /* TCC_CYAN */
76 { 0, 0xffff, 0xffff, 0xffff }, /* TCC_WHITE */
77 #if 0
78 /* These work best on a black background */
79 { 0, 0x0000, 0x0000, 0x0000 }, /* TCC_NONE (not used) */
80 { 0, 0x0000, 0x0000, 0x0000 }, /* TCC_BLACK */
81 { 0, 0x9e9e, 0x1818, 0x2828 }, /* TCC_RED */
82 { 0, 0xaeae, 0xcece, 0x9191 }, /* TCC_GREEN */
83 { 0, 0xffff, 0xf7f7, 0x9696 }, /* TCC_YELLOW */
84 { 0, 0x4141, 0x8686, 0xbebe }, /* TCC_BLUE */
85 { 0, 0x9696, 0x3c3c, 0x5959 }, /* TCC_MAGENTA */
86 { 0, 0x7171, 0xbebe, 0xbebe }, /* TCC_CYAN */
87 { 0, 0xffff, 0xffff, 0xffff }, /* TCC_WHITE */
88 #endif
89 };
90
91
92 /* Buffer for color sequences */
93 static char *color_buf;
94
95 static TermTextAttr type_ttas[FT_COUNT];
96
97 /* Reorganized these to correspond with FileType in file-types.h. */
98 static const char *const indicator_name[]= {
99 "fi", "ex", "di", "bd", "cd", "pi", "so", "ln", "lc",
100 "rc", "ec", "no", "mi", "or", "do", NULL
101 };
102
103 /* Reorganized to correspond with FileType in file-types.h. */
104 #define LEN_STR_PAIR(s) sizeof (s) - 1, s, NULL
105 #define COLOR_INDICATOR_SIZE 15
106 static struct bin_str color_indicator[] = {
107 { LEN_STR_PAIR ("0") }, /* fi: File: default */
108 { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */
109 { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */
110 { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */
111 { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */
112 { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */
113 { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */
114 { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */
115 { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */
116 { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */
117 { 0, NULL }, /* ec: End color (replaces lc+no+rc) */
118 { LEN_STR_PAIR ("0") }, /* no: Normal */
119 { 0, NULL }, /* mi: Missing file: undefined */
120 { 0, NULL }, /* or: Orphanned symlink: undefined */
121 { LEN_STR_PAIR ("01;35") } /* do: Door: bright magenta */
122 };
123
124
125 /* FIXME: comment */
126 static struct color_ext_type *color_ext_list = NULL;
127
128 /* Nonzero means use colors to mark types. Also define the different
129 colors as well as the stuff for the LS_COLORS environment variable.
130 The LS_COLORS variable is now in a termcap-like format. */
131 static int print_with_color;
132
133 static gboolean
get_funky_string(char ** dest,const char ** src,gboolean equals_end,size_t * output_count)134 get_funky_string (char **dest, const char **src, gboolean equals_end,
135 size_t *output_count)
136 {
137 int num; /* For numerical codes */
138 size_t count; /* Something to count with */
139 enum {
140 ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
141 } state;
142 const char *p;
143 char *q;
144
145 p = *src; /* We don't want to double-indirect */
146 q = *dest; /* the whole darn time. */
147
148 count = 0; /* No characters counted in yet. */
149 num = 0;
150
151 state = ST_GND; /* Start in ground state. */
152 while (state < ST_END)
153 {
154 switch (state)
155 {
156 case ST_GND: /* Ground state (no escapes) */
157 switch (*p)
158 {
159 case ':':
160 case '\0':
161 state = ST_END; /* End of string */
162 break;
163 case '\\':
164 state = ST_BACKSLASH; /* Backslash scape sequence */
165 ++p;
166 break;
167 case '^':
168 state = ST_CARET; /* Caret escape */
169 ++p;
170 break;
171 case '=':
172 if (equals_end)
173 {
174 state = ST_END; /* End */
175 break;
176 }
177 /* else fall through */
178 default:
179 *(q++) = *(p++);
180 ++count;
181 break;
182 }
183 break;
184
185 case ST_BACKSLASH: /* Backslash escaped character */
186 switch (*p)
187 {
188 case '0':
189 case '1':
190 case '2':
191 case '3':
192 case '4':
193 case '5':
194 case '6':
195 case '7':
196 state = ST_OCTAL; /* Octal sequence */
197 num = *p - '0';
198 break;
199 case 'x':
200 case 'X':
201 state = ST_HEX; /* Hex sequence */
202 num = 0;
203 break;
204 case 'a': /* Bell */
205 num = 7; /* Not all C compilers know what \a means */
206 break;
207 case 'b': /* Backspace */
208 num = '\b';
209 break;
210 case 'e': /* Escape */
211 num = 27;
212 break;
213 case 'f': /* Form feed */
214 num = '\f';
215 break;
216 case 'n': /* Newline */
217 num = '\n';
218 break;
219 case 'r': /* Carriage return */
220 num = '\r';
221 break;
222 case 't': /* Tab */
223 num = '\t';
224 break;
225 case 'v': /* Vtab */
226 num = '\v';
227 break;
228 case '?': /* Delete */
229 num = 127;
230 break;
231 case '_': /* Space */
232 num = ' ';
233 break;
234 case '\0': /* End of string */
235 state = ST_ERROR; /* Error! */
236 break;
237 default: /* Escaped character like \ ^ : = */
238 num = *p;
239 break;
240 }
241 if (state == ST_BACKSLASH)
242 {
243 *(q++) = num;
244 ++count;
245 state = ST_GND;
246 }
247 ++p;
248 break;
249
250 case ST_OCTAL: /* Octal sequence */
251 if (*p < '0' || *p > '7')
252 {
253 *(q++) = num;
254 ++count;
255 state = ST_GND;
256 }
257 else
258 num = (num << 3) + (*(p++) - '0');
259 break;
260
261 case ST_HEX: /* Hex sequence */
262 switch (*p)
263 {
264 case '0':
265 case '1':
266 case '2':
267 case '3':
268 case '4':
269 case '5':
270 case '6':
271 case '7':
272 case '8':
273 case '9':
274 num = (num << 4) + (*(p++) - '0');
275 break;
276 case 'a':
277 case 'b':
278 case 'c':
279 case 'd':
280 case 'e':
281 case 'f':
282 num = (num << 4) + (*(p++) - 'a') + 10;
283 break;
284 case 'A':
285 case 'B':
286 case 'C':
287 case 'D':
288 case 'E':
289 case 'F':
290 num = (num << 4) + (*(p++) - 'A') + 10;
291 break;
292 default:
293 *(q++) = num;
294 ++count;
295 state = ST_GND;
296 break;
297 }
298 break;
299
300 case ST_CARET: /* Caret escape */
301 state = ST_GND; /* Should be the next state... */
302 if (*p >= '@' && *p <= '~')
303 {
304 *(q++) = *(p++) & 037;
305 ++count;
306 }
307 else if (*p == '?')
308 {
309 *(q++) = 127;
310 ++count;
311 }
312 else
313 state = ST_ERROR;
314 break;
315
316 default:
317 abort ();
318 }
319 }
320
321 *dest = q;
322 *src = p;
323 *output_count = count;
324
325 return state != ST_ERROR;
326 }
327
328 void
parse_ls_colors(gint size_modifier)329 parse_ls_colors (gint size_modifier)
330 {
331 const char *p; /* Pointer to character being parsed */
332 char *buf; /* color_buf buffer pointer */
333 int state; /* State of parser */
334 int ind_no; /* Indicator number */
335 char label[3]; /* Indicator label */
336 struct color_ext_type *ext; /* Extension we are working on */
337
338 if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0')
339 return;
340
341 ext = NULL;
342 strcpy (label, "??");
343
344 /* This is an overly conservative estimate, but any possible
345 LS_COLORS string will *not* generate a color_buf longer than
346 itself, so it is a safe way of allocating a buffer in
347 advance. */
348 buf = color_buf = g_strdup (p);
349
350 state = 1;
351 while (state > 0)
352 {
353 switch (state)
354 {
355 case 1: /* First label character */
356 switch (*p)
357 {
358 case ':':
359 ++p;
360 break;
361
362 case '*':
363 /* Allocate new extension block and add to head of
364 linked list (this way a later definition will
365 override an earlier one, which can be useful for
366 having terminal-specific defs override global). */
367
368 ext = g_new(struct color_ext_type, 1);
369 ext->next = color_ext_list;
370 color_ext_list = ext;
371
372 ++p;
373 ext->ext.string = buf;
374
375 state = (get_funky_string (&buf, &p, TRUE, &ext->ext.len)
376 ? 4 : -1);
377 break;
378
379 case '\0':
380 state = 0; /* Done! */
381 break;
382
383 default: /* Assume it is file type label */
384 label[0] = *(p++);
385 state = 2;
386 break;
387 }
388 break;
389
390 case 2: /* Second label character */
391 if (*p)
392 {
393 label[1] = *(p++);
394 state = 3;
395 }
396 else
397 state = -1; /* Error */
398 break;
399
400 case 3: /* Equal sign after indicator label */
401 state = -1; /* Assume failure... */
402 if (*(p++) == '=')/* It *should* be... */
403 {
404 for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
405 {
406 if (STREQ (label, indicator_name[ind_no]))
407 {
408 color_indicator[ind_no].string = buf;
409 state = (get_funky_string (&buf, &p, FALSE,
410 &color_indicator[ind_no].len)
411 ? 1 : -1);
412 break;
413 }
414 }
415 if (state == -1)
416 g_printerr("gviewglob: Unrecognized LS_COLORS prefix: \"%s\".\n", label);
417 }
418 break;
419
420 case 4: /* Equal sign after *.ext */
421 if (*(p++) == '=')
422 {
423 ext->seq.string = buf;
424 state = (get_funky_string (&buf, &p, FALSE, &ext->seq.len)
425 ? 1 : -1);
426 }
427 else
428 state = -1;
429 break;
430 }
431 }
432
433 if (state < 0)
434 {
435 struct color_ext_type *e;
436 struct color_ext_type *e2;
437
438 g_printerr("gviewglob: Unparsable value for LS_COLORS environment variable.\n");
439 g_free (color_buf);
440 for (e = color_ext_list; e != NULL; /* empty */)
441 {
442 e2 = e;
443 e = e->next;
444 g_free (e2);
445 }
446 print_with_color = 0;
447 }
448
449 /* Dealing with bin_str is very tiresome. Convert
450 to useable GStrings. */
451 int i;
452 struct color_ext_type* iter;
453 for (i = 0; i < COLOR_INDICATOR_SIZE; i++) {
454 color_indicator[i].gstr = g_string_new_len(
455 color_indicator[i].string,
456 color_indicator[i].len);
457 }
458 for (iter = color_ext_list; iter; iter = iter->next) {
459 iter->ext.gstr = g_string_new_len(iter->ext.string, iter->ext.len);
460 iter->seq.gstr = g_string_new_len(iter->seq.string, iter->seq.len);
461 }
462
463 create_termtextattrs();
464 create_pangoattrlists(size_modifier);
465 }
466
467
468 /* Create TermTextAttrs from the terminal colouring sequences. */
create_termtextattrs(void)469 static void create_termtextattrs(void) {
470
471 TermTextAttr normal;
472 int i;
473
474 /* Initialize "no", just in case it's not included
475 in LS_COLORS. */
476 termtextattr_init(&normal);
477
478 parse_codes(&color_indicator[11], &normal); /* "no" */
479
480 /* All file types inherit from "no". */
481 for (i = 0; i < FT_COUNT; i++) {
482 termtextattr_copy(&type_ttas[i], &normal);
483 parse_codes(&color_indicator[i], &type_ttas[i]);
484 }
485
486 /* Now do the extensions. */
487 struct color_ext_type* iter;
488 for (iter = color_ext_list; iter; iter = iter->next) {
489 /* Extensions only apply to regular files, apparently. */
490 termtextattr_copy(&iter->tta, &type_ttas[FT_REGULAR]);
491 parse_codes(&iter->seq, &iter->tta);
492 termtextattr_check_reverse(&iter->tta);
493 }
494
495 /* It's safe to reverse the file types now (if necessary). */
496 for (i = 0; i < FT_COUNT; i++)
497 termtextattr_check_reverse(&type_ttas[i]);
498 }
499
500
501 /* Create PangoAttrLists from the TermTextAttrs. */
create_pangoattrlists(gint size_modifier)502 static void create_pangoattrlists(gint size_modifier) {
503 TermTextAttr* match;
504 struct color_ext_type* iter;
505 int i;
506
507 for (i = 0; i < FT_COUNT; i++) {
508 /* It's safe to reverse the file types now (if necessary). */
509 termtextattr_check_reverse(&type_ttas[i]);
510 match = scan_types_for_equivalency(&type_ttas[i]);
511 if (match)
512 type_ttas[i].p_list = match->p_list;
513 else
514 type_ttas[i].p_list = create_pango_list(&type_ttas[i], size_modifier);
515 }
516 for (iter = color_ext_list; iter; iter = iter->next) {
517 match = scan_exts_for_equivalency(&iter->tta);
518 if (match)
519 iter->tta.p_list = match->p_list;
520 else
521 iter->tta.p_list = create_pango_list(&iter->tta, size_modifier);
522 }
523 }
524
525
526 /* If the given TermTextAttr has TAC_REVERSE, reverse its colors. */
termtextattr_check_reverse(TermTextAttr * tta)527 static void termtextattr_check_reverse(TermTextAttr* tta) {
528
529 if (tta->attr & TAC_REVERSE) {
530 /* Switch foreground with background. */
531 enum term_color_code temp;
532 temp = tta->fg;
533 tta->fg = tta->bg;
534 tta->bg = temp;
535
536 /* Remove TAC_REVERSE now that it's been applied. */
537 tta->attr &= (~TAC_REVERSE);
538 }
539 }
540
541
542 /* Parse the code sequences in s and convert to a TermTextAttr. */
parse_codes(struct bin_str * s,TermTextAttr * tta)543 static void parse_codes(struct bin_str* s, TermTextAttr* tta) {
544
545 ptrdiff_t pos = 0;
546 char* endptr = NULL;
547 long code;
548
549 while (pos < s->len) {
550 code = strtol(s->gstr->str + pos, &endptr, 10);
551 if (s->gstr->str + pos == endptr) {
552 /* Did not convert any characters. */
553 if (pos + 1 == s->len) {
554 /* We're at the end of the string. */
555 break;
556 }
557 else {
558 /* It's just a separator or something. Skip it. */
559 pos++;
560 }
561 }
562 else {
563 /* Got a code -- let's see what it is. */
564 pos = endptr - s->gstr->str;
565 switch (code) {
566 case 0:
567 tta->attr = 0;
568 break;
569 case 1:
570 tta->attr |= TAC_BOLD;
571 break;
572 case 4:
573 tta->attr |= TAC_UNDERSCORE;
574 break;
575 case 7:
576 tta->attr |= TAC_REVERSE;
577 break;
578 case 30:
579 tta->fg = TCC_BLACK;
580 break;
581 case 31:
582 tta->fg = TCC_RED;
583 break;
584 case 32:
585 tta->fg = TCC_GREEN;
586 break;
587 case 33:
588 tta->fg = TCC_YELLOW;
589 break;
590 case 34:
591 tta->fg = TCC_BLUE;
592 break;
593 case 35:
594 tta->fg = TCC_MAGENTA;
595 break;
596 case 36:
597 tta->fg = TCC_CYAN;
598 break;
599 case 37:
600 tta->fg = TCC_WHITE;
601 break;
602 case 40:
603 tta->bg = TCC_BLACK;
604 break;
605 case 41:
606 tta->bg = TCC_RED;
607 break;
608 case 42:
609 tta->bg = TCC_GREEN;
610 break;
611 case 43:
612 tta->bg = TCC_YELLOW;
613 break;
614 case 44:
615 tta->bg = TCC_BLUE;
616 break;
617 case 45:
618 tta->bg = TCC_MAGENTA;
619 break;
620 case 46:
621 tta->bg = TCC_CYAN;
622 break;
623 case 47:
624 tta->bg = TCC_WHITE;
625 break;
626 }
627 }
628 }
629 }
630
631
632 /* Initialize the given TermTextAttr. */
termtextattr_init(TermTextAttr * tta)633 static void termtextattr_init(TermTextAttr* tta) {
634 tta->fg = TCC_NONE;
635 tta->bg = TCC_NONE;
636 tta->attr = 0;
637 tta->p_list = NULL;
638 }
639
640
641 /* Copy the attribute fields in src to the fields in dest. */
termtextattr_copy(TermTextAttr * dest,TermTextAttr * src)642 static void termtextattr_copy(TermTextAttr* dest, TermTextAttr* src) {
643 dest->fg = src->fg;
644 dest->bg = src->bg;
645 dest->attr = src->attr;
646 dest->p_list = NULL; /* Don't copy this one. */
647 }
648
649
650 /* Scan through the type_ttas array for a matching tta. */
scan_types_for_equivalency(TermTextAttr * tta)651 static TermTextAttr* scan_types_for_equivalency(TermTextAttr* tta) {
652 int i;
653 TermTextAttr* retval = NULL;
654
655 for (i = 0; i < FT_COUNT; i++) {
656 if (tta == &type_ttas[i]) {
657 /* We've reached ourselves, so we're done. */
658 break;
659 }
660 if (are_equal(tta, &type_ttas[i])) {
661 retval = &type_ttas[i];
662 break;
663 }
664 }
665 return retval;
666 }
667
668
669 /* Scan throught the color_ext_list list for a matching tta. */
scan_exts_for_equivalency(TermTextAttr * tta)670 static TermTextAttr* scan_exts_for_equivalency(TermTextAttr* tta) {
671 struct color_ext_type* iter;
672 TermTextAttr* retval = NULL;
673
674 for (iter = color_ext_list; iter; iter = iter->next) {
675 if (&iter->tta == tta) {
676 /* We've reached ourselves, so we're done. */
677 break;
678 }
679 else if (are_equal(tta, &iter->tta)) {
680 retval = &iter->tta;
681 break;
682 }
683 }
684 return retval;
685 }
686
687
688 /* Compares the given TermTextAttrs for equivalency. */
are_equal(TermTextAttr * a,TermTextAttr * b)689 static gboolean are_equal(TermTextAttr* a, TermTextAttr* b) {
690 gboolean is_same = TRUE;
691 is_same &= a->fg == b->fg;
692 is_same &= a->bg == b->bg;
693 is_same &= a->attr == b->attr;
694
695 return is_same;
696 }
697
698
699 /* Convert the given TermTextAttr into a PangoAttrList. */
create_pango_list(TermTextAttr * tta,gint size_modifier)700 static PangoAttrList* create_pango_list(TermTextAttr* tta, gint size_modifier) {
701
702 PangoAttribute* p_attr;
703 PangoAttrList* p_list = pango_attr_list_new();
704 gboolean list_set = FALSE;
705 gdouble scale_factor;
706
707 /* First set the font size. */
708 if (size_modifier != 0) {
709 if (size_modifier > 0)
710 scale_factor = pow(PANGO_SCALE_LARGE, size_modifier);
711 else
712 scale_factor = pow(PANGO_SCALE_SMALL, -size_modifier);
713 p_attr = pango_attr_scale_new(scale_factor);
714 p_attr->start_index = 0;
715 p_attr->end_index = G_MAXINT;
716 pango_attr_list_insert(p_list, p_attr);
717 list_set = TRUE;
718 }
719
720 /* Foreground colour is not set through Pango so that
721 its color can change when active or selected
722 (see label_set_attributes()). */
723
724 /* Background colour */
725 if (tta->bg > TCC_NONE && tta->bg <= TCC_WHITE) {
726 p_attr = pango_attr_background_new(
727 map[tta->bg].red,
728 map[tta->bg].green,
729 map[tta->bg].blue);
730 p_attr->start_index = 0;
731 p_attr->end_index = G_MAXINT;
732 pango_attr_list_insert(p_list, p_attr);
733 list_set = TRUE;
734 }
735
736
737 /* Bold */
738 if (tta->attr & TAC_BOLD) {
739 p_attr = pango_attr_weight_new(PANGO_WEIGHT_HEAVY);
740 p_attr->start_index = 0;
741 p_attr->end_index = G_MAXINT;
742 pango_attr_list_insert(p_list, p_attr);
743 list_set = TRUE;
744 }
745
746 /* Underscore */
747 if (tta->attr & TAC_UNDERSCORE) {
748 p_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
749 p_attr->start_index = 0;
750 p_attr->end_index = G_MAXINT;
751 pango_attr_list_insert(p_list, p_attr);
752 list_set = TRUE;
753 }
754
755 if (list_set) {
756 /* Probably don't need to do this, but it doesn't hurt since
757 the attribute lists are valid through the life of the program. */
758 pango_attr_list_ref(p_list);
759 }
760 else {
761 pango_attr_list_unref(p_list);
762 p_list = NULL;
763 }
764
765 return p_list;
766 }
767
768
769 /* Get a PangoAttrList for this label, based on its name and type. */
label_set_attributes(gchar * name,FileType type,GtkLabel * label)770 void label_set_attributes(gchar* name, FileType type, GtkLabel* label) {
771
772 PangoAttrList* p_list;
773 TermTextAttr* tta;
774
775 tta = &type_ttas[type];
776
777 p_list = tta->p_list;
778 if (type == FT_REGULAR) {
779 struct color_ext_type* iter;
780 for (iter = color_ext_list; iter; iter = iter->next) {
781 if (g_str_has_suffix(name, iter->ext.gstr->str)) {
782 tta = &iter->tta;
783 p_list = tta->p_list;
784 break;
785 }
786 }
787 }
788
789 if (p_list)
790 gtk_label_set_attributes(label, p_list);
791
792 /* Foreground colour */
793 if (tta->fg > TCC_NONE && tta->fg <= TCC_WHITE) {
794 gtk_widget_modify_fg(
795 GTK_WIDGET(label), GTK_STATE_NORMAL,&map[tta->fg]);
796 /*gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_ACTIVE, &color);*/
797 }
798 }
799
800
set_color(enum term_color_code code,GdkColor * color)801 void set_color(enum term_color_code code, GdkColor* color) {
802 map[code].red = color->red;
803 map[code].green = color->green;
804 map[code].blue = color->blue;
805 }
806
807