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