X11workbench Toolkit  1.0
pixmap_helper.c
1 // _ _ _ //
3 // _ __ (_)__ __ _ __ ___ __ _ _ __ | |__ ___ | | _ __ ___ _ __ ___ //
4 // | '_ \ | |\ \/ /| '_ ` _ \ / _` || '_ \ | '_ \ / _ \| || '_ \ / _ \| '__|/ __| //
5 // | |_) || | > < | | | | | || (_| || |_) | | | | || __/| || |_) || __/| | _| (__ //
6 // | .__/ |_|/_/\_\|_| |_| |_| \__,_|| .__/_____|_| |_| \___||_|| .__/ \___||_|(_)\___| //
7 // |_| |_| |_____| |_| //
8 // //
9 // pixmap and icon helpers (ultimately providing universal support) //
10 // //
12 
13 /*****************************************************************************
14 
15  X11workbench - X11 programmer's 'work bench' application and toolkit
16  Copyright (c) 2010-2019 by Bob Frazier (aka 'Big Bad Bombastic Bob')
17 
18  DISCLAIMER: The X11workbench application and toolkit software are supplied
19  'as-is', with no warranties, either implied or explicit.
20  Any claims to alleged functionality or features should be
21  considered 'preliminary', and might not function as advertised.
22 
23  MIT-like license:
24 
25  There is no restriction as to what you can do with this software, so long
26  as you include the above copyright notice and DISCLAIMER for any distributed
27  work that is equal to or derived from this one, along with this paragraph
28  that explains the terms of the license if the source is also being made
29  available. A "derived work" describes a work that uses a significant portion
30  of the source files or algorithms that are included with this one.
31  Specifically excluded from this are files that were generated by the software,
32  or anything that is included with the software that is part of another package
33  (such as files that were created or added during the 'configure' process).
34  Specifically included is the use of part or all of any of the X11 workbench
35  toolkit source or header files in your distributed application. If you do not
36  ship the source, the above copyright statement is still required to be placed
37  in a reasonably prominent place, such as documentation, splash screens, and/or
38  'about the application' dialog boxes.
39 
40  Use and distribution are in accordance with GPL, LGPL, and/or the above
41  MIT-like license. See COPYING and README files for more information.
42 
43  This file may have additional license requirements, due to the use of
44  potentially derived code. Please see the code comments in the appropriate
45  source file section to identify that portion of the code that may be
46  covered by additional requirements.
47 
48 
49  Additional information at http://sourceforge.net/projects/X11workbench
50 
51 ******************************************************************************/
52 
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <memory.h>
57 #include <string.h>
58 #include <strings.h>
59 #include <math.h> // and now I'll need -lm
60 
61 // application header file
62 #include "pixmap_helper.h" // this will include platform_helper.h and window_helper.h
63 
64 // This next section has includes for the XShmXXX functions - must do this AFTER platform_helper.h has been included
65 #if !defined(WIN32) && defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION)
66 #include <sys/ipc.h>
67 #include <sys/shm.h>
68 #include <X11/extensions/XShm.h>
69 #endif // !defined(WIN32) && defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION)
70 
71 #ifdef X11WORKBENCH_TOOLKIT_HAVE_XFT
72 #include <X11/Xft/Xft.h>
73 #endif // X11WORKBENCH_TOOLKIT_HAVE_XFT
74 
75 
76 // include pixmap data
77 
78 #include "icon_ok.xpm"
79 #include "icon_stop.xpm"
80 #include "icon_warn.xpm"
81 #include "icon_what.xpm"
82 #include "icon_splat.xpm"
83 
84 // other pixmaps (some not entirely work safe)
85 #include "icon_bang.xpm"
86 #include "icon_barney.xpm"
87 #include "icon_bear.xpm"
88 #include "icon_death.xpm"
89 #include "icon_finger.xpm"
90 #include "icon_skull.xpm"
91 #include "icon_triangle.xpm"
92 #include "icon_what_bold.xpm"
93 #include "icon_wtf.xpm"
94 #include "icon_thumbup.xpm"
95 #include "icon_thumbdown.xpm"
96 
97 
98 
99 #ifdef NO_DEBUG
100 #define DEBUG_DUMP_XPM_ATTRIBUTES(X)
101 #define DEBUG_DUMP_COLORMAP(X)
102 #else
103 static void DebugDumpXpmAttributes(const char *szFunction, int nLine, XPM_ATTRIBUTES *pAttr);
104 #define DEBUG_DUMP_XPM_ATTRIBUTES(X) DebugDumpXpmAttributes(__FUNCTION__, __LINE__, X)
105 #define DEBUG_DUMP_COLORMAP(X) WBDebugDumpColormap("Called from " __FUNCTION__, X)
106 #endif // NO_DEBUG
107 
108 
109 #define _PI_ 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 /* approximately */
110 
111 
112 #define MINIMUM_ATOM_RESOURCE_LIST_SIZE 256
113 
114 typedef struct __INTERNAL_ATOM_RESOURCE_LIST__
115 {
116  Atom aAtom;
117  char **ppResource;
118 } INTERNAL_ATOM_RESOURCE_LIST;
119 
120 static INTERNAL_ATOM_RESOURCE_LIST *pAtomResourceList = NULL;
121 static int nAtomResourceList = 0, nAtomResourceListMax = 0;
122 
123 static char **ppRegAppLarge_Internal = NULL;
124 static char **ppRegAppSmall_Internal = NULL;
125 
126 XStandardColormap PXM_StandardColormapFromColormap_rval; // storage for static var for PXM_StandardColormapFromColormap()
127 
128 
129 //--------------------
130 // STARTUP AND CLEANUP
131 //--------------------
132 
133 void PXM_OnExit(void)
134 {
135  if(pAtomResourceList)
136  {
137  WBFree(pAtomResourceList);
138  pAtomResourceList = NULL;
139  }
140 
141  nAtomResourceList = 0;
142  nAtomResourceListMax = 0;
143 
144  ppRegAppLarge_Internal = NULL;
145  ppRegAppSmall_Internal = NULL;
146 }
147 
148 
149 //---------------
150 // MATH UTILITIES
151 //---------------
152 
153 unsigned char WB_isqrt(unsigned char iVal)
154 {
155 static const unsigned char aAnswers[256] =
156 {
157  0,1,1,2,2,2,2,3,3,3,3,3,3,4,4,4,
158  4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,
159  6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,
160  7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,
161  8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,
162  9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,
163  10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,
164  11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
165  11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,
166  12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,
167  13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
168  13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,
169  14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
170  14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,
171  15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
172  15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16
173 };
174 
175 
176  return aAnswers[iVal & 0xff];
177 }
178 
179 unsigned char WB_icos0(unsigned char iVal)
180 {
181 static const unsigned char aAnswers[256] =
182 {
183 255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,
184 254,254,253,253,253,253,253,252,252,252,252,252,251,251,251,250,
185 250,250,249,249,249,248,248,248,247,247,247,246,246,245,245,244,
186 244,244,243,243,242,242,241,241,240,240,239,238,238,237,237,236,
187 236,235,234,234,233,232,232,231,231,230,229,228,228,227,226,226,
188 225,224,223,223,222,221,220,220,219,218,217,216,215,215,214,213,
189 212,211,210,209,208,208,207,206,205,204,203,202,201,200,199,198,
190 197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,181,
191 180,179,178,177,176,175,174,172,171,170,169,168,167,165,164,163,
192 162,161,159,158,157,156,154,153,152,151,149,148,147,146,144,143,
193 142,140,139,138,136,135,134,132,131,130,128,127,126,124,123,122,
194 120,119,117,116,115,113,112,110,109,108,106,105,103,102,100,99,
195 98,96,95,93,92,90,89,87,86,84,83,81,80,79,77,76,
196 74,73,71,70,68,67,65,63,62,60,59,57,56,54,53,51,
197 50,48,47,45,44,42,41,39,37,36,34,33,31,30,28,27,
198 25,23,22,20,19,17,16,14,13,11,9,8,6,5,3,2
199 };
200 
201 
202  return aAnswers[iVal & 0xff];
203 }
204 
205 static const char aCosAnswers[0x400] = // 1024 of them for a complete circle
206 {
207  127, 127, 127, 127, 127, 127, 127, 127,
208  127, 127, 127, 127, 127, 127, 127, 126,
209  126, 126, 126, 126, 126, 126, 126, 126,
210  126, 126, 125, 125, 125, 125, 125, 125,
211  125, 124, 124, 124, 124, 124, 124, 123,
212  123, 123, 123, 123, 122, 122, 122, 122,
213  122, 121, 121, 121, 121, 120, 120, 120,
214  120, 119, 119, 119, 118, 118, 118, 118,
215  117, 117, 117, 116, 116, 116, 115, 115,
216  115, 114, 114, 114, 113, 113, 113, 112,
217  112, 112, 111, 111, 111, 110, 110, 109,
218  109, 109, 108, 108, 107, 107, 106, 106,
219  106, 105, 105, 104, 104, 103, 103, 102,
220  102, 102, 101, 101, 100, 100, 99, 99,
221  98, 98, 97, 97, 96, 96, 95, 95,
222  94, 94, 93, 93, 92, 91, 91, 90,
223  90, 89, 89, 88, 88, 87, 86, 86,
224  85, 85, 84, 84, 83, 82, 82, 81,
225  81, 80, 79, 79, 78, 78, 77, 76,
226  76, 75, 74, 74, 73, 72, 72, 71,
227  71, 70, 69, 69, 68, 67, 67, 66,
228  65, 65, 64, 63, 63, 62, 61, 61,
229  60, 59, 58, 58, 57, 56, 56, 55,
230  54, 54, 53, 52, 51, 51, 50, 49,
231  49, 48, 47, 46, 46, 45, 44, 44,
232  43, 42, 41, 41, 40, 39, 38, 38,
233  37, 36, 35, 35, 34, 33, 32, 32,
234  31, 30, 29, 29, 28, 27, 26, 26,
235  25, 24, 23, 22, 22, 21, 20, 19,
236  19, 18, 17, 16, 16, 15, 14, 13,
237  12, 12, 11, 10, 9, 9, 8, 7,
238  6, 5, 5, 4, 3, 2, 2, 1,
239  0, -1, -2, -2, -3, -4, -5, -5,
240  -6, -7, -8, -9, -9, -10, -11, -12,
241  -12, -13, -14, -15, -16, -16, -17, -18,
242  -19, -19, -20, -21, -22, -22, -23, -24,
243  -25, -26, -26, -27, -28, -29, -29, -30,
244  -31, -32, -32, -33, -34, -35, -35, -36,
245  -37, -38, -38, -39, -40, -41, -41, -42,
246  -43, -44, -44, -45, -46, -46, -47, -48,
247  -49, -49, -50, -51, -51, -52, -53, -54,
248  -54, -55, -56, -56, -57, -58, -58, -59,
249  -60, -61, -61, -62, -63, -63, -64, -65,
250  -65, -66, -67, -67, -68, -69, -69, -70,
251  -71, -71, -72, -72, -73, -74, -74, -75,
252  -76, -76, -77, -78, -78, -79, -79, -80,
253  -81, -81, -82, -82, -83, -84, -84, -85,
254  -85, -86, -86, -87, -88, -88, -89, -89,
255  -90, -90, -91, -91, -92, -93, -93, -94,
256  -94, -95, -95, -96, -96, -97, -97, -98,
257  -98, -99, -99, -100, -100, -101, -101, -102,
258  -102, -102, -103, -103, -104, -104, -105, -105,
259  -106, -106, -106, -107, -107, -108, -108, -109,
260  -109, -109, -110, -110, -111, -111, -111, -112,
261  -112, -112, -113, -113, -113, -114, -114, -114,
262  -115, -115, -115, -116, -116, -116, -117, -117,
263  -117, -118, -118, -118, -118, -119, -119, -119,
264  -120, -120, -120, -120, -121, -121, -121, -121,
265  -122, -122, -122, -122, -122, -123, -123, -123,
266  -123, -123, -124, -124, -124, -124, -124, -124,
267  -125, -125, -125, -125, -125, -125, -125, -126,
268  -126, -126, -126, -126, -126, -126, -126, -126,
269  -126, -126, -127, -127, -127, -127, -127, -127,
270  -127, -127, -127, -127, -127, -127, -127, -127,
271  -127, -127, -127, -127, -127, -127, -127, -127,
272  -127, -127, -127, -127, -127, -127, -127, -126,
273  -126, -126, -126, -126, -126, -126, -126, -126,
274  -126, -126, -125, -125, -125, -125, -125, -125,
275  -125, -124, -124, -124, -124, -124, -124, -123,
276  -123, -123, -123, -123, -122, -122, -122, -122,
277  -122, -121, -121, -121, -121, -120, -120, -120,
278  -120, -119, -119, -119, -118, -118, -118, -118,
279  -117, -117, -117, -116, -116, -116, -115, -115,
280  -115, -114, -114, -114, -113, -113, -113, -112,
281  -112, -112, -111, -111, -111, -110, -110, -109,
282  -109, -109, -108, -108, -107, -107, -106, -106,
283  -106, -105, -105, -104, -104, -103, -103, -102,
284  -102, -102, -101, -101, -100, -100, -99, -99,
285  -98, -98, -97, -97, -96, -96, -95, -95,
286  -94, -94, -93, -93, -92, -91, -91, -90,
287  -90, -89, -89, -88, -88, -87, -86, -86,
288  -85, -85, -84, -84, -83, -82, -82, -81,
289  -81, -80, -79, -79, -78, -78, -77, -76,
290  -76, -75, -74, -74, -73, -72, -72, -71,
291  -71, -70, -69, -69, -68, -67, -67, -66,
292  -65, -65, -64, -63, -63, -62, -61, -61,
293  -60, -59, -58, -58, -57, -56, -56, -55,
294  -54, -54, -53, -52, -51, -51, -50, -49,
295  -49, -48, -47, -46, -46, -45, -44, -44,
296  -43, -42, -41, -41, -40, -39, -38, -38,
297  -37, -36, -35, -35, -34, -33, -32, -32,
298  -31, -30, -29, -29, -28, -27, -26, -26,
299  -25, -24, -23, -22, -22, -21, -20, -19,
300  -19, -18, -17, -16, -16, -15, -14, -13,
301  -12, -12, -11, -10, -9, -9, -8, -7,
302  -6, -5, -5, -4, -3, -2, -2, -1,
303  0, 1, 2, 2, 3, 4, 5, 5,
304  6, 7, 8, 9, 9, 10, 11, 12,
305  12, 13, 14, 15, 16, 16, 17, 18,
306  19, 19, 20, 21, 22, 22, 23, 24,
307  25, 26, 26, 27, 28, 29, 29, 30,
308  31, 32, 32, 33, 34, 35, 35, 36,
309  37, 38, 38, 39, 40, 41, 41, 42,
310  43, 44, 44, 45, 46, 46, 47, 48,
311  49, 49, 50, 51, 51, 52, 53, 54,
312  54, 55, 56, 56, 57, 58, 58, 59,
313  60, 61, 61, 62, 63, 63, 64, 65,
314  65, 66, 67, 67, 68, 69, 69, 70,
315  71, 71, 72, 72, 73, 74, 74, 75,
316  76, 76, 77, 78, 78, 79, 79, 80,
317  81, 81, 82, 82, 83, 84, 84, 85,
318  85, 86, 86, 87, 88, 88, 89, 89,
319  90, 90, 91, 91, 92, 93, 93, 94,
320  94, 95, 95, 96, 96, 97, 97, 98,
321  98, 99, 99, 100, 100, 101, 101, 102,
322  102, 102, 103, 103, 104, 104, 105, 105,
323  106, 106, 106, 107, 107, 108, 108, 109,
324  109, 109, 110, 110, 111, 111, 111, 112,
325  112, 112, 113, 113, 113, 114, 114, 114,
326  115, 115, 115, 116, 116, 116, 117, 117,
327  117, 118, 118, 118, 118, 119, 119, 119,
328  120, 120, 120, 120, 121, 121, 121, 121,
329  122, 122, 122, 122, 122, 123, 123, 123,
330  123, 123, 124, 124, 124, 124, 124, 124,
331  125, 125, 125, 125, 125, 125, 125, 126,
332  126, 126, 126, 126, 126, 126, 126, 126,
333  126, 126, 127, 127, 127, 127, 127, 127,
334  127, 127, 127, 127, 127, 127, 127, 127 //,
335 // 127
336 };
337 
338 char WB_icos(int iVal)
339 {
340  return aCosAnswers[iVal & 0x3ff];
341 }
342 
343 unsigned int WB_iatan(int iX, int iY)
344 {
345 
346  return 0; // for now...
347 }
348 
349 
350 
351 
352 
353 //-------------------------
354 // RGB and YUV conversions
355 //-------------------------
356 
357 static int clip255(int iIn)
358 {
359  if(iIn < 0)
360  {
361  return 0;
362  }
363  else if(iIn > 255)
364  {
365  return 255;
366  }
367 
368  return iIn;
369 }
370 
371 void PXM_RGBToYUV(int iR, int iG, int iB, int *piY, int *piU, int *piV)
372 {
373 int iY, iU, iV;
374 
375  iR = clip255(iR);
376  iG = clip255(iG);
377  iB = clip255(iB);
378 
379  iY = clip255((( 66 * iR + 129 * iG + 25 * iB + 128) >> 8) + 16);
380  iU = clip255((( -38 * iR - 74 * iG + 112 * iB + 128) >> 8) + 128);
381  iV = clip255((( 112 * iR - 94 * iG - 18 * iB + 128) >> 8) + 128);
382 
383  if(piY)
384  {
385  *piY = iY;
386  }
387 
388  if(piU)
389  {
390  *piU = iU;
391  }
392 
393  if(piV)
394  {
395  *piV = iV;
396  }
397 }
398 
399 void PXM_YUVToRGB(int iY, int iU, int iV, int *piR, int *piG, int *piB)
400 {
401 int iR, iG, iB;
402 int iC = iY - 16;
403 int iD = iU - 128;
404 int iE = iV - 128;
405 
406  iR = clip255(( 298 * iC + 409 * iE + 128) >> 8);
407  iG = clip255(( 298 * iC - 100 * iD - 208 * iE + 128) >> 8);
408  iB = clip255(( 298 * iC + 516 * iD + 128) >> 8);
409 
410  if(piR)
411  {
412  *piR = iR;
413  }
414 
415  if(piG)
416  {
417  *piG = iG;
418  }
419 
420  if(piB)
421  {
422  *piB = iB;
423  }
424 }
425 
426 void PXM_HSVToRGB(int iH, int iS, int iV, int *piR, int *piG, int *piB)
427 {
428 // this algorithm is similar to what Microsoft uses in their MFC classes, and
429 // what wxWidgets uses in their classes. As such, it's an "open" algorithm,
430 // as the licensing of these two code bases appears to be otherwise incompatible.
431 // The algorithm has been attributed to A. R. Smith . It appears to be "a standard"
432 // (NOTE: I shall research to make sure it's use here is not stomping on ownership)
433 int iR, iG, iB;
434 
435 double dH, dS, dV, dFracH, dR, dG, dB;
436 int iQuadrant;
437 double dUnSat, dLinDn, dLinUp;
438 
439 
440  if(!iS) // a simple optimization for B&W
441  {
442  iR = iG = iB = iV; // RGB is equal to the brightness when no color
443  }
444  else
445  {
446  dH = (6.0 / 256.0) * iH; // convert 0-255 angle to 0-360 angle [for the algorithm] and divide by 60
447  iQuadrant = (int)floor(dH); // quadrant 0 through 5 for 0-360 angle
448  dFracH = dH - iQuadrant; // the fractional part of 'dH'
449 
450  dS = iS / 255.0; // convert 0-255 saturation to 0-1.0 value
451  dV = iV / 255.0; // convert 0-255 'Volume' (brightness, luminocity) to 0-1.0 value
452 
453  dUnSat = dV * (1.0 - dS); // linear delta based on saturation value
454  dLinDn = dV * (1.0 - dS * dFracH); // NOTE: an improved algorithm would use a cos/sin function
455  dLinUp = dV * (1.0 - dS * (1.0 - dFracH)); // NOTE: an improved algorithm would use a cos/sin function
456 
457  // switch/case is typically slower - using 'if' block instead
458  if(iQuadrant < 3) // bottom half
459  {
460  if(iQuadrant == 0)
461  {
462  dR = dV; // red is essentially 'saturated' for +/-60 degrees... (this seems wrong to me)
463  dG = dLinUp; // linear slope increasing
464  dB = dUnSat; // 'un-saturated' value (as dS increases, this goes down, based on dV)
465  }
466  else if(iQuadrant == 1)
467  {
468  dR = dLinDn; // linear slope decreasing
469  dG = dV; // now green is 'saturated'
470  dB = dUnSat; // still 'un-saturated'
471  }
472  else // 2
473  {
474  dR = dUnSat; // now red is 'un-saturated'
475  dG = dV; // green still 'saturated'
476  dB = dLinUp; // blue is 'on the rise' now
477  }
478  }
479  else
480  {
481  if(iQuadrant == 3)
482  {
483  dR = dUnSat; // red is 'un-saturated' still
484  dG = dLinDn; // green is on the way down
485  dB = dV; // now blue is 'saturated'
486  }
487  else if(iQuadrant == 4)
488  {
489  dR = dLinUp; // red is 'on the rise' now
490  dG = dUnSat; // green is 'unsaturated'
491  dB = dV; // blue is 'saturated' again
492  }
493  else // 5
494  {
495  dR = dV; // red is 'saturated' again
496  dG = dUnSat; // green is still 'unsaturated'
497  dB = dLinDn; // blue is 'on the way down'
498  }
499  }
500 
501  iR = clip255((int)floor(256 * dR)); // using 256 rather than 255 gives me some 'rounding up'
502  iG = clip255((int)floor(256 * dG));
503  iB = clip255((int)floor(256 * dB));
504  }
505 
506  if(piR)
507  {
508  *piR = iR;
509  }
510 
511  if(piG)
512  {
513  *piG = iG;
514  }
515 
516  if(piB)
517  {
518  *piB = iB;
519  }
520 }
521 
522 void PXM_RGBToHSV(int iR, int iG, int iB, int *piH, int *piS, int *piV)
523 {
524 // this algorithm is similar to what Microsoft uses in their MFC classes, and
525 // what wxWidgets uses in their classes. As such, it's an "open" algorithm,
526 // as the licensing of these two code bases appears to be otherwise incompatible.
527 // The algorithm has been attributed to A. R. Smith . It appears to be "a standard"
528 // (NOTE: I shall research to make sure it's use here is not stomping on ownership)
529 
530 double dH, dS, dV, dDelta;
531 int iMinRGB, iMaxRGB;
532 
533 
534  iMinRGB = (iR <= iG)
535  ? (iR <= iB)
536  ? iR : iB
537  : (iG <= iB)
538  ? iG : iB;
539 
540  iMaxRGB = (iR >= iG)
541  ? (iR >= iB)
542  ? iR : iB
543  : (iG >= iB)
544  ? iG : iB;
545 
546  if(piV)
547  {
548  *piV = iMaxRGB; // use the max RGB value as my 'volume' (aka brightness, luminocity)
549  }
550 
551  dV = iMaxRGB / 255.0; // convert to value between 0 and 1 for rest of algorithm
552 
553  if(!iMaxRGB) // black
554  {
555  if(piH)
556  {
557  *piH = 0; // the color red
558  }
559  if(piS)
560  {
561  *piS = 0; // zero saturation
562  }
563 
564  return; // I am done here. 'V' is already equal to the RGB values (which must be the same if I get here)
565  }
566 
567  dS = 1.0 * (iMaxRGB - iMinRGB) // the delta
568  / (double)iMaxRGB; // ratio of delta to max = saturation (a value from 0 to 1.0)
569 
570  if(piS) // store it
571  {
572  *piS = clip255((int)floor(256.0 * dS)); // using 256 rather than 255 gives me some 'rounding up'
573  }
574 
575  // calculating 'H'
576 
577  if(!piH) // if not asking for H, bail out now
578  {
579  return;
580  }
581 
582  if(iMaxRGB == iMinRGB)
583  {
584  dH = 0.0; // the color 'red'
585  }
586  else
587  {
588  // NOTE: this infers the quadrants based on which color is maximum
589 
590  dDelta = iMaxRGB - iMinRGB;
591 
592  if(iR == iMaxRGB) // maxed out red?
593  {
594  // quadrants 5 and 0 (note quadrant 5 goes negative)
595  dH = (iG - iB) / dDelta; // calculate diff between yellow and magenta as +/- 1.0
596  }
597  else if(iG == iMaxRGB) // maxed out green?
598  {
599  dH = 2.0 + (iB - iR) / dDelta; // calculate diff between cyan and yellow as +/- 1.0
600  }
601  else // if(iB == iMaxRGB) maxed out blue
602  {
603  dH = 4.0 + (iR - iG) / dDelta; // calculate diff between magenta and cyan as +/- 1.0
604  }
605  }
606 
607  // dH is a value from -1 to 5. If it's less than zero, add 6 to it
608  if(dH < 0.0)
609  {
610  dH += 6.0;
611  }
612 
613  // now dH is a value from 0 to 6, corresponding to values of 0-256.
614 
615  if(dH >= 6.0)
616  {
617  dH = 0.0; // so it converts correctly
618  }
619 
620  *piH = clip255((int)floor((256.0 / 6.0) * dH)); // using 256 rather than 255 gives me some 'rounding up'
621 }
622 
623 
624 static unsigned short internal_get_rgb_from_pixel(long lPixel, int iMult, int iMax)
625 {
626 unsigned long lVal;
627 
628 
629  if(WB_LIKELY(iMult == 65536)) // a typical value for 8-bit colors in the pixel
630  {
631  lVal = lPixel / 65536; // this should compile as a fast bit shift
632  }
633  else if(WB_LIKELY(iMult == 256)) // a typical value for 8-bit colors in the pixel
634  {
635  lVal = lPixel / 256; // this should compile as a fast bit shift
636  }
637  else if(WB_LIKELY(iMult == 1)) // a typical value for 8-bit colors in the pixel
638  {
639  lVal = lPixel;
640  }
641  else // other values are possible, deal with them here
642  {
643  lVal = lPixel / iMult; // an arbitrary multiplier - slower, but functional
644  }
645 
646  if(WB_LIKELY(iMax == 65535 || iMax == 255))
647  {
648  lVal = lVal & iMax;
649 
650  if(WB_LIKELY(iMax == 255))
651  {
652  if(lVal == iMax) // so that white is always ffffH
653  {
654  lVal = 65535;
655  }
656  else
657  {
658  lVal *= 256; // to convert it to 0-65535 value
659  }
660  }
661  }
662  else // unlikely, but possible - slower code but functional
663  {
664  lVal %= (iMax + 1);
665 
666  if(lVal == iMax) // so that white is always ffffH
667  {
668  lVal = 65535;
669  }
670  else
671  {
672 #ifdef HAS_WB_UINT64_BUILTIN
673  lVal = (unsigned long)((WB_UINT64)65536 // do math as 'long long' to avoid overflows on 32-bit
674  * (WB_UINT64)lVal
675  / (WB_UINT64)(iMax + 1));
676 #else // !HAS_WB_UINT64_BUILTIN
677  // NOTE: some values could cause math overflow (but are not likely)
678 
679  lVal = 65536L * lVal
680  / (iMax + 1);
681 #endif // HAS_WB_UINT64_BUILTIN
682  }
683  }
684 
685  return (unsigned short)lVal;
686 }
687 
688 void PXM_PixelToRGB(XStandardColormap *pMap, XColor *pColor)
689 {
690 unsigned long lColor;
691 XStandardColormap map;
692 
693 
694  if(!pColor)
695  {
696  return;
697  }
698 
699  if(!pMap)
700  {
702  pMap = &map;
703 
704 // DEBUG_DUMP_COLORMAP(pMap);
705  }
706 
707  // 'nuking' this one out is a bit difficult. I have to sort the values properly
708 
709  lColor = pColor->pixel - pMap->base_pixel;
710 
711  if(!pMap->red_mult && !pMap->green_mult && !pMap->blue_mult)
712  {
713  return;
714  }
715 
716  pColor->flags = DoRed | DoGreen | DoBlue; // pre-assign this, re-assign as needed
717 
718  if(!pMap->green_mult && !pMap->blue_mult)
719  {
720  // monochrome
721 
722  pColor->red = internal_get_rgb_from_pixel(lColor, pMap->red_mult, pMap->red_max);
723  pColor->green = pColor->blue = pColor->red; // make them the same (by convention for now)
724 
725  pColor->flags = DoRed; // usually indicates 'monochrome' - only use 'red'
726  }
727  else
728  {
729  pColor->red = internal_get_rgb_from_pixel(lColor, pMap->red_mult, pMap->red_max);
730  pColor->green = internal_get_rgb_from_pixel(lColor, pMap->green_mult, pMap->green_max);
731  pColor->blue = internal_get_rgb_from_pixel(lColor, pMap->blue_mult, pMap->blue_max);
732  }
733 }
734 
735 void PXM_RGBToPixel(XStandardColormap *pMap, XColor *pColor)
736 {
737 unsigned long lR, lG, lB;
738 XStandardColormap map;
739 
740 
741  if(!pColor)
742  {
743  return;
744  }
745 
746  if(!pMap)
747  {
749  pMap = &map;
750 
751 // DEBUG_DUMP_COLORMAP(pMap);
752  }
753 
754  // this one is straightforward, right out of the docs for the XStandardColormap structure
755 
756  lR = lG = lB = 0; // pre-assign
757 
758  if(!pColor->flags) // assume all 3 primaries, assign accordingly
759  {
760  pColor->flags = DoRed | DoGreen | DoBlue;
761  }
762 
763  if(pColor->flags & DoRed)
764  {
765  lR = ((unsigned long)(pColor->red) * (unsigned long)(pMap->red_max + 1))
766  / (unsigned long)65536L;
767  }
768 
769 // if(lR < 0)
770 // {
771 // lR = 0;
772 // }
773 // else
774  if(lR > pMap->red_max)
775  {
776  lR = pMap->red_max;
777  }
778 
779  if(pColor->flags & DoGreen)
780  {
781  lG = ((unsigned long)(pColor->green) * (unsigned long)(pMap->green_max + 1))
782  / (unsigned long)65536L;
783  }
784 
785 // if(lG < 0)
786 // {
787 // lG = 0;
788 // }
789 // else
790  if(lG > pMap->green_max)
791  {
792  lG = pMap->green_max;
793  }
794 
795  if(pColor->flags & DoBlue)
796  {
797  lB = (((unsigned long)pColor->blue) * (unsigned long)(pMap->blue_max + 1))
798  / (unsigned long)65536L;
799  }
800 
801 // if(lB < 0)
802 // {
803 // lB = 0;
804 // }
805 // else
806  if(lB > pMap->blue_max)
807  {
808  lB = pMap->blue_max;
809  }
810 
811  pColor->pixel = (pMap->base_pixel
812  + lR * pMap->red_mult
813  + lG * pMap->green_mult
814  + lB * pMap->blue_mult)
815  & 0xffffffffL;
816 
817 // WB_ERROR_PRINT("TEMPORARY: %s - pixel=%lX %d,%d,%d %ld,%ld,%ld %ld,%ld,%ld %ld,%ld,%ld %ld\n",
818 // __FUNCTION__,
819 // pColor->pixel, pColor->red, pColor->green, pColor->blue,
820 // lR, lG, lB, pMap->red_mult, pMap->green_mult, pMap->blue_mult,
821 // pMap->red_max, pMap->green_max, pMap->blue_max, pMap->base_pixel);
822 }
823 
824 
825 void PXM_RegisterAppIcons(char *ppRegAppLarge[], char *ppRegAppSmall[])
826 {
827  ppRegAppLarge_Internal = ppRegAppLarge;
828  ppRegAppSmall_Internal = ppRegAppSmall;
829 }
830 
831 static char **GetPreDefinedIconResource(int idIcon)
832 {
833 char **pData = NULL;
834 
835  switch(idIcon)
836  {
837  case ID_APPLICATION:
838  if(ppRegAppSmall_Internal)
839  {
840  pData = ppRegAppSmall_Internal;
841  }
842  else
843  {
844  pData = icon_ok_xpm; // TODO: make a 19x19 version
845  }
846  break;
847  case ID_ICON_APP:
848  if(ppRegAppLarge_Internal)
849  {
850  pData = ppRegAppLarge_Internal;
851  }
852  else
853  {
854  pData = icon_ok_xpm;
855  }
856  break;
857  case ID_ICON_OK:
858  pData = icon_ok_xpm;
859  break;
860  case ID_ICON_STOP:
861  pData = icon_stop_xpm;
862  break;
863  case ID_ICON_WARN:
864  pData = icon_warn_xpm;
865  break;
866  case ID_ICON_WHAT:
867  pData = icon_what_xpm;
868  break;
869  case ID_ICON_SPLAT:
870  pData = icon_splat_xpm;
871  break;
872  case ID_ICON_BANG:
873  pData = icon_bang_xpm;
874  break;
875  case ID_ICON_TRIANGLE:
876  pData = icon_triangle_xpm;
877  break;
878  case ID_ICON_WHAT_BOLD:
879  pData = icon_what_bold_xpm;
880  break;
881  case ID_ICON_WTF:
882  pData = icon_wtf_xpm;
883  break;
884  case ID_ICON_DEATH:
885  pData = icon_death_xpm;
886  break;
887  case ID_ICON_FINGER:
888  pData = icon_finger_xpm;
889  break;
890  case ID_ICON_SKULL:
891  pData = icon_skull_xpm;
892  break;
893  case ID_ICON_THUMBUP:
894  pData = icon_thumbup_xpm;
895  break;
896  case ID_ICON_THUMBDOWN:
897  pData = icon_thumbdown_xpm;
898  break;
899  case ID_ICON_BEAR:
900  pData = icon_bear_xpm;
901  break;
902  case ID_ICON_BARNEY: // this is a joke. really.
903  pData = icon_barney_xpm;
904  break;
905  }
906 
907  return pData;
908 }
909 
910 static void RegisterIconResource(Atom aIcon, char **ppResource)
911 {
912 int i1;
913 
914  if(!pAtomResourceList)
915  {
916  pAtomResourceList = (INTERNAL_ATOM_RESOURCE_LIST *)
917  WBAlloc(MINIMUM_ATOM_RESOURCE_LIST_SIZE * sizeof(*pAtomResourceList));
918 
919  if(!pAtomResourceList)
920  {
921  WB_ERROR_PRINT("%s - not enough memoory for atom resource list\n", __FUNCTION__);
922  return;
923  }
924 
925  nAtomResourceList = 0;
926  nAtomResourceListMax = MINIMUM_ATOM_RESOURCE_LIST_SIZE;
927  }
928 
929  for(i1=0; i1 < nAtomResourceList; i1++)
930  {
931  if(pAtomResourceList[i1].aAtom == aIcon) // already there?
932  {
933  WB_ERROR_PRINT("%s - matching atom already in the list (ignoring)\n", __FUNCTION__);
934  return; // fow now I just leave. later I might allow editing
935  }
936  }
937 
938  if((nAtomResourceList + 1) >= nAtomResourceListMax)
939  {
940  int iNewSize = MINIMUM_ATOM_RESOURCE_LIST_SIZE / 2 + nAtomResourceListMax;
941 
942  void *pTemp = WBReAlloc(pAtomResourceList, iNewSize);
943  if(!pTemp)
944  {
945  WB_ERROR_PRINT("%s - not enough memoory for atom resource list re-alloc\n", __FUNCTION__);
946  return;
947  }
948 
949  pAtomResourceList = (INTERNAL_ATOM_RESOURCE_LIST *)pTemp;
950  nAtomResourceListMax += MINIMUM_ATOM_RESOURCE_LIST_SIZE / 2;
951  }
952 
953  pAtomResourceList[nAtomResourceList].aAtom = aIcon;
954  pAtomResourceList[nAtomResourceList].ppResource = ppResource;
955  nAtomResourceList++;
956 }
957 
958 static const char * const szPreDefinedIconResources[] =
959 {
960  "ID_APPLICATION",
961  "ID_ICON_OK",
962  "ID_ICON_STOP",
963  "ID_ICON_WARN",
964  "ID_ICON_WHAT",
965  "ID_ICON_QUESTION",
966  "ID_ICON_SPLAT",
967  "ID_ICON_ASTERISK",
968  "ID_ICON_BANG",
969  "ID_ICON_TRIANGLE",
970  "ID_ICON_WHAT_BOLD",
971  "ID_ICON_WTF",
972  "ID_ICON_DEATH",
973  "ID_ICON_FINGER",
974  "ID_ICON_SKULL",
975  "ID_ICON_THUMBUP",
976  "ID_ICON_THUMBDOWN",
977  "ID_ICON_BEAR",
978  "ID_ICON_BARNEY",
979  "ID_ICON_APP"
980 };
981 
982 static char **GetRegisteredIconResource(Atom aIcon)
983 {
984 static int iHasBeenRegistered = 0;
985 int i1, i2;
986 
987  // if the pre-defined atoms have not yet been registered, do it NOW
988 
989  if(!iHasBeenRegistered)
990  {
991  for(i1=ID_ICON_FIRST, i2=0;
992  i1 <= ID_ICON_LAST
993  && i2 < sizeof(szPreDefinedIconResources)/sizeof(szPreDefinedIconResources[0]);
994  i1++, i2++)
995  {
996  Atom aTemp = WBGetAtom(WBGetDefaultDisplay(), szPreDefinedIconResources[i2]);
997 
998  if(aTemp != None)
999  {
1000  RegisterIconResource(aTemp, GetPreDefinedIconResource(i1));
1001  }
1002  }
1003 
1004  iHasBeenRegistered = 1;
1005  }
1006 
1007  for(i1=0; i1 < nAtomResourceList; i1++)
1008  {
1009  if(pAtomResourceList[i1].aAtom == aIcon) // already there?
1010  {
1011  return pAtomResourceList[i1].ppResource;
1012  }
1013  }
1014 
1015  return NULL;
1016 }
1017 
1018 
1019 
1020 Pixmap PXM_GetIconPixmap(int idIcon, XPM_ATTRIBUTES *pAttr, Pixmap *pMask)
1021 {
1022 char **pData;
1023 
1024 
1025  pData = GetPreDefinedIconResource(idIcon);
1026 
1027  if(!pData)
1028  {
1029  if(pAttr)
1030  {
1031  bzero(pAttr, sizeof(*pAttr));
1032  }
1033 
1034  if(pMask)
1035  {
1036  *pMask = None;
1037  }
1038 
1039  return None;
1040  }
1041 
1042  return PXM_LoadPixmap(pData, pAttr, pMask);
1043 }
1044 
1045 
1046 Pixmap PXM_GetIconPixmapFromAtom(Atom aIcon, XPM_ATTRIBUTES *pAttr, Pixmap *pMask /* = NULL*/)
1047 {
1048 char **pData;
1049 
1050 
1051  pData = GetRegisteredIconResource(aIcon);
1052 
1053  if(!pData)
1054  {
1055  if(pAttr)
1056  {
1057  bzero(pAttr, sizeof(*pAttr));
1058  }
1059 
1060  if(pMask)
1061  {
1062  *pMask = None;
1063  }
1064 
1065  return None;
1066  }
1067 
1068  return PXM_LoadPixmap(pData, pAttr, pMask);
1069 }
1070 
1071 
1072 Pixmap PXM_LoadPixmap(char *ppXPM[], XPM_ATTRIBUTES *pAttr, Pixmap *pMask /* = NULL*/)
1073 {
1074 Pixmap pixRval = None, pixRval2 = None;
1075 XPM_ATTRIBUTES xattr;
1076 //#ifndef NO_DEBUG
1077 //WB_UINT64 ullTime = WBGetTimeIndex();
1078 //#endif // NO_DEBUG
1079 
1080 
1081  if(!ppXPM)
1082  {
1083  if(pAttr)
1084  {
1085  bzero(pAttr, sizeof(*pAttr));
1086  }
1087 
1088  if(pMask)
1089  {
1090  *pMask = None;
1091  }
1092 
1093  return None;
1094  }
1095 
1096  bzero(&xattr, sizeof(xattr));
1097 
1098 // WB_ERROR_PRINT("TEMPORARY: %s line %d delta tick %lld\n", __FUNCTION__, __LINE__, (WBGetTimeIndex() - ullTime));
1099 
1100 #ifdef X11WORKBENCH_TOOLKIT_HAVE_XPM
1102 #endif // X11WORKBENCH_TOOLKIT_HAVE_XPM
1104  ppXPM, &pixRval, &pixRval2, &xattr);
1105 #ifdef X11WORKBENCH_TOOLKIT_HAVE_XPM
1107 #endif // X11WORKBENCH_TOOLKIT_HAVE_XPM
1108 
1109 // WB_ERROR_PRINT("TEMPORARY: %s line %d delta tick %lld\n", __FUNCTION__, __LINE__, (WBGetTimeIndex() - ullTime));
1110 
1111  if(pAttr)
1112  {
1113  memcpy(pAttr, &xattr, sizeof(xattr));
1114  }
1115  else
1116  {
1117  WB_IF_DEBUG_LEVEL(DebugLevel_Light | DebugSubSystem_Pixmap)
1118  {
1119  DEBUG_DUMP_XPM_ATTRIBUTES(&xattr);
1120  }
1121 
1122  XPM_FREE_ATTRIBUTES(&xattr);
1123  }
1124 
1125  if(pMask)
1126  {
1127  *pMask = pixRval2;
1128  }
1129  else if(pixRval2 != None) // free pixRval2 if it was allocated (it's the 'mask')
1130  {
1132  XFreePixmap(WBGetDefaultDisplay(), pixRval2);
1134  }
1135 
1136  return(pixRval);
1137 }
1138 
1139 Pixmap PXM_ImageToPixmap(Display *pDisplay, Drawable dw, XImage *pImage,
1140  unsigned long clrFGPixel, unsigned long clrBGPixel)
1141 {
1142 Pixmap pxRval;
1143 WBGC gc;
1144 XGCValues gcv;
1145 int iW, iH;
1146 
1147  if(!pDisplay)
1148  {
1149  pDisplay = WBGetDefaultDisplay();
1150  }
1151 
1152  if(!pImage)
1153  {
1154  WB_ERROR_PRINT("%s - pImage is NULL\n", __FUNCTION__);
1155  return None;
1156  }
1157 
1158  iW = pImage->width;
1159  iH = pImage->height;
1160 
1161  if(!iW || !iH)
1162  {
1163  WB_ERROR_PRINT("%s - Image width/height not valid, iW=%d,iH=%d\n", __FUNCTION__, iW, iH);
1164  return None;
1165  }
1166 
1168  pxRval = XCreatePixmap(pDisplay, dw, iW, iH, DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
1170 
1171  if(pxRval == None)
1172  {
1173  WB_ERROR_PRINT("%s - XCreatePixmap failed\n", __FUNCTION__);
1174  return None;
1175  }
1176 
1177  // I will need to create a GC. Make it a simple one that only specifies FG and BG
1178 
1179  memset(&gcv, 0, sizeof(gcv));
1180  gcv.foreground = clrFGPixel;//BlackPixel(pDisplay, DefaultScreen(pDisplay));
1181  gcv.background = clrBGPixel;//WhitePixel(pDisplay, DefaultScreen(pDisplay));
1182 
1183  // NOTE: for monochrome masks I'd likely use '1' for foreground, '0' for background
1184 
1186  gc = WBCreateGC(pDisplay, dw, (GCForeground | GCBackground), &gcv);
1188 
1189  if(gc == NULL)
1190  {
1191  WB_ERROR_PRINT("%s - WBCreateGC failed\n", __FUNCTION__);
1192 
1194  XFreePixmap(pDisplay, pxRval);
1196  return None;
1197  }
1198  else
1199  {
1201  WBXPutImage(pDisplay, pxRval, gc, pImage, 0, 0, 0, 0, iW, iH); // and now I have a copy of it
1202 
1203  WBFreeGC(gc);
1205  }
1206 
1207  return pxRval;
1208 }
1209 
1210 
1211 Pixmap PXM_ImageToPixmap0(Display *pDisplay, Drawable dw, XImage *pImage)
1212 {
1213  if(!pDisplay)
1214  {
1215  pDisplay = WBGetDefaultDisplay();
1216  }
1217 
1218  return PXM_ImageToPixmap(pDisplay, dw, pImage,
1219  BlackPixel(pDisplay, DefaultScreen(pDisplay)),
1220  WhitePixel(pDisplay, DefaultScreen(pDisplay)));
1221 }
1222 
1223 
1224 XImage *PXM_PixmapToImage(Display *pDisplay, Pixmap pxImage)
1225 {
1226 XImage *pRval;
1227 Window winRoot; // not used, still needed?
1228 int iX=0, iY=0;
1229 unsigned int iWidth=0, iHeight=0, iBorder;
1230 unsigned int uiDepth = 0;
1231 
1232 
1233  if(!pDisplay)
1234  {
1235  pDisplay = WBGetDefaultDisplay();
1236  }
1237 
1238  // TODO: special handling for pxImage == None ???
1239 
1240  if(pxImage == None)
1241  {
1242  return NULL;
1243  }
1244 
1246 
1247  // use XGetGeometry to obtain the characteristics of the pixmap. iX and iY SHOULD be zero...
1248  XGetGeometry(pDisplay, pxImage, &winRoot, &iX, &iY, &iWidth, &iHeight, &iBorder, &uiDepth);
1249 
1250  if(!iWidth || !iHeight)
1251  {
1252  pRval = NULL;
1253  }
1254  else
1255  {
1256  // TODO: do I still need iX and iY?
1257  pRval = WBXGetImage(pDisplay, pxImage, 0, 0, iWidth, iHeight, -1L, ZPixmap);
1258  }
1259 
1261 
1262  return pRval;
1263 }
1264 
1265 Pixmap PXM_CopyPixmap(Display *pDisplay, Drawable dw, Pixmap pxSource)
1266 {
1267 XGCValues gcv;
1268 Window winRoot;
1269 GC gc;
1270 Pixmap pxRval;
1271 int iRet, iX=0, iY=0;
1272 unsigned int iWidth=0, iHeight=0, iBorder;
1273 unsigned int uiDepth = 0;
1274 
1275 
1276  if(!pDisplay)
1277  {
1278  pDisplay = WBGetDefaultDisplay();
1279  }
1280 
1281  if((CARD32)pxSource & 0xe0000000)
1282  {
1283  WB_ERROR_PRINT("%s - invalid Pixmap - %d (%08xH)\n", __FUNCTION__, (int)pxSource, (int)pxSource);
1284 
1285  return None;
1286  }
1287 
1289  // use XGetGeometry to obtain the characteristics of the pixmap. iX and iY SHOULD be zero...
1290  iRet = XGetGeometry(pDisplay, pxSource, &winRoot, &iX, &iY, &iWidth, &iHeight, &iBorder, &uiDepth);
1292 
1293  if(!iWidth || !iHeight)
1294  {
1295  WB_ERROR_PRINT("%s - XGetGeometry failed, pxSource=%d (%08xH), iRet=%d\n",
1296  __FUNCTION__, (int)pxSource, (int)pxSource, iRet);
1297  pxRval = None;
1298  }
1299  else
1300  {
1302  pxRval = XCreatePixmap(pDisplay, dw, iWidth, iHeight, uiDepth); // note depth of new pixmap matches old
1304 
1305  if(pxRval == None)
1306  {
1307  WB_ERROR_PRINT("%s - XCreatePixmap failed\n", __FUNCTION__);
1308  return None;
1309  }
1310 
1311  // I will need to create a GC. Make it a simple one that only specifies FG and BG
1312 
1313  memset(&gcv, 0, sizeof(gcv));
1314  gcv.foreground = BlackPixel(pDisplay, DefaultScreen(pDisplay)); // use these (for now)
1315  gcv.background = WhitePixel(pDisplay, DefaultScreen(pDisplay));
1316 
1317  // NOTE: for monochrome masks I'd likely use '1' for foreground, '0' for background
1318 
1320  gc = XCreateGC(pDisplay, dw, (GCForeground | GCBackground), &gcv);
1322 
1323  if(gc == NULL)
1324  {
1325  WB_ERROR_PRINT("%s - WBCreateGC failed\n", __FUNCTION__);
1326 
1328  XFreePixmap(pDisplay, pxRval);
1330  pxRval = None;
1331  }
1332  else
1333  {
1335  XCopyArea(pDisplay, pxSource, pxRval, gc, 0, 0, iWidth, iHeight, 0, 0);
1336  XFreeGC(pDisplay, gc);
1338  }
1339  }
1340 
1341  return pxRval;
1342 }
1343 
1344 void WBSimpleAntiAliasPixmap(Display *pDisplay, const XStandardColormap *pMap, Pixmap pxImage, unsigned long lPixel, WB_GEOM *pGeom)
1345 {
1346 WB_GEOM geom;
1347 XImage *pImage = NULL;
1348 WBGC gc;
1349 XGCValues gcv;
1350 XStandardColormap map;
1351 
1352 
1353  if(!pDisplay)
1354  {
1355  pDisplay = WBGetDefaultDisplay();
1356  }
1357 
1358  if(pxImage == None)
1359  {
1360  return;
1361  }
1362 
1363  if(!pMap)
1364  {
1365  WBDefaultStandardColormap(pDisplay, &map);
1366  pMap = &map;
1367  }
1368 
1369  if(pGeom)
1370  {
1371  memcpy(&geom, pGeom, sizeof(geom));
1372  }
1373  else
1374  {
1375  Window winRoot; // unused, but I still need it
1376 
1377  int iX=0, iY=0;
1378  unsigned int iWidth=0, iHeight=0, iBorder;
1379  unsigned int uiDepth = 0;
1380 
1381  // use XGetGeometry to obtain the characteristics of the pixmap. iX and iY SHOULD be zero...
1383  XGetGeometry(pDisplay, pxImage, &winRoot, &iX, &iY, &iWidth, &iHeight, &iBorder, &uiDepth);
1385 
1386  geom.x = 0;
1387  geom.y = 0;
1388  geom.width = iWidth;
1389  geom.height = iHeight;
1390  }
1391 
1392  if(!geom.width || !geom.height)
1393  {
1394  return;
1395  }
1396 
1397  // create an XImage, and perform the operation on that
1399  pImage = WBXGetImage(pDisplay, pxImage, geom.x, geom.y, geom.width, geom.height, 0xffffffff, ZPixmap);
1400  // NOTE: 'ZPixmap' is WAY faster than XYPixmap, but takes up more RAM
1402 
1403  if(!pImage)
1404  {
1405  WB_ERROR_PRINT("ERROR: %s - unable to create image via XGetImage()\n", __FUNCTION__);
1406  return;
1407  }
1408 
1409  WBSimpleAntiAliasImage(pMap, pImage, lPixel, &geom);
1410 
1411  memset(&gcv, 0, sizeof(gcv));
1412  gcv.foreground = lPixel;
1413  gcv.background = lPixel; // for now just do this
1414 
1416  gc = WBCreateGC(pDisplay, pxImage, (GCForeground | GCBackground), &gcv);
1418 
1419  if(gc == None)
1420  {
1421  WB_ERROR_PRINT("%s - XCreateGC failed\n", __FUNCTION__);
1422  }
1423  else
1424  {
1426  WBXPutImage(pDisplay, pxImage, gc, pImage, 0, 0, geom.x, geom.y, geom.width, geom.height);
1427 
1428  WBFreeGC(gc);
1430  }
1431 
1432  // I can destroy the image now
1434  WBXDestroyImage(pImage);
1436 }
1437 
1438 static unsigned long __internal_grey_the_pixel(XStandardColormap *pMap, unsigned long lPixel,
1439  int iR0, int iG0, int iB0) // note 16-bit RGB here
1440 {
1441 XColor clr;
1442 int iR, iG, iB;
1443 
1444  clr.pixel = lPixel;
1445  PXM_PixelToRGB(pMap, &clr);
1446  RGB_FROM_XCOLOR(clr, iR, iG, iB); // 16-bit RGB values
1447 
1448  iR = (3 * iR + iR0 + 1) / 4; // create 'average' colors (this works the best, 3/4 original, 1/4 background)
1449  iG = (3 * iG + iG0 + 1) / 4;
1450  iB = (3 * iB + iB0 + 1) / 4;
1451 
1452  RGB_TO_XCOLOR(iR, iG, iB, clr);
1453  PXM_RGBToPixel(pMap, &clr);
1454 
1455  return clr.pixel; // yeah that was a lot of stuff to do
1456 }
1457 
1458 void WBSimpleAntiAliasImage(const XStandardColormap *pMap, XImage *pImage, unsigned long lPixel, WB_GEOM *pGeom)
1459 {
1460 WB_GEOM geom;
1461 XStandardColormap map;
1462 int nX, nY, iR, iG, iB;
1463 XColor clr;
1464 
1465 
1466  // TODO: do I want to operate directly on the memory? for now, use the 'XGetPixel' and 'XPutPixel' utilities
1467 
1468  if(!pImage)
1469  {
1470  return;
1471  }
1472 
1473  if(!pMap)
1474  {
1476  }
1477  else
1478  {
1479  memcpy(&map, pMap, sizeof(map));
1480  }
1481 
1482  if(pGeom)
1483  {
1484  memcpy(&geom, pGeom, sizeof(geom));
1485  }
1486  else
1487  {
1488  geom.x = 0;
1489  geom.y = 0;
1490  geom.width = pImage->width;
1491  geom.height = pImage->height;
1492  }
1493 
1494  clr.pixel = lPixel;
1495  PXM_PixelToRGB(&map, &clr);
1496  RGB_FROM_XCOLOR(clr, iR, iG, iB);
1497 
1498  for(nX = geom.x; nX < (geom.x + geom.width - 1); nX++)
1499  {
1500  for(nY = geom.y; nY < (geom.y + geom.height - 1); nY++)
1501  {
1502  // detect the 'inside pixel' or 'outside pixel' on a corner
1503  // the idea is to look for one of these and put 'greyed'
1504  // pixels in between
1505  //
1506  // X. Xo .X oX
1507  // .X becomes oX and X. becomes Xo
1508  //
1509  // where 'o' represents a color between . and X
1510  //
1511 
1512  unsigned long lPixel1 = XGetPixel(pImage, nX, nY);
1513  unsigned long lPixel2 = XGetPixel(pImage, nX + 1, nY);
1514  unsigned long lPixel3 = XGetPixel(pImage, nX, nY + 1);
1515  unsigned long lPixel4 = XGetPixel(pImage, nX + 1, nY + 1);
1516 
1517  if(lPixel1 == lPixel && lPixel4 == lPixel)
1518  {
1519  if(lPixel2 != lPixel) // grey it
1520  {
1521  lPixel2 = __internal_grey_the_pixel(&map, lPixel2, iR, iG, iB);
1522  if(lPixel2 != lPixel) // make sure it's not because if it is, it's a problem
1523  {
1525  XPutPixel(pImage, nX + 1, nY, lPixel2);
1527  }
1528  }
1529 
1530  if(lPixel3 != lPixel) // grey it
1531  {
1532  lPixel3 = __internal_grey_the_pixel(&map, lPixel3, iR, iG, iB);
1533  if(lPixel3 != lPixel) // make sure it's not because if it is, it's a problem
1534  {
1536  XPutPixel(pImage, nX, nY + 1, lPixel3);
1538  }
1539  }
1540  }
1541 
1542  if(lPixel2 == lPixel && lPixel3 == lPixel)
1543  {
1544  if(lPixel1 != lPixel) // grey it
1545  {
1546  lPixel1 = __internal_grey_the_pixel(&map, lPixel1, iR, iG, iB);
1547  if(lPixel1 != lPixel) // make sure it's not because if it is, it's a problem
1548  {
1550  XPutPixel(pImage, nX, nY, lPixel1);
1552  }
1553  }
1554 
1555  if(lPixel4 != lPixel) // grey it
1556  {
1557  lPixel4 = __internal_grey_the_pixel(&map, lPixel4, iR, iG, iB);
1558  if(lPixel4 != lPixel) // make sure it's not because if it is, it's a problem
1559  {
1561  XPutPixel(pImage, nX + 1, nY + 1, lPixel4);
1563  }
1564  }
1565  }
1566 
1567  }
1568  }
1569 
1570 }
1571 
1572 
1573 #if defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1574 int WBXShmQueryExtension(Display *pDisplay)
1575 {
1576  return XShmQueryExtension(pDisplay) ? 1 : 0;
1577 }
1578 #endif // defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1579 
1580 int WBXPutImage(Display *pDisplay, Drawable dw, WBGC gc, XImage *pImage,
1581  int src_x, int src_y, int dest_x, int dest_y,
1582  unsigned int width, unsigned int height)
1583 {
1584 int iRval;
1585 
1586  // for now, just do this
1588  iRval = XPutImage(pDisplay, dw, gc->gc, pImage, src_x, src_y, dest_x, dest_y, width, height); // for now just do this
1590 
1591  // TODO: I'll need to determine whether or not my image is using shared memory
1592  // and also make sure that it's attached to the display [as it should be]
1593  // If both of these is NOT the case, then I use XPutImage() to avoid issues
1594 
1595 //Bool XShmPutImage(
1596 // Display *display;
1597 // Drawable d;
1598 // GC gc;
1599 // XImage *image;
1600 // int src_x, src_y, dest_x, dest_y;
1601 // unsigned int width, height;
1602 // bool send_event);
1603 
1604  return iRval;
1605 }
1606 
1607 XImage *WBXGetImage(Display *pDisplay, Drawable dw,
1608  int x, int y, unsigned int width, unsigned int height,
1609  unsigned long plane_mask, int format)
1610 {
1611 XImage *pImage;
1612 
1613  // TODO: if the drawable has an image locally cached, use it. This handles the situation
1614  // where a remote connection has poor performance grabbing an image from the server,
1615  // but sending an image TO the server is reasonably fast by comparison.
1616 
1617 
1618 #if defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1619  if(!WBXShmQueryExtension(pDisplay))
1620  {
1621 #endif // defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1622 
1624  pImage = XGetImage(pDisplay, dw, x, y, width, height, plane_mask, format);
1626 
1627 #if defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1628  }
1629  else
1630  {
1631 // WB_ERROR_PRINT("TEMPORARY: %s line %d - 'XShm' not (yet) being invoked\n", __FUNCTION__, __LINE__);
1632 
1634  pImage = XGetImage(pDisplay, dw, x, y, width, height, plane_mask, format); // for now just do this
1636 
1637  if(!pImage)
1638  {
1639  WB_ERROR_PRINT("ERROR - %s - Unable to get XImage: dw=%08xH x=%d y=%d width=%d height=%d plane_mask=%08lxH format=%d\n",
1640  __FUNCTION__, (int)dw, x, y, width, height, (unsigned long)plane_mask, format);
1641  }
1642 
1643 #if 0
1644  XShmSegmentInfo shminfo;
1645  int screen = DefaultScreen(pDisplay);
1646  Visual *pVisual = DefaultVisual(pDisplay, screen);
1647  int depth = DefaultDepth(pDisplay, screen);
1648 
1649  if(format == XYBitmap)
1650  {
1651  depth = 1;
1652  }
1653 
1654  bzero(&shminfo, sizeof(shminfo));
1655 
1656  pImage = XShmCreateImage(pDisplay, pVisual, depth, format, NULL, &shminfo, width, height);
1657 
1658  if(pImage)
1659  {
1660  shminfo.readOnly = False;
1661  pImage->data = WBAllocShm(pDisplay, image->bytes_per_line * image->height, &shminfo, IPC_PRIVATE, PIC_CREAT | 0777);
1662 
1663  if(!pImage->data)
1664  {
1665  WBXDestroyImage(pImage);
1666  pImage = NULL;
1667  }
1668 
1669 // shminfo.shmaddr; // shmat(shminfo.shmid, 0, 0);
1670 // shminfo.readOnly = False;
1671 
1672 // if(!XShmAttach(d, &shminfo))
1673 // {
1674 // // this would be an error
1675 // }
1676 
1677  if(!XShmGetImage(pDisplay, dw, pImage, x, y, plane_mask))
1678  {
1679  // is FALSE the error, or is it a TRUE value that's an error? determine which...
1680 
1681  WBXDestroyImage(pImage);
1682  pImage = NULL;
1683  }
1684 
1685  XSync(pDisplay, 0); // must do this to make sure it completes before I return
1686  }
1687 #endif // 0
1688  }
1689 #endif // defined(X11WORKBENCH_TOOLKIT_HAVE_XSHM_EXTENSION) || defined(__DOXYGEN__)
1690  return pImage;
1691 }
1692 
1693 int WBXDestroyImage(XImage *pImage)
1694 {
1695 int iRval;
1696 
1697  // TODO: determine whether the image is using shared memory. If so, detach
1698  // it from the display (if it's attached), and free the shared memory
1699  // FIRST, and set the data pointer to NULL. Then, destroy the image
1700  // with XDestroyImage() as if nothing else was different.
1701 
1703  iRval = XDestroyImage(pImage); // for now, just do this
1705 
1706  return iRval;
1707 }
1708 
1709 XImage * WBXCopyImage(Display *pDisplay, XImage *pImage)
1710 {
1711 XImage *pRval;
1712 
1713  if(!pImage)
1714  {
1715  return NULL;
1716  }
1717 
1718  if(!pDisplay)
1719  {
1720  pDisplay = WBGetDefaultDisplay();
1721  }
1722 
1724  pRval = XCreateImage(pDisplay, DefaultVisual(pDisplay, DefaultScreen(pDisplay)),
1725  pImage->depth, pImage->format, pImage->xoffset,
1726  pImage->data, pImage->width, pImage->height,
1727  pImage->bitmap_pad, pImage->bytes_per_line);
1729 
1730 
1731  return pRval;
1732 }
1733 
1734 
1736 // X11 'equivalence' functions for XImage
1737 //
1738 // Some of this code may have been adapted from the Xorg and/or earlier versions
1739 // of the X11 server implementation, and derivatives of it. The copyright statement
1740 // and license for the X11 server code is included here, for reference:
1741 //
1742  /*
1743 
1744  Copyright 1988, 1998 The Open Group
1745 
1746  Permission to use, copy, modify, distribute, and sell this software and its
1747  documentation for any purpose is hereby granted without fee, provided that
1748  the above copyright notice appear in all copies and that both that
1749  copyright notice and this permission notice appear in supporting
1750  documentation.
1751 
1752  The above copyright notice and this permission notice shall be included
1753  in all copies or substantial portions of the Software.
1754 
1755  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1756  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1757  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1758  IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1759  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1760  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1761  OTHER DEALINGS IN THE SOFTWARE.
1762 
1763  Except as contained in this notice, the name of The Open Group shall
1764  not be used in advertising or otherwise to promote the sale, use or
1765  other dealings in this Software without prior written authorization
1766  from The Open Group.
1767 
1768  Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
1769 
1770  All Rights Reserved
1771 
1772  Permission to use, copy, modify, and distribute this software and its
1773  documentation for any purpose and without fee is hereby granted,
1774  provided that the above copyright notice appear in all copies and that
1775  both that copyright notice and this permission notice appear in
1776  supporting documentation, and that the name of Digital not be
1777  used in advertising or publicity pertaining to distribution of the
1778  software without specific, written prior permission.
1779 
1780  DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1781  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1782  DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1783  ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1784  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1785  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1786  SOFTWARE.
1787  */
1788 //
1789 // Please do not remove the above copyright and licensing information from
1790 // any derived work. Thank you.
1791 //
1792 // Although this code can not be considered 'derived', I most definitely
1793 // examined the licensed code when writing it. As such I believe it is only
1794 // fair to at least comply with the intent of the license for Xorg and
1795 // related X11 libraries and X11 servers.
1796 //
1798 
1799 
1800 
1801 Region WBXImageToRegion(const XImage *pImage)
1802 {
1803 Region rgnRval;
1804 
1805  if(!pImage)
1806  {
1807  rgnRval = None;
1808  }
1809  else
1810  {
1811  // Use 'pImage' "not background pixel" x,y points to create a Region.
1812  //
1813  // see 'miCoalesce' in Xorg server; how horizontal 'bands' are used to combine
1814  // rectangles in a Region. I want to do something very much like that here, so
1815  // that there are no adjacent rectangles horizontally.
1816  // After that I fix it vertically. Pretty straightforward. Should be fast.
1817 
1818 
1819  rgnRval = None; // temporary
1820  }
1821 
1822  return rgnRval;
1823 }
1824 
1825 XImage * WBXImageFromRegion(Region rgnSource, int width, int height)
1826 {
1827 XImage *pRval;
1828 
1829  if(rgnSource == None)
1830  {
1831  pRval = NULL;
1832  }
1833  else
1834  {
1835  // First create an XImage that matches the bounding rectangle of the region.
1836  // Then,
1837  // simply figure out what the bounding rect is
1838  // see 'miCoalesce' in Xorg serve; how horizontal 'bands' are used to combine
1839  // rectangles in a Region. I want to do something very much like that here, so
1840  // that there are no adjacent rectangles horizontally.
1841  // After that I fix it vertically. Pretty straightforward. Should be fast.
1842 
1843 
1844  pRval = NULL; // temporary
1845  }
1846 
1847  return pRval;
1848 }
1849 
1850 int WBXDrawPoint(XImage *pImage, WBGC hGC, int x, int y)
1851 {
1852 int iRval;
1853 int bNoClip;
1854 
1855  if(!pImage || !hGC)
1856  {
1857  return -1;
1858  }
1859 
1860  iRval = 0;
1861  bNoClip = hGC->clip_rgn == None || XEmptyRegion(hGC->clip_rgn);
1862 
1863  if(bNoClip ||
1864  XPointInRegion(hGC->clip_rgn, x, y)) // TODO: clip origin???
1865  {
1867  iRval = XPutPixel(pImage, x, y, hGC->values.foreground);
1869  }
1870 
1871  return iRval;
1872 }
1873 
1874 int WBXDrawPoints(XImage *pImage, WBGC hGC,
1875  XPoint *points, int npoints, int mode)
1876 {
1877 int i1, i2, iX, iY, iRval;
1878 int bNoClip;
1879 
1880 
1881  if(!pImage || !hGC || !points || npoints <= 0 ||
1882  (mode != CoordModeOrigin && mode != CoordModePrevious))
1883  {
1884  return -1;
1885  }
1886 
1887  iX = points[0].x; // warning avoidance, put this here, mostly for CoordModePrevious
1888  iY = points[0].y;
1889 
1890  bNoClip = hGC->clip_rgn == None || XEmptyRegion(hGC->clip_rgn);
1891 
1892  for(i1=0, iRval = 0; i1 < npoints; i1++)
1893  {
1894  if(mode == CoordModeOrigin)
1895  {
1896  iX = points[i1].x; // ok this does it again for the first point but so what
1897  iY = points[i1].y;
1898  }
1899  else
1900  {
1901  iX += points[i1].x;
1902  iY += points[i1].y;
1903  }
1904 
1905  if(!bNoClip) // we have a clip region
1906  {
1907  // don't poke the point if it's not inside the clip region
1908  if(!XPointInRegion(hGC->clip_rgn, iX, iY)) // TODO: clip origin???
1909  {
1910  continue; // skip this point
1911  }
1912  }
1913 
1915  i2 = XPutPixel(pImage, iX, iY, hGC->values.foreground);
1917 
1918  if(i2)
1919  {
1920  iRval = i2;
1921  }
1922  }
1923 
1924  return iRval;
1925 }
1926 
1927 int WBXDrawLine(XImage *pImage, WBGC hGC,
1928  int x1, int y1, int x2, int y2)
1929 {
1930 // return -1; // for now
1931 XPoint pt[2];
1932 
1933  pt[0].x = x1;
1934  pt[0].y = y1;
1935  pt[1].x = x2;
1936  pt[1].y = y2;
1937 
1938  return WBXDrawLines(pImage, hGC, &(pt[0]), 2, CoordModeOrigin); // probably the best way
1939 }
1940 
1941 
1942 // for reference, from x11-servers/xorg-server/work/xorg-server-1.18.4/mi/miwideline.c
1943 //void
1944 //miPolylines(DrawablePtr drawable,
1945 // GCPtr gc,
1946 // int mode,
1947 // int n,
1948 // DDXPointPtr points)
1949 //{
1950 // if (gc->lineWidth == 0) {
1951 // if (gc->lineStyle == LineSolid)
1952 // miZeroLine(drawable, gc, mode, n, points);
1953 // else
1954 // miZeroDashLine(drawable, gc, mode, n, points);
1955 // } else {
1956 // if (gc->lineStyle == LineSolid)
1957 // miWideLine(drawable, gc, mode, n, points);
1958 // else
1959 // miWideDash(drawable, gc, mode, n, points);
1960 // }
1961 
1962 int WBXDrawLines(XImage *pImage, WBGC hGC,
1963  XPoint *points, int npoints, int mode)
1964 {
1965 
1966  if(!pImage || !hGC || !points || npoints <= 0 ||
1967  (mode != CoordModeOrigin && mode != CoordModePrevious))
1968  {
1969  return -1;
1970  }
1971 
1972  // by definition, a line width of zero is "minimal line" which is for me the same as 1
1973  // and would be independent of scaling and other factors (so always 1 pixel)
1974  // a pixel width greater than 1 should be the width of the line such that horizontal or
1975  // vertical would be "that many" pixels and I assume diagonal is the same 'appearance'
1976  // width, meaning you gotta do some simple trig or another algorithm that looks similar
1977 
1978 
1979  // TODO: implement this
1980 
1981 
1982  return -1; // for now
1983 }
1984 
1985 int WBXDrawRectangle(XImage *pImage, WBGC hGC,
1986  int x, int y, unsigned int width, unsigned int height)
1987 {
1988 XPoint ptRect[5];
1989 
1990  ptRect[0].x = x;
1991  ptRect[0].y = y;
1992  ptRect[1].x = x + width - 1;
1993  ptRect[1].y = y;
1994  ptRect[2].x = ptRect[1].x;
1995  ptRect[2].y = y + height - 1;
1996  ptRect[3].x = x;
1997  ptRect[3].y = ptRect[2].y;
1998  ptRect[4].x = x;
1999  ptRect[4].y = y; // close up the polygon
2000 
2001  return WBXDrawLines(pImage, hGC, &(ptRect[0]),
2002  sizeof(ptRect) / sizeof(ptRect[0]),
2003  CoordModeOrigin); // probably the best way
2004 }
2005 
2006 int WBXFillRectangle(XImage *pImage, WBGC hGC,
2007  int x, int y, unsigned int width, unsigned int height)
2008 {
2009 int iRval;
2010 
2011 XPoint ptRect[5];
2012 
2013  ptRect[0].x = x;
2014  ptRect[0].y = y;
2015  ptRect[1].x = x + width - 1;
2016  ptRect[1].y = y;
2017  ptRect[2].x = ptRect[1].x;
2018  ptRect[2].y = y + height - 1;
2019  ptRect[3].x = x;
2020  ptRect[3].y = ptRect[2].y;
2021  ptRect[4].x = x;
2022  ptRect[4].y = y; // close up the polygon
2023 
2024  iRval = WBXFillPolygon(pImage, hGC, &(ptRect[0]),
2025  sizeof(ptRect) / sizeof(ptRect[0]),
2026  Convex, CoordModeOrigin); // use 'convex' shape for rectangle
2027 
2028  if(!iRval) // fill worked, now draw the outline
2029  {
2030  // TODO: if foreground color is same as fill color, no need to do this next part
2031 
2032  iRval = WBXDrawLines(pImage, hGC, &(ptRect[0]),
2033  sizeof(ptRect) / sizeof(ptRect[0]),
2034  CoordModeOrigin); // probably the best way
2035  }
2036 
2037  return -1; // for now
2038 }
2039 
2040 int WBXDrawArc(XImage *pImage, WBGC hGC,
2041  int x, int y, unsigned int width, unsigned int height,
2042  int angle1, int angle2)
2043 {
2044 XPoint ptPoly[4096]; // 4k points for my arc polygon
2045 XPoint *pPoly = &(ptPoly[0]); // if I need more points, malloc them.
2046 int iRval, nLines = 0;
2047 
2048 
2049  // TODO: use integer trig WB_isin(X) and WB_icos(X) to determine the x and y offsets
2050  // from the center, and draw a set of lines from point to point. so simple!
2051  //
2052  // NOTE: 'WB_icos(X) uses 'pi == 512' for angular granularity. so a circle is
2053  // literally 1024 "angular units" i.e. 0x400
2054 
2055 
2056  // TODO: implement this
2057 
2058 
2059  // render the poly lines using WBXDrawLines
2060  iRval = 0;
2061 
2062  if(nLines > 0)
2063  {
2064  iRval = WBXDrawLines(pImage, hGC, pPoly, nLines,
2065  CoordModeOrigin); // probably the best way
2066  }
2067 
2068  return iRval;
2069 }
2070 
2071 int WBXFillArc(XImage *pImage, WBGC hGC,
2072  int x, int y, unsigned int width, unsigned int height,
2073  int angle1, int angle2)
2074 {
2075  return -1; // for now (use WBXFillPolygon to do it, similar to what WBXDrawArc does)
2076 }
2077 
2078 int WBXFillPolygon(XImage *pImage, WBGC hGC,
2079  XPoint *points, int npoints, int shape, int mode)
2080 {
2081  if(!pImage || !hGC || !points || npoints <= 0 ||
2082  (shape != Convex && shape != Nonconvex && shape != Complex) ||
2083  (mode != CoordModeOrigin && mode != CoordModePrevious))
2084  {
2085  return -1;
2086  }
2087 
2088  // shape can be Convex, Nonconvex, or Complex
2089  // mode can be CoordModeOrigin or CoordModePrevious
2090 
2091  // basic fill algorithm for arbitrary complex polygon:
2092  //
2093  // 1. get a bounding retangle for it
2094  // 2. start at one corner, go across or down (either works)
2095  // 3. when you reach a boundary for one of the edges, flip the 'fill' bit
2096  // 3a. this could be done with a mono bitmap except when lines overlap
2097  // 3b. so instead this should be done mathematically, except it's slower
2098  // 4. In cases where lines overlap any of the bits, ignore them
2099  //
2100  // a convex polygon makes this quite a bit easier, COULD use a mono bitmap
2101  // to enclose the polygon and a simpler fill method to test the mono bitmap.
2102 
2103 
2104  return -1; // for now
2105 }
2106 
2107 int WBXDrawString(XImage *pImage, WB_FONTC pFont, WBGC hGC,
2108  int x, int y, const char *string, int length)
2109 {
2110 //Display *pDisplay = WBGetDefaultDisplay(); // in case I need one
2111 
2112 
2113 
2114 // TODO: if 'pFont' is NULL, use the font assigned to WBGC
2115 
2116 #ifdef X11WORKBENCH_TOOLKIT_HAVE_XFT
2117  if(pFont->pxftFont)
2118  {
2119 #warning TODO: IMPLEMENT THIS PART for Xft FONTS - this may require legacy font stuff too
2120  }
2121  else
2122 #endif // X11WORKBENCH_TOOLKIT_HAVE_XFT
2123  {
2124  // Legacy mode
2125  //
2126  // Step 1: draw the text in black on white using a monochrome pixmap, left/bottom justified
2127  // Step 2: transfer the pixmap to a 1-plane XY Image
2128  // Step 3: Using 'hGC', do a bitwise copy onto the XImage such that the background is transparent
2129  // with the 'hGC's foreground color and any anti-alising I might want to add...
2130 
2131 
2132  }
2133 
2134  return -1; // for now
2135 }
2136 
2137 
2138 
2139 
2140 
2141 #ifndef NO_DEBUG
2142 static void DebugDumpXpmAttributes(const char *szFunction, int nLine, XPM_ATTRIBUTES *pAttr)
2143 {
2144  WBDebugPrint("%s line %d XPM_ATTRIBUTES contain:\n", szFunction, nLine);
2145 #if defined(X11WORKBENCH_TOOLKIT_HAVE_XPM)
2146  WBDebugPrint(" valuemask: %ld\n", pAttr->valuemask);
2147  WBDebugPrint(" visual: %p\n", pAttr->visual);
2148  WBDebugPrint(" colormap: %p\n", (void *)pAttr->colormap);
2149 #endif // defined(X11WORKBENCH_TOOLKIT_HAVE_XPM)
2150 
2151  WBDebugPrint(" depth: %u\n", pAttr->depth);
2152  WBDebugPrint(" width: %u\n", pAttr->width);
2153  WBDebugPrint(" height: %u\n", pAttr->height);
2154 
2155 // if I'm using libXpm then I have some additional data members...
2156 #if defined(X11WORKBENCH_TOOLKIT_HAVE_XPM)
2157  WBDebugPrint(" x_hotspot: %u\n", pAttr->x_hotspot);
2158  WBDebugPrint(" y_hotspot: %u\n", pAttr->y_hotspot);
2159  WBDebugPrint(" cpp: %u\n", pAttr->cpp);
2160  WBDebugPrint(" pixels: %p\n", pAttr->pixels);
2161  WBDebugPrint(" npixels: %u\n", pAttr->npixels);
2162  WBDebugPrint(" colorsymbols: %p\n", pAttr->colorsymbols);
2163  WBDebugPrint(" numsymbols: %u\n", pAttr->numsymbols);
2164  WBDebugPrint(" rgb_fname: %s\n", pAttr->rgb_fname);
2165  WBDebugPrint(" nextensions: %u\n", pAttr->nextensions);
2166  WBDebugPrint(" extensions: %p\n", pAttr->extensions);
2167  WBDebugPrint(" ncolors: %u\n", pAttr->ncolors);
2168  WBDebugPrint(" colorTable: %p\n", pAttr->colorTable);
2169  WBDebugPrint(" mask_pixel: %u\n", pAttr->mask_pixel);
2170  WBDebugPrint(" exactColors: %c\n", pAttr->exactColors ? 'T' : 'F');
2171  WBDebugPrint(" closeness: %u\n", pAttr->closeness);
2172  WBDebugPrint(" red_closeness: %u\n", pAttr->red_closeness);
2173  WBDebugPrint(" green_closeness: %u\n", pAttr->green_closeness);
2174  WBDebugPrint(" blue_closeness: %u\n", pAttr->blue_closeness);
2175  WBDebugPrint(" color_key: %d\n", pAttr->color_key);
2176  WBDebugPrint(" alloc_pixels: %p\n", pAttr->alloc_pixels);
2177  WBDebugPrint(" nalloc_pixels: %d\n", pAttr->nalloc_pixels);
2178  WBDebugPrint(" alloc_close_colors: %c\n", pAttr->alloc_close_colors ? 'T' : 'F');
2179  WBDebugPrint(" bitmap_format: %d\n", pAttr->bitmap_format);
2180  WBDebugPrint(" alloc_color: %p\n", pAttr->alloc_color);
2181  WBDebugPrint(" free_colors: %p\n", pAttr->free_colors);
2182  WBDebugPrint(" color_closure: %p\n", pAttr->color_closure);
2183 #endif // defined(X11WORKBENCH_TOOLKIT_HAVE_XPM)
2184 }
2185 #endif // !NO_DEBUG
2186 
2187 
2188 void WBDebugDumpColormap(const char *szTitle, const XStandardColormap *pMap)
2189 {
2190 #ifndef NO_DEBUG
2191  WBDebugPrint("WBDebugDumpColormap - %s\n", szTitle);
2192  WBDebugPrint(" XStandardColormap: %p\n", pMap);
2193  if(pMap)
2194  {
2195  WBDebugPrint(" colormap = %lld\n", (WB_UINT64)pMap->colormap);
2196  WBDebugPrint(" red_max = %ld\n", pMap->red_max);
2197  WBDebugPrint(" red_mult = %ld\n", pMap->red_mult);
2198  WBDebugPrint(" green_max = %ld\n", pMap->green_max);
2199  WBDebugPrint(" green_mult = %ld\n", pMap->green_mult);
2200  WBDebugPrint(" blue_max = %ld\n", pMap->blue_max);
2201  WBDebugPrint(" blue_mult = %ld\n", pMap->blue_mult);
2202  WBDebugPrint(" base_pixel = %ld (%08lxH)\n", pMap->base_pixel, pMap->base_pixel);
2203  }
2204 #endif // !NO_DEBUG
2205 }
2206 
2207 
2208 void WBDebugDumpXColor(const char *szTitle, const XColor *pColor)
2209 {
2210 #ifndef NO_DEBUG
2211 char tbuf[32];
2212 
2213  WBDebugPrint("DebugDumpXColor - %s\n", szTitle);
2214  WBDebugPrint(" XColor: %p\n", pColor);
2215  if(pColor)
2216  {
2217  WBDebugPrint(" pixel = %lu \"#%6.6lX\"\n", pColor->pixel, pColor->pixel);
2218  WBDebugPrint(" red = %d\n", pColor->red);
2219  WBDebugPrint(" green = %d\n", pColor->green);
2220  WBDebugPrint(" blue = %d\n", pColor->blue);
2221 
2222  tbuf[0] = 0;
2223  if(pColor->flags & DoRed)
2224  {
2225 // if(tbuf[0])
2226 // {
2227 // strcat(tbuf, " | ");
2228 // }
2229 
2230  strcat(tbuf, "DoRed");
2231  }
2232 
2233  if(pColor->flags & DoGreen)
2234  {
2235  if(tbuf[0])
2236  {
2237  strcat(tbuf, " | ");
2238  }
2239 
2240  strcat(tbuf, "DoGreen");
2241  }
2242 
2243  if(pColor->flags & DoBlue)
2244  {
2245  if(tbuf[0])
2246  {
2247  strcat(tbuf, " | ");
2248  }
2249 
2250  strcat(tbuf, "DoBlue");
2251  }
2252 
2253  if(tbuf[0])
2254  {
2255  WBDebugPrint(" flags = %d %s\n", pColor->flags, tbuf);
2256  }
2257  else
2258  {
2259  WBDebugPrint(" flags = %d (%XH)\n", pColor->flags, pColor->flags);
2260  }
2261  }
2262 #endif // !NO_DEBUG
2263 }
2264 
2265 
GC gc
the associated 'GC'
#define WB_LIKELY(x)
optimization for code branching when condition is 'likely'. use within conditionals
int WBXDrawArc(XImage *pImage, WBGC hGC, int x, int y, unsigned int width, unsigned int height, int angle1, int angle2)
XImage version for XDrawArc()
Pixmap PXM_GetIconPixmap(int idIcon, XPM_ATTRIBUTES *pAttr, Pixmap *pMask)
Create Icon pixmap pair using pre-defined resource ID.
void PXM_RGBToYUV(int iR, int iG, int iB, int *piY, int *piU, int *piV)
Convert R, G, B values to Y, U, V with 0-255 range.
void WBDefaultStandardColormap(Display *pDisplay, XStandardColormap *pMap)
returns a default XStandardColormap structure for the default screen of the specified display
unsigned char WB_isqrt(unsigned char iVal)
integer square root of a value 0-255
XImage * WBXImageFromRegion(Region rgnSource, int width, int height)
Create a Region from an XImage.
int WBXFillPolygon(XImage *pImage, WBGC hGC, XPoint *points, int npoints, int shape, int mode)
XImage version for XFillPolygon()
void PXM_YUVToRGB(int iY, int iU, int iV, int *piR, int *piG, int *piB)
Convert Y, U, V values to R, G, B with 0-255 range.
void PXM_RegisterAppIcons(char *ppRegAppLarge[], char *ppRegAppSmall[])
Icon Registration for application 'large' and 'small' icons.
Pixmap PXM_LoadPixmap(char *ppXPM[], XPM_ATTRIBUTES *pAttr, Pixmap *pMask)
Create pixmap or pixmap pair using an XPM array.
unsigned int width
Compatibility structure for use with MyLoadPixmapFromData() whenever libXpm is not in use.
int WBXDrawRectangle(XImage *pImage, WBGC hGC, int x, int y, unsigned int width, unsigned int height)
XImage version for XDrawRectangle()
int WBXPutImage(Display *pDisplay, Drawable dw, WBGC gc, XImage *pImage, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height)
Write contents of an XImage onto a Drawable.
#define XPM_FREE_ATTRIBUTES(pAttr)
Platform helper macro to free XPM_ATTRIBUTES filled in by XPM_CREATE_PIXMAP_FROM_DATA()
void PXM_OnExit(void)
Frees resources allocated by Pixmap utility functions.
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
internal wrapper struct for X11 'geometry' definition
void PXM_RGBToPixel(XStandardColormap *pMap, XColor *pColor)
Icon Registration for application 'large' and 'small' icons.
int WBXFillRectangle(XImage *pImage, WBGC hGC, int x, int y, unsigned int width, unsigned int height)
XImage version for XFillRectangle()
int width
The width of the returned pixmaps.
void PXM_PixelToRGB(XStandardColormap *pMap, XColor *pColor)
Convert the pixel menber of an XColor to RGB.
Pixmap PXM_GetIconPixmapFromAtom(Atom aIcon, XPM_ATTRIBUTES *pAttr, Pixmap *pMask)
Create Icon pixmap pair using a registered or pre-defined resource ID.
void * WBReAlloc(void *pBuf, int nNewSize)
High performance memory sub-allocator 're-allocate'.
int WBXDrawLine(XImage *pImage, WBGC hGC, int x1, int y1, int x2, int y2)
XImage version for XDrawLines()
XImage * WBXCopyImage(Display *pDisplay, XImage *pImage)
Make a copy of an XImage.
Pixmap PXM_ImageToPixmap(Display *pDisplay, Drawable dw, XImage *pImage, unsigned long clrFGPixel, unsigned long clrBGPixel)
Convert 'locally stored' XImage to 'server object' Pixmap.
int WBXShmQueryExtension(Display *pDisplay)
Indicates whether the 'XShm' extensions are available (libXext)
void WBDebugDumpColormap(const char *szTitle, const XStandardColormap *pMap)
Dump XStandardColormap members for debugging.
unsigned char WB_icos0(unsigned char iVal)
integer 255 * cos(iVal * pi / 512) calculation via lookup table (legacy, to be removed?...
void * WBAlloc(int nSize)
High performance memory sub-allocator 'allocate'.
#define END_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro follows the call(s)
void WBDebugDumpXColor(const char *szTitle, const XColor *pColor)
Dump XColor members for debugging.
unsigned long long WB_UINT64
Platform abstract unsigned 64-bit integer.
int WBXDrawPoint(XImage *pImage, WBGC hGC, int x, int y)
XImage version for XDrawPoint()
int WBXDrawString(XImage *pImage, WB_FONTC pFont, WBGC hGC, int x, int y, const char *string, int length)
XImage version for XDrawString() or DTDrawString()
#define WB_ERROR_PRINT(...)
Preferred method of implementing an 'error level' debug message for all subsystems.
Definition: debug_helper.h:474
Window WBGetHiddenHelperWindow(void)
Returns a special 'hidden' window used for information purposes.
int WBXDrawPoints(XImage *pImage, WBGC hGC, XPoint *points, int npoints, int mode)
XImage version for XDrawPoints()
void WBFree(void *pBuf)
High performance memory sub-allocator 'free'.
XGCValues values
cached XGCValues for the GC
WBGC WBCreateGC(Display *pDisplay, Drawable dw, unsigned long valuemask, const XGCValues *values)
Creates a WBGC, wrapper for XCreateGC()
XImage * PXM_PixmapToImage(Display *pDisplay, Pixmap pxImage)
Convert pixmap to image (a wrapper for XGetImage on a pixmap)
Atom WBGetAtom(Display *pDisplay, const char *szAtomName)
Lookup and/or allocate an internal Atom for a named string (lookups include X11 atoms)
XImage * WBXGetImage(Display *pDisplay, Drawable dw, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)
Read contents of a Drawable onto an XImage.
void WBSimpleAntiAliasImage(const XStandardColormap *pMap, XImage *pImage, unsigned long lPixel, WB_GEOM *pGeom)
Simple anti-alias of an XImage using foreground pixel color.
void PXM_RGBToHSV(int iR, int iG, int iB, int *piH, int *piS, int *piV)
Convert R, G, B values to H, S, V with 0-255 range.
int WBXDestroyImage(XImage *pImage)
Destroy an XImage - call this instead of XDestroyImage()
unsigned int height
char WB_icos(int iVal)
integer 127 * cos(iVal * pi / 512) calculation via lookup table
void WBFreeGC(WBGC hGC)
Free resources for a WBGC, wrapper for XFreeGC()
Pixmap PXM_ImageToPixmap0(Display *pDisplay, Drawable dw, XImage *pImage)
Convert 'locally stored' XImage to 'server object' Pixmap using default FG/BG colors for monochrome.
#define RGB_FROM_XCOLOR(X, R, G, B)
Simple RGB assignment from pixel, 0-65535 RGB.
int depth
depth of the returned 'image' pixmap. The mask pixmap always has a depth of '1'.
#define BEGIN_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro precedes the call(s)
Region clip_rgn
clipping region (or None to use clip_image) - owned by the object
int WBXDrawLines(XImage *pImage, WBGC hGC, XPoint *points, int npoints, int mode)
XImage version for XDrawLine()
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
An allocated structure containing XFontStruct, XFontInfo, and XftFont [as applicable] for a specified...
Definition: font_helper.h:152
#define WB_IF_DEBUG_LEVEL(L)
Preferred method of implementing conditional debug 'if block' code.
Definition: debug_helper.h:404
#define XPM_CREATE_PIXMAP_FROM_DATA(A, B, C, D, E, F)
Platform helper macro to create a pixmap from data.
internal wrapper struct for GC with local cache
Pixmap PXM_CopyPixmap(Display *pDisplay, Drawable dw, Pixmap pxSource)
Copy a pixmap for the specified Display and Drawable.
void PXM_HSVToRGB(int iH, int iS, int iV, int *piR, int *piG, int *piB)
Convert H, S, V values to R, G, B with 0-255 range.
void WBSimpleAntiAliasPixmap(Display *pDisplay, const XStandardColormap *pMap, Pixmap pxImage, unsigned long lPixel, WB_GEOM *pGeom)
Simple anti-alias of a Pixmap using foreground pixel color.
int WBXFillArc(XImage *pImage, WBGC hGC, int x, int y, unsigned int width, unsigned int height, int angle1, int angle2)
XImage version for XFillArc()
int height
height of the returned pixmaps
#define RGB_TO_XCOLOR(R, G, B, X)
Simple RGB assignment to pixel, 0-65535 RGB.
Region WBXImageToRegion(const XImage *pImage)
Create a Region from an XImage.