xref: /petsc/src/sys/classes/draw/impls/x/xcolor.c (revision 6996bd1a6dda9216f11f3a1c5d2357ea301aa80d)
1 /*
2     Code for managing color the X implementation of the PetscDraw routines.
3 
4     Currently we default to using cmapping[0 to PETSC_DRAW_BASIC_COLORS-1] for the basic colors and
5     cmapping[DRAW_BASIC_COLORS to 255] for contour plots.
6 
7 */
8 #include <../src/sys/classes/draw/impls/x/ximpl.h>
9 #include <X11/Xatom.h>
10 
11 static const char *colornames[PETSC_DRAW_BASIC_COLORS] = {"white",   "black",     "red",      "green",      "cyan",      "blue",       "magenta",   "aquamarine",      "forestgreen", "orange",        "violet",
12                                                           "brown",   "pink",      "coral",    "gray",       "yellow",    "gold",       "lightpink", "mediumturquoise", "khaki",       "dimgray",       "yellowgreen",
13                                                           "skyblue", "darkgreen", "navyblue", "sandybrown", "cadetblue", "powderblue", "deeppink",  "thistle",         "limegreen",   "lavenderblush", "plum"};
14 
15 /*
16    Sets up a color map for a display. This is shared by all the windows
17   opened on that display; this is to save time when windows are open so
18   each one does not have to create its own color map which can take 15 to 20 seconds
19 
20      This is new code written 2/26/1999 Barry Smith,I hope it can replace
21   some older,rather confusing code.
22 
23      The calls to XAllocNamedColor() and XAllocColor() are very slow
24      because we have to request from the X server for each
25      color. Could not figure out a way to request a large number at the
26      same time.
27 
28    IMPORTANT: this code will fail if user opens windows on two different
29   displays: should add error checking to detect this. This is because all windows
30   share the same gColormap and gCmapping.
31 
32 */
33 static Colormap          gColormap = 0;
34 static PetscDrawXiPixVal gCmapping[PETSC_DRAW_MAXCOLOR];
35 static unsigned char     gCpalette[PETSC_DRAW_MAXCOLOR][3];
36 
PetscDrawSetUpColormap_Shared(Display * display,int screen,Visual * visual,Colormap colormap)37 static PetscErrorCode PetscDrawSetUpColormap_Shared(Display *display, int screen, Visual *visual, Colormap colormap)
38 {
39   int           i, k, ncolors = PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS;
40   unsigned char R[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
41   unsigned char G[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
42   unsigned char B[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
43   XColor        colordef, ecolordef;
44   PetscBool     fast = PETSC_FALSE;
45 
46   PetscFunctionBegin;
47   if (colormap) gColormap = colormap;
48   else gColormap = DefaultColormap(display, screen);
49 
50   /* set the basic colors into the color map */
51   for (i = 0; i < PETSC_DRAW_BASIC_COLORS; i++) {
52     XAllocNamedColor(display, gColormap, colornames[i], &colordef, &ecolordef);
53     gCmapping[i]    = colordef.pixel;
54     gCpalette[i][0] = (unsigned char)(colordef.red >> 8);
55     gCpalette[i][1] = (unsigned char)(colordef.green >> 8);
56     gCpalette[i][2] = (unsigned char)(colordef.blue >> 8);
57   }
58 
59   /* set the contour colors into the colormap */
60   PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_fast", &fast, NULL));
61   PetscCall(PetscDrawUtilitySetCmap(NULL, ncolors, R, G, B));
62   for (i = 0, k = PETSC_DRAW_BASIC_COLORS; i < ncolors; i++, k++) {
63     colordef.red   = (unsigned short)(R[i] << 8);
64     colordef.green = (unsigned short)(G[i] << 8);
65     colordef.blue  = (unsigned short)(B[i] << 8);
66     colordef.flags = DoRed | DoGreen | DoBlue;
67     colordef.pixel = gCmapping[PETSC_DRAW_BLACK];
68     if (!fast) XAllocColor(display, gColormap, &colordef);
69     gCmapping[k]    = colordef.pixel;
70     gCpalette[k][0] = R[i];
71     gCpalette[k][1] = G[i];
72     gCpalette[k][2] = B[i];
73   }
74 
75   PetscCall(PetscInfo(NULL, "Successfully allocated colors\n"));
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 /*
80     Keep a record of which pixel numbers in the cmap have been
81   used so far; this is to allow us to try to reuse as much of the current
82   colormap as possible.
83 */
84 static PetscBool cmap_pixvalues_used[PETSC_DRAW_MAXCOLOR];
85 static int       cmap_base = 0;
86 
PetscDrawSetUpColormap_Private(Display * display,int screen,Visual * visual,Colormap colormap)87 static PetscErrorCode PetscDrawSetUpColormap_Private(Display *display, int screen, Visual *visual, Colormap colormap)
88 {
89   int           found, i, k, ncolors = PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS;
90   unsigned char R[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
91   unsigned char G[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
92   unsigned char B[PETSC_DRAW_MAXCOLOR - PETSC_DRAW_BASIC_COLORS];
93   Colormap      defaultmap = DefaultColormap(display, screen);
94   XColor        colordef;
95   PetscBool     fast = PETSC_FALSE;
96 
97   PetscFunctionBegin;
98   if (colormap) gColormap = colormap;
99   else gColormap = XCreateColormap(display, RootWindow(display, screen), visual, AllocAll);
100 
101   cmap_base = 0;
102 
103   PetscCall(PetscMemzero(cmap_pixvalues_used, sizeof(cmap_pixvalues_used)));
104 
105   /* set the basic colors into the color map */
106   for (i = 0; i < PETSC_DRAW_BASIC_COLORS; i++) {
107     XParseColor(display, gColormap, colornames[i], &colordef);
108     /* try to allocate the color in the default-map */
109     found = XAllocColor(display, defaultmap, &colordef);
110     /* use it, if it exists and is not already used in the new colormap */
111     if (found && colordef.pixel < PETSC_DRAW_MAXCOLOR && !cmap_pixvalues_used[colordef.pixel]) {
112       cmap_pixvalues_used[colordef.pixel] = PETSC_TRUE;
113       /* otherwise search for the next available slot */
114     } else {
115       while (cmap_pixvalues_used[cmap_base]) cmap_base++;
116       colordef.pixel                   = cmap_base;
117       cmap_pixvalues_used[cmap_base++] = PETSC_TRUE;
118     }
119     XStoreColor(display, gColormap, &colordef);
120     gCmapping[i]    = colordef.pixel;
121     gCpalette[i][0] = (unsigned char)(colordef.red >> 8);
122     gCpalette[i][1] = (unsigned char)(colordef.green >> 8);
123     gCpalette[i][2] = (unsigned char)(colordef.blue >> 8);
124   }
125 
126   /* set the contour colors into the colormap */
127   PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_fast", &fast, NULL));
128   PetscCall(PetscDrawUtilitySetCmap(NULL, ncolors, R, G, B));
129   for (i = 0, k = PETSC_DRAW_BASIC_COLORS; i < ncolors; i++, k++) {
130     colordef.red   = (unsigned short)(R[i] << 8);
131     colordef.green = (unsigned short)(G[i] << 8);
132     colordef.blue  = (unsigned short)(B[i] << 8);
133     colordef.flags = DoRed | DoGreen | DoBlue;
134     colordef.pixel = gCmapping[PETSC_DRAW_BLACK];
135     if (!fast) {
136       /* try to allocate the color in the default-map */
137       found = XAllocColor(display, defaultmap, &colordef);
138       /* use it, if it exists and is not already used in the new colormap */
139       if (found && colordef.pixel < PETSC_DRAW_MAXCOLOR && !cmap_pixvalues_used[colordef.pixel]) {
140         cmap_pixvalues_used[colordef.pixel] = PETSC_TRUE;
141         /* otherwise search for the next available slot */
142       } else {
143         while (cmap_pixvalues_used[cmap_base]) cmap_base++;
144         colordef.pixel                   = cmap_base;
145         cmap_pixvalues_used[cmap_base++] = PETSC_TRUE;
146       }
147       XStoreColor(display, gColormap, &colordef);
148     }
149     gCmapping[k]    = colordef.pixel;
150     gCpalette[k][0] = R[i];
151     gCpalette[k][1] = G[i];
152     gCpalette[k][2] = B[i];
153   }
154 
155   PetscCall(PetscInfo(NULL, "Successfully allocated colors\n"));
156   PetscFunctionReturn(PETSC_SUCCESS);
157 }
158 
PetscDrawSetUpColormap_X(Display * display,int screen,Visual * visual,Colormap colormap)159 static PetscErrorCode PetscDrawSetUpColormap_X(Display *display, int screen, Visual *visual, Colormap colormap)
160 {
161   PetscBool   sharedcolormap = PETSC_FALSE;
162   XVisualInfo vinfo;
163 
164   PetscFunctionBegin;
165   PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_x_shared_colormap", &sharedcolormap, NULL));
166   /*
167      Need to determine if window supports allocating a private colormap,
168   */
169   if (XMatchVisualInfo(display, screen, 24, StaticColor, &vinfo) || XMatchVisualInfo(display, screen, 24, TrueColor, &vinfo) || XMatchVisualInfo(display, screen, 16, StaticColor, &vinfo) || XMatchVisualInfo(display, screen, 16, TrueColor, &vinfo) || XMatchVisualInfo(display, screen, 15, StaticColor, &vinfo) || XMatchVisualInfo(display, screen, 15, TrueColor, &vinfo))
170     sharedcolormap = PETSC_TRUE;
171   /*
172      Generate the X colormap object
173   */
174   if (sharedcolormap) {
175     PetscCall(PetscDrawSetUpColormap_Shared(display, screen, visual, colormap));
176   } else {
177     PetscCall(PetscDrawSetUpColormap_Private(display, screen, visual, colormap));
178   }
179   PetscFunctionReturn(PETSC_SUCCESS);
180 }
181 
182 PETSC_INTERN PetscErrorCode PetscDrawSetColormap_X(PetscDraw_X *, Colormap);
183 
PetscDrawSetColormap_X(PetscDraw_X * XiWin,Colormap colormap)184 PetscErrorCode PetscDrawSetColormap_X(PetscDraw_X *XiWin, Colormap colormap)
185 {
186   PetscBool fast = PETSC_FALSE;
187 
188   PetscFunctionBegin;
189   PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_fast", &fast, NULL));
190   PetscCheck(XiWin->depth >= 8, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "PETSc Graphics require monitors with at least 8 bit color (256 colors)");
191   if (!gColormap) PetscCall(PetscDrawSetUpColormap_X(XiWin->disp, XiWin->screen, XiWin->vis, colormap));
192   XiWin->cmap     = gColormap;
193   XiWin->cmapsize = fast ? PETSC_DRAW_BASIC_COLORS : PETSC_DRAW_MAXCOLOR;
194   PetscCall(PetscMemcpy(XiWin->cmapping, gCmapping, sizeof(XiWin->cmapping)));
195   PetscCall(PetscMemcpy(XiWin->cpalette, gCpalette, sizeof(XiWin->cpalette)));
196   XiWin->background = XiWin->cmapping[PETSC_DRAW_WHITE];
197   XiWin->foreground = XiWin->cmapping[PETSC_DRAW_BLACK];
198   PetscFunctionReturn(PETSC_SUCCESS);
199 }
200 
PetscDrawXiColormap(PetscDraw_X * XiWin)201 PetscErrorCode PetscDrawXiColormap(PetscDraw_X *XiWin)
202 {
203   return PetscDrawSetColormap_X(XiWin, (Colormap)0);
204 }
205