1*0a6a1f1dSLionel Sambuc /* Id */
2eda6f593SDavid van Moolenbroek
3eda6f593SDavid van Moolenbroek /*
4eda6f593SDavid van Moolenbroek * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
5eda6f593SDavid van Moolenbroek *
6eda6f593SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
7eda6f593SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8eda6f593SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9eda6f593SDavid van Moolenbroek *
10eda6f593SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eda6f593SDavid van Moolenbroek * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eda6f593SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eda6f593SDavid van Moolenbroek * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eda6f593SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15eda6f593SDavid van Moolenbroek * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16eda6f593SDavid van Moolenbroek * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eda6f593SDavid van Moolenbroek */
18eda6f593SDavid van Moolenbroek
19eda6f593SDavid van Moolenbroek #include <sys/types.h>
20eda6f593SDavid van Moolenbroek
21eda6f593SDavid van Moolenbroek #include <ctype.h>
22eda6f593SDavid van Moolenbroek #include <stdlib.h>
23eda6f593SDavid van Moolenbroek #include <string.h>
24eda6f593SDavid van Moolenbroek
25eda6f593SDavid van Moolenbroek #include "tmux.h"
26eda6f593SDavid van Moolenbroek
27eda6f593SDavid van Moolenbroek /*
28eda6f593SDavid van Moolenbroek * Colour to string conversion functions. Bit 8 of the colour means it is one
29eda6f593SDavid van Moolenbroek * of the 256 colour palette.
30eda6f593SDavid van Moolenbroek */
31eda6f593SDavid van Moolenbroek
32eda6f593SDavid van Moolenbroek /* An RGB colour. */
33eda6f593SDavid van Moolenbroek struct colour_rgb {
34eda6f593SDavid van Moolenbroek u_char r;
35eda6f593SDavid van Moolenbroek u_char g;
36eda6f593SDavid van Moolenbroek u_char b;
37eda6f593SDavid van Moolenbroek };
38eda6f593SDavid van Moolenbroek
39eda6f593SDavid van Moolenbroek /* 256 colour RGB table, generated on first use. */
40eda6f593SDavid van Moolenbroek struct colour_rgb *colour_rgb_256;
41eda6f593SDavid van Moolenbroek
42eda6f593SDavid van Moolenbroek void colour_rgb_generate256(void);
43eda6f593SDavid van Moolenbroek u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
44eda6f593SDavid van Moolenbroek int colour_rgb_find(struct colour_rgb *);
45eda6f593SDavid van Moolenbroek
46eda6f593SDavid van Moolenbroek /* Generate 256 colour RGB table. */
47eda6f593SDavid van Moolenbroek void
colour_rgb_generate256(void)48eda6f593SDavid van Moolenbroek colour_rgb_generate256(void)
49eda6f593SDavid van Moolenbroek {
50eda6f593SDavid van Moolenbroek struct colour_rgb *rgb;
51eda6f593SDavid van Moolenbroek u_int i, r, g, b;
52eda6f593SDavid van Moolenbroek
53eda6f593SDavid van Moolenbroek /*
54eda6f593SDavid van Moolenbroek * Allocate the table. The first 16 colours are often changed by users
55eda6f593SDavid van Moolenbroek * and terminals so don't include them.
56eda6f593SDavid van Moolenbroek */
57eda6f593SDavid van Moolenbroek colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256);
58eda6f593SDavid van Moolenbroek
59eda6f593SDavid van Moolenbroek /* Add the colours first. */
60eda6f593SDavid van Moolenbroek r = g = b = 0;
61eda6f593SDavid van Moolenbroek for (i = 240; i > 24; i--) {
62eda6f593SDavid van Moolenbroek rgb = &colour_rgb_256[240 - i];
63eda6f593SDavid van Moolenbroek
64eda6f593SDavid van Moolenbroek if (r != 0)
65eda6f593SDavid van Moolenbroek rgb->r = (r * 40) + 55;
66eda6f593SDavid van Moolenbroek if (g != 0)
67eda6f593SDavid van Moolenbroek rgb->g = (g * 40) + 55;
68eda6f593SDavid van Moolenbroek if (b != 0)
69eda6f593SDavid van Moolenbroek rgb->b = (b * 40) + 55;
70eda6f593SDavid van Moolenbroek
71eda6f593SDavid van Moolenbroek b++;
72eda6f593SDavid van Moolenbroek if (b > 5) {
73eda6f593SDavid van Moolenbroek b = 0;
74eda6f593SDavid van Moolenbroek g++;
75eda6f593SDavid van Moolenbroek }
76eda6f593SDavid van Moolenbroek if (g > 5) {
77eda6f593SDavid van Moolenbroek g = 0;
78eda6f593SDavid van Moolenbroek r++;
79eda6f593SDavid van Moolenbroek }
80eda6f593SDavid van Moolenbroek }
81eda6f593SDavid van Moolenbroek
82eda6f593SDavid van Moolenbroek /* Then add the greys. */
83eda6f593SDavid van Moolenbroek for (i = 24; i > 0; i--) {
84eda6f593SDavid van Moolenbroek rgb = &colour_rgb_256[240 - i];
85eda6f593SDavid van Moolenbroek
86eda6f593SDavid van Moolenbroek rgb->r = 8 + (24 - i) * 10;
87eda6f593SDavid van Moolenbroek rgb->g = 8 + (24 - i) * 10;
88eda6f593SDavid van Moolenbroek rgb->b = 8 + (24 - i) * 10;
89eda6f593SDavid van Moolenbroek }
90eda6f593SDavid van Moolenbroek }
91eda6f593SDavid van Moolenbroek
92*0a6a1f1dSLionel Sambuc /* Get colour RGB distance. */
93eda6f593SDavid van Moolenbroek u_int
colour_rgb_distance(struct colour_rgb * rgb1,struct colour_rgb * rgb2)94eda6f593SDavid van Moolenbroek colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
95eda6f593SDavid van Moolenbroek {
96eda6f593SDavid van Moolenbroek int r, g, b;
97eda6f593SDavid van Moolenbroek
98eda6f593SDavid van Moolenbroek r = rgb1->r - rgb2->r;
99eda6f593SDavid van Moolenbroek g = rgb1->g - rgb2->g;
100eda6f593SDavid van Moolenbroek b = rgb1->b - rgb2->b;
101eda6f593SDavid van Moolenbroek return (r * r + g * g + b * b);
102eda6f593SDavid van Moolenbroek }
103eda6f593SDavid van Moolenbroek
104eda6f593SDavid van Moolenbroek /* Work out the nearest colour from the 256 colour set. */
105eda6f593SDavid van Moolenbroek int
colour_rgb_find(struct colour_rgb * rgb)106eda6f593SDavid van Moolenbroek colour_rgb_find(struct colour_rgb *rgb)
107eda6f593SDavid van Moolenbroek {
108*0a6a1f1dSLionel Sambuc u_int distance, lowest, colour, i;
109eda6f593SDavid van Moolenbroek
110eda6f593SDavid van Moolenbroek if (colour_rgb_256 == NULL)
111eda6f593SDavid van Moolenbroek colour_rgb_generate256();
112eda6f593SDavid van Moolenbroek
113eda6f593SDavid van Moolenbroek colour = 16;
114eda6f593SDavid van Moolenbroek lowest = UINT_MAX;
115eda6f593SDavid van Moolenbroek for (i = 0; i < 240; i++) {
116eda6f593SDavid van Moolenbroek distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
117eda6f593SDavid van Moolenbroek if (distance < lowest) {
118eda6f593SDavid van Moolenbroek lowest = distance;
119eda6f593SDavid van Moolenbroek colour = 16 + i;
120eda6f593SDavid van Moolenbroek }
121eda6f593SDavid van Moolenbroek }
122eda6f593SDavid van Moolenbroek return (colour);
123eda6f593SDavid van Moolenbroek }
124eda6f593SDavid van Moolenbroek
125eda6f593SDavid van Moolenbroek /* Set grid cell foreground colour. */
126eda6f593SDavid van Moolenbroek void
colour_set_fg(struct grid_cell * gc,int c)127eda6f593SDavid van Moolenbroek colour_set_fg(struct grid_cell *gc, int c)
128eda6f593SDavid van Moolenbroek {
129eda6f593SDavid van Moolenbroek if (c & 0x100)
130eda6f593SDavid van Moolenbroek gc->flags |= GRID_FLAG_FG256;
131eda6f593SDavid van Moolenbroek gc->fg = c;
132eda6f593SDavid van Moolenbroek }
133eda6f593SDavid van Moolenbroek
134eda6f593SDavid van Moolenbroek /* Set grid cell background colour. */
135eda6f593SDavid van Moolenbroek void
colour_set_bg(struct grid_cell * gc,int c)136eda6f593SDavid van Moolenbroek colour_set_bg(struct grid_cell *gc, int c)
137eda6f593SDavid van Moolenbroek {
138eda6f593SDavid van Moolenbroek if (c & 0x100)
139eda6f593SDavid van Moolenbroek gc->flags |= GRID_FLAG_BG256;
140eda6f593SDavid van Moolenbroek gc->bg = c;
141eda6f593SDavid van Moolenbroek }
142eda6f593SDavid van Moolenbroek
143eda6f593SDavid van Moolenbroek /* Convert colour to a string. */
144eda6f593SDavid van Moolenbroek const char *
colour_tostring(int c)145eda6f593SDavid van Moolenbroek colour_tostring(int c)
146eda6f593SDavid van Moolenbroek {
147eda6f593SDavid van Moolenbroek static char s[32];
148eda6f593SDavid van Moolenbroek
149eda6f593SDavid van Moolenbroek if (c & 0x100) {
150eda6f593SDavid van Moolenbroek xsnprintf(s, sizeof s, "colour%u", c & ~0x100);
151eda6f593SDavid van Moolenbroek return (s);
152eda6f593SDavid van Moolenbroek }
153eda6f593SDavid van Moolenbroek
154eda6f593SDavid van Moolenbroek switch (c) {
155eda6f593SDavid van Moolenbroek case 0:
156eda6f593SDavid van Moolenbroek return ("black");
157eda6f593SDavid van Moolenbroek case 1:
158eda6f593SDavid van Moolenbroek return ("red");
159eda6f593SDavid van Moolenbroek case 2:
160eda6f593SDavid van Moolenbroek return ("green");
161eda6f593SDavid van Moolenbroek case 3:
162eda6f593SDavid van Moolenbroek return ("yellow");
163eda6f593SDavid van Moolenbroek case 4:
164eda6f593SDavid van Moolenbroek return ("blue");
165eda6f593SDavid van Moolenbroek case 5:
166eda6f593SDavid van Moolenbroek return ("magenta");
167eda6f593SDavid van Moolenbroek case 6:
168eda6f593SDavid van Moolenbroek return ("cyan");
169eda6f593SDavid van Moolenbroek case 7:
170eda6f593SDavid van Moolenbroek return ("white");
171eda6f593SDavid van Moolenbroek case 8:
172eda6f593SDavid van Moolenbroek return ("default");
173*0a6a1f1dSLionel Sambuc case 90:
174*0a6a1f1dSLionel Sambuc return ("brightblack");
175*0a6a1f1dSLionel Sambuc case 91:
176*0a6a1f1dSLionel Sambuc return ("brightred");
177*0a6a1f1dSLionel Sambuc case 92:
178*0a6a1f1dSLionel Sambuc return ("brightgreen");
179*0a6a1f1dSLionel Sambuc case 93:
180*0a6a1f1dSLionel Sambuc return ("brightyellow");
181*0a6a1f1dSLionel Sambuc case 94:
182*0a6a1f1dSLionel Sambuc return ("brightblue");
183*0a6a1f1dSLionel Sambuc case 95:
184*0a6a1f1dSLionel Sambuc return ("brightmagenta");
185*0a6a1f1dSLionel Sambuc case 96:
186*0a6a1f1dSLionel Sambuc return ("brightcyan");
187*0a6a1f1dSLionel Sambuc case 97:
188*0a6a1f1dSLionel Sambuc return ("brightwhite");
189eda6f593SDavid van Moolenbroek }
190eda6f593SDavid van Moolenbroek return (NULL);
191eda6f593SDavid van Moolenbroek }
192eda6f593SDavid van Moolenbroek
193eda6f593SDavid van Moolenbroek /* Convert colour from string. */
194eda6f593SDavid van Moolenbroek int
colour_fromstring(const char * s)195eda6f593SDavid van Moolenbroek colour_fromstring(const char *s)
196eda6f593SDavid van Moolenbroek {
197eda6f593SDavid van Moolenbroek const char *errstr;
198eda6f593SDavid van Moolenbroek const char *cp;
199eda6f593SDavid van Moolenbroek struct colour_rgb rgb;
200eda6f593SDavid van Moolenbroek int n;
201eda6f593SDavid van Moolenbroek
202eda6f593SDavid van Moolenbroek if (*s == '#' && strlen(s) == 7) {
203eda6f593SDavid van Moolenbroek for (cp = s + 1; isxdigit((u_char) *cp); cp++)
204eda6f593SDavid van Moolenbroek ;
205eda6f593SDavid van Moolenbroek if (*cp != '\0')
206eda6f593SDavid van Moolenbroek return (-1);
207eda6f593SDavid van Moolenbroek n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b);
208eda6f593SDavid van Moolenbroek if (n != 3)
209eda6f593SDavid van Moolenbroek return (-1);
210eda6f593SDavid van Moolenbroek return (colour_rgb_find(&rgb) | 0x100);
211eda6f593SDavid van Moolenbroek }
212eda6f593SDavid van Moolenbroek
213eda6f593SDavid van Moolenbroek if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
214eda6f593SDavid van Moolenbroek n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
215eda6f593SDavid van Moolenbroek if (errstr != NULL)
216eda6f593SDavid van Moolenbroek return (-1);
217eda6f593SDavid van Moolenbroek return (n | 0x100);
218eda6f593SDavid van Moolenbroek }
219eda6f593SDavid van Moolenbroek
220eda6f593SDavid van Moolenbroek if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0'))
221eda6f593SDavid van Moolenbroek return (0);
222eda6f593SDavid van Moolenbroek if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0'))
223eda6f593SDavid van Moolenbroek return (1);
224eda6f593SDavid van Moolenbroek if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0'))
225eda6f593SDavid van Moolenbroek return (2);
226eda6f593SDavid van Moolenbroek if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0'))
227eda6f593SDavid van Moolenbroek return (3);
228eda6f593SDavid van Moolenbroek if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0'))
229eda6f593SDavid van Moolenbroek return (4);
230eda6f593SDavid van Moolenbroek if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0'))
231eda6f593SDavid van Moolenbroek return (5);
232eda6f593SDavid van Moolenbroek if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0'))
233eda6f593SDavid van Moolenbroek return (6);
234eda6f593SDavid van Moolenbroek if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0'))
235eda6f593SDavid van Moolenbroek return (7);
236eda6f593SDavid van Moolenbroek if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
237eda6f593SDavid van Moolenbroek return (8);
238*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightblack") == 0 ||
239*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '0' && s[1] == '\0'))
240*0a6a1f1dSLionel Sambuc return (90);
241*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightred") == 0 ||
242*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '1' && s[1] == '\0'))
243*0a6a1f1dSLionel Sambuc return (91);
244*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightgreen") == 0 ||
245*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '2' && s[1] == '\0'))
246*0a6a1f1dSLionel Sambuc return (92);
247*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightyellow") == 0 ||
248*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '3' && s[1] == '\0'))
249*0a6a1f1dSLionel Sambuc return (93);
250*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightblue") == 0 ||
251*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '4' && s[1] == '\0'))
252*0a6a1f1dSLionel Sambuc return (94);
253*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightmagenta") == 0 ||
254*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '5' && s[1] == '\0'))
255*0a6a1f1dSLionel Sambuc return (95);
256*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightcyan") == 0 ||
257*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '6' && s[1] == '\0'))
258*0a6a1f1dSLionel Sambuc return (96);
259*0a6a1f1dSLionel Sambuc if (strcasecmp(s, "brightwhite") == 0 ||
260*0a6a1f1dSLionel Sambuc (s[0] == '9' && s[1] == '7' && s[1] == '\0'))
261*0a6a1f1dSLionel Sambuc return (97);
262eda6f593SDavid van Moolenbroek return (-1);
263eda6f593SDavid van Moolenbroek }
264eda6f593SDavid van Moolenbroek
265eda6f593SDavid van Moolenbroek /* Convert 256 colour palette to 16. */
266eda6f593SDavid van Moolenbroek u_char
colour_256to16(u_char c)267eda6f593SDavid van Moolenbroek colour_256to16(u_char c)
268eda6f593SDavid van Moolenbroek {
269eda6f593SDavid van Moolenbroek static const u_char table[256] = {
270eda6f593SDavid van Moolenbroek 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
271eda6f593SDavid van Moolenbroek 0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4,
272eda6f593SDavid van Moolenbroek 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
273eda6f593SDavid van Moolenbroek 10, 10, 10, 14, 1, 5, 4, 4, 12, 12, 3, 8, 4, 4, 12, 12,
274eda6f593SDavid van Moolenbroek 2, 2, 6, 4, 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10,
275eda6f593SDavid van Moolenbroek 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 5, 4, 12, 12, 1, 1,
276eda6f593SDavid van Moolenbroek 5, 4, 12, 12, 3, 3, 8, 4, 12, 12, 2, 2, 2, 6, 12, 12,
277eda6f593SDavid van Moolenbroek 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 1, 5,
278eda6f593SDavid van Moolenbroek 12, 12, 1, 1, 1, 5, 12, 12, 1, 1, 1, 5, 12, 12, 3, 3,
279eda6f593SDavid van Moolenbroek 3, 7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,
280eda6f593SDavid van Moolenbroek 9, 9, 9, 9, 13, 12, 9, 9, 9, 9, 13, 12, 9, 9, 9, 9,
281eda6f593SDavid van Moolenbroek 13, 12, 9, 9, 9, 9, 13, 12, 11, 11, 11, 11, 7, 12, 10, 10,
282eda6f593SDavid van Moolenbroek 10, 10, 10, 14, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13,
283eda6f593SDavid van Moolenbroek 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9,
284eda6f593SDavid van Moolenbroek 9, 13, 11, 11, 11, 11, 11, 15, 0, 0, 0, 0, 0, 0, 8, 8,
285eda6f593SDavid van Moolenbroek 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15
286eda6f593SDavid van Moolenbroek };
287eda6f593SDavid van Moolenbroek
288eda6f593SDavid van Moolenbroek return (table[c]);
289eda6f593SDavid van Moolenbroek }
290