1 static char*id="$XConsortium: xcolors.c,v 1.3 94/06/07 13:08:11 gildea Exp $";
2 /*
3 * xcolors - display all X color names and colors
4 * Time-stamp: <94/06/06 20:16:00 gildea>
5 *
6 * Copyright (c) 1989,1991,1994 by Stephen Gildea
7 *
8 * Permission to use, copy, modify, distribute, and sell this software and
9 * its documentation for any purpose is hereby granted without fee, provided
10 * that the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation. The authors make no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
15 *
16 * Author: Stephen Gildea <gildea@expo.lcs.mit.edu>
17 * Orignal program by Paul Vixie.
18 */
19
20 #include <X11/Intrinsic.h>
21 #include <X11/StringDefs.h>
22 #include <X11/Xaw/Paned.h>
23 #include <X11/Xaw/AsciiText.h>
24 #include <X11/Xaw/Viewport.h>
25 #include <X11/Xaw/Box.h>
26 #include <X11/Xaw/Label.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <math.h> /* for sqrt() */
30
31 #ifndef RGB_TXT
32 #define RGB_TXT "/usr/lib/X11/rgb.txt"
33 #endif
34
35 String fallback_resources[] = {
36 "*Label.Font: 5x7",
37 "*panes.Width: 985",
38 "*Text*Height: 50",
39 "*viewport.allowVert: on",
40 "*sample*String: \
41 Button 1 sets the text color, button 2 sets the background.\\n\
42 Press q to quit. You can also type new text here.",
43 "*Label*translations: #override \
44 <Btn1Up>: set-foreground()\\n\
45 <Btn2Up>: set-background()",
46 "*Box*baseTranslations: #override \
47 <Key>q: quit()",
48 NULL};
49
50 struct OptionVals {
51 char *start_color;
52 char *rgb_file;
53 char *near_color;
54 int near_distance; /* radius, 0 to sqrt(3)*256 */
55 } opts;
56
57 XtResource resources[] = {
58 { "startColor", "StartColor", XtRString, sizeof (char *),
59 XtOffsetOf(struct OptionVals, start_color), XtRString, NULL },
60 { "rgbFile", "RgbFile", XtRString, sizeof (char *),
61 XtOffsetOf(struct OptionVals, rgb_file), XtRString, RGB_TXT },
62 { "nearColor", "NearColor", XtRString, sizeof (char *),
63 XtOffsetOf(struct OptionVals, near_color), XtRString, NULL },
64 { "nearDistance", "NearDistance", XtRInt, sizeof (int),
65 XtOffsetOf(struct OptionVals, near_distance),XtRImmediate,(XtPointer)64},
66 };
67
68 XrmOptionDescRec cmd_options[] = {
69 {"-start", ".startColor", XrmoptionSepArg, NULL},
70 {"-rgbfile", ".rgbFile", XrmoptionSepArg, NULL},
71 {"-near", ".nearColor", XrmoptionSepArg, NULL},
72 {"-distance", ".nearDistance", XrmoptionSepArg, NULL},
73 };
74
75 String wm_trans =
76 "<ClientMessage>WM_PROTOCOLS: quit()\n";
77
78 char *program_name;
79 int n_colors_displayed = 0; /* number of colors we are showing */
80 Atom wm_delete_window;
81 Atom wm_protocols;
82
83 Widget sample; /* the sample text */
84
usage(outf)85 void usage(outf)
86 FILE *outf;
87 {
88 static char *option_help[] = {
89 " -rgbfile filename rgb.txt color database file to use",
90 " -start colorname first color to show",
91 " -near colorname only show colors similar to this one",
92 " -distance int how far in 0-255 RGB space is similar",
93 "",
94 NULL};
95 char **cpp;
96
97 fprintf (outf, "usage: %s [-options ...]\n",
98 program_name);
99 fprintf (outf, " where options include:\n");
100 for (cpp = option_help; *cpp; cpp++) {
101 fprintf (outf, "%s\n", *cpp);
102 }
103 fprintf (outf, "%s\n", id+1);
104 fprintf (outf, "rgb file: %s\n", opts.rgb_file);
105 }
106
107 void
do_set_color(w,colorname,foreground_flag)108 do_set_color(w, colorname, foreground_flag)
109 Widget w;
110 String colorname; /* if null, get from w */
111 Boolean foreground_flag;
112 {
113 Arg arg[2];
114 int n;
115 XrmValue namein, pixelout;
116 Pixel color;
117
118 if (colorname) {
119 namein.addr = colorname;
120 namein.size = strlen(colorname) + 1;
121 pixelout.size = 0; /* so we can check for success */
122 XtConvert(w, XtRString, &namein, XtRPixel, &pixelout);
123 if (pixelout.size == 0) {
124 fprintf(stderr, "%s: no such color as \"%s\" for %s\n",
125 program_name, colorname,
126 foreground_flag ? XtNforeground : XtNbackground);
127 return;
128 }
129 color = *(Pixel*)(pixelout.addr);
130 } else {
131 n = 0;
132 XtSetArg(arg[n], XtNborderColor, &color); n++;
133 XtGetValues(w, arg, n);
134 }
135
136 /* set the value in the text sample */
137 XtSetArg(arg[0], foreground_flag ? XtNforeground : XtNbackground, color);
138 XtSetValues(sample, arg, 1);
139 }
140
141 /* ARGSUSED */
142 void
set_foreground(w,event,params,num_params)143 set_foreground(w, event, params, num_params)
144 Widget w;
145 XEvent *event;
146 String *params;
147 Cardinal *num_params;
148 {
149 do_set_color(w, *num_params ? params[0] : NULL, TRUE);
150 }
151
152 /* ARGSUSED */
153 void
set_background(w,event,params,num_params)154 set_background(w, event, params, num_params)
155 Widget w;
156 XEvent *event;
157 String *params;
158 Cardinal *num_params;
159 {
160 do_set_color(w, *num_params ? params[0] : NULL, FALSE);
161 }
162
163 /* ARGSUSED */
164 void
quit_action(w,event,params,num_params)165 quit_action(w, event, params, num_params)
166 Widget w;
167 XEvent *event;
168 String *params;
169 Cardinal *num_params;
170 {
171 if(event->type == ClientMessage && event->xclient.type == wm_protocols
172 && event->xclient.data.l[0] != wm_delete_window)
173 return;
174
175 exit(0);
176 }
177
178 XtActionsRec actionTable[] = {
179 {"quit", quit_action},
180 {"set-foreground", set_foreground},
181 {"set-background", set_background},
182 };
183
184
main(argc,argv)185 main(argc, argv)
186 int argc;
187 char *argv[];
188 {
189 XtAppContext app_context;
190 Widget toplevel, panes, viewport, colors;
191 Arg arg[10];
192 int n;
193 Status stat;
194 XColor near_rgb, junk_rgb;
195
196 toplevel = XtAppInitialize(&app_context, "Xcolors",
197 cmd_options, XtNumber(cmd_options), &argc, argv,
198 fallback_resources, NULL, 0);
199
200 XtGetApplicationResources (toplevel, (XtPointer) &opts, resources,
201 XtNumber(resources), NULL, 0);
202
203 program_name = argv[0];
204 argc--; argv++;
205
206 if (argc) {
207 if (!strcmp(argv[0], "-help")) {
208 usage(stdout);
209 exit(0);
210 } else {
211 usage(stderr);
212 exit(3);
213 }
214 }
215
216 if (opts.near_color) {
217 /* User asked to only see colors near this in RGB space.
218 Get the color from the server and scale it for comparison with
219 rgb.txt values */
220 stat = XLookupColor(XtDisplay(toplevel),
221 DefaultColormapOfScreen(XtScreen(toplevel)),
222 opts.near_color, &near_rgb, &junk_rgb);
223 if (!stat) {
224 fprintf(stderr, "%s: color \"%s\" is not known to the X server\n",
225 program_name, opts.near_color);
226 exit(1);
227 }
228 near_rgb.red >>= 8;
229 near_rgb.green >>= 8;
230 near_rgb.blue >>= 8;
231 near_rgb.flags = DoRed|DoBlue|DoGreen;
232 } else
233 near_rgb.flags = 0;
234
235 XtAppAddActions(app_context, actionTable, XtNumber(actionTable));
236
237 n = 0;
238 panes = XtCreateManagedWidget("panes", panedWidgetClass,
239 toplevel, arg, n);
240
241 n = 0;
242 XtSetArg(arg[n], XtNeditType, XawtextEdit); n++;
243 sample = XtCreateManagedWidget("sample", asciiTextWidgetClass,
244 panes, arg, n);
245
246 n = 0;
247 viewport = XtCreateManagedWidget("viewport", viewportWidgetClass,
248 panes, arg, n);
249
250 n = 0;
251 colors = XtCreateManagedWidget("colors", boxWidgetClass,
252 viewport, arg, n);
253
254 colordemo(colors, opts.start_color, near_rgb, opts.near_distance);
255
256 if (n_colors_displayed == 0) {
257 fprintf(stderr, "%s: no colors to display\n", program_name);
258 exit(5);
259 }
260
261 XtSetMappedWhenManaged(toplevel, FALSE);
262 XtRealizeWidget(toplevel);
263
264 /* do WM_DELETE_WINDOW before map */
265 XtOverrideTranslations(toplevel, XtParseTranslationTable(wm_trans));
266 wm_protocols = XInternAtom(XtDisplay(toplevel), "WM_PROTOCOLS", False);
267 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
268 False);
269 XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
270 &wm_delete_window, 1);
271
272 XtMapWidget(toplevel);
273 XtAppMainLoop(app_context);
274 /* NOTREACHED */
275 }
276
colordemo(parent,startcolor,nearcolor,maxdist)277 colordemo(parent, startcolor, nearcolor, maxdist)
278 Widget parent;
279 char *startcolor;
280 XColor nearcolor; /* scaled 0-255 */
281 int maxdist;
282 {
283 int r, g, b, prev_r, prev_g, prev_b;
284 char rgb_line[100];
285 char colorname[50], save_colorname[50];
286 FILE *rgb;
287 Bool do_color();
288 double ddist = maxdist;
289
290 rgb = fopen(opts.rgb_file, "r");
291 if (rgb == NULL) {
292 perror(opts.rgb_file);
293 exit(2);
294 }
295
296 prev_r = prev_g = prev_b = -1;
297 save_colorname[0] = '\0';
298 while (fgets(rgb_line, 100, rgb)) {
299 if (rgb_line[0] == '!')
300 continue; /* comment line */
301 sscanf(rgb_line, "%d %d %d %[^\n]\n", &r, &g, &b, colorname);
302 if (startcolor)
303 if (l_strcasecmp(colorname, startcolor))
304 continue; /* haven't reached starting point yet */
305 else
306 startcolor = (char *)NULL;
307 if (r != prev_r || g != prev_g || b != prev_b) {
308 if (nearcolor.flags) {
309 double ourdist =
310 sqrt((double)((nearcolor.red-r)*(nearcolor.red-r)
311 + (nearcolor.green-g)*(nearcolor.green-g)
312 + (nearcolor.blue-b)*(nearcolor.blue-b)));
313 if (ourdist > ddist)
314 continue;
315 }
316 if (save_colorname[0] != '\0') /* skip first time through */
317 if (!do_color(parent, save_colorname))
318 return 0;
319 prev_r = r;
320 prev_g = g;
321 prev_b = b;
322 }
323 strcpy(save_colorname, colorname);
324 }
325 if (save_colorname[0] != '\0')
326 (void)do_color(parent, save_colorname);
327
328 if (startcolor) { /* never found starting color in the file */
329 fprintf(stderr, "%s: \"%s\" not found in %s\n",
330 program_name, startcolor, opts.rgb_file);
331 }
332
333 }
334
335
336 /*
337 * does one color.
338 * Returns a success code.
339 */
340 Bool
do_color(parent,colorname)341 do_color(parent, colorname)
342 Widget parent;
343 char *colorname;
344 {
345 Arg arg[10];
346 int n;
347 XrmValue namein, pixelout;
348
349 /* convert colorname to a Pixel (a colormap index) */
350 namein.addr = colorname;
351 namein.size = strlen(colorname) + 1;
352 pixelout.size = 0; /* so we can check for success */
353 XtConvert(parent, XtRString, &namein, XtRPixel, &pixelout);
354 if (pixelout.size == 0) {
355 fprintf(stderr, "%s: Not enough room in color map.\n", program_name);
356 fprintf(stderr, "To see colors after this, ");
357 fprintf(stderr, "use the -start option to name a starting color.\n");
358 return FALSE;
359 }
360
361 /* create a widget to display the color */
362 n = 0;
363 XtSetArg(arg[n], XtNborderWidth, 10); n++;
364 XtSetArg(arg[n], XtNborderColor, *(Pixel*)(pixelout.addr)); n++;
365 XtCreateManagedWidget(colorname, labelWidgetClass, parent, arg, n);
366 n_colors_displayed++;
367 return TRUE;
368 }
369
370
371 /*
372 * Not all systems have strcasecmp, so we provide our own.
373 * Similar to strcmp, but ignores case.
374 * Always returns 1 if different.
375 */
376 int
l_strcasecmp(s1,s2)377 l_strcasecmp(s1, s2)
378 char *s1, *s2;
379 {
380 for ( ; *s1 && *s2 ; s1++, s2++)
381 if ((isupper(*s1) ? tolower(*s1) : *s1) !=
382 (isupper(*s2) ? tolower(*s2) : *s2))
383 return 1;
384 if (*s1 || *s2)
385 return 1;
386 return 0;
387 }
388