X11 Work Bench Toolkit  1.0
window_dressing.c
Go to the documentation of this file.
1 
2 // _ _ _ _ //
3 // __ __(_) _ __ __| | ___ __ __ __| | _ __ ___ ___ ___ (_) _ __ __ _ ___ //
4 // \ \ /\ / /| || '_ \ / _` | / _ \\ \ /\ / / / _` || '__|/ _ \/ __|/ __|| || '_ \ / _` | / __| //
5 // \ V V / | || | | || (_| || (_) |\ V V / | (_| || | | __/\__ \\__ \| || | | || (_| | _| (__ //
6 // \_/\_/ |_||_| |_| \__,_| \___/ \_/\_/_____\__,_||_| \___||___/|___/|_||_| |_| \__, |(_)\___| //
7 // |_____| |___/ //
8 // //
9 // Utilities for painting and handling standard components of windows //
10 // //
12 
13 /*****************************************************************************
14 
15  X11workbench - X11 programmer's 'work bench' application and toolkit
16  Copyright (c) 2010-2016 by Bob Frazier (aka 'Big Bad Bombastic Bob')
17  all rights reserved
18 
19  DISCLAIMER: The X11workbench application and toolkit software are supplied
20  'as-is', with no warranties, either implied or explicit.
21  Any claims to alleged functionality or features should be
22  considered 'preliminary', and might not function as advertised.
23 
24  BSD-like license:
25 
26  There is no restriction as to what you can do with this software, so long
27  as you include the above copyright notice and DISCLAIMER for any distributed
28  work that is equal to or derived from this one, along with this paragraph
29  that explains the terms of the license if the source is also being made
30  available. A "derived work" describes a work that uses a significant portion
31  of the source files or algorithms that are included with this one.
32  Specifically excluded from this are files that were generated by the software,
33  or anything that is included with the software that is part of another package
34  (such as files that were created or added during the 'configure' process).
35  Specifically included is the use of part or all of any of the X11 workbench
36  toolkit source or header files in your distributed application. If you do not
37  ship the source, the above copyright statement is still required to be placed
38  in a reasonably prominent place, such as documentation, splash screens, and/or
39  'about the application' dialog boxes.
40 
41  Use and distribution are in accordance with GPL, LGPL, and/or the above
42  BSD-like license. See COPYING and README files for more information.
43 
44 
45  Additional information at http://sourceforge.net/projects/X11workbench
46 
47 ******************************************************************************/
48 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <memory.h>
56 #include <string.h>
57 #include <strings.h>
58 #include <errno.h>
59 #include <X11/Xlib.h>
60 
61 #include "window_dressing.h"
62 #include "pixmap_helper.h"
63 #include "conf_help.h"
64 #include "draw_text.h"
65 
66 
67 static XColor clrScrollFG,
68  clrScrollBG,
69  clrScrollAFG,
70  clrScrollABG,
71  clrScrollHFG,
72  clrScrollHBG,
73  clrScrollBD,
74  clrScrollBD2,
75  clrScrollBD3;
76 
79 static int iInitScrollColorFlag = 0;
80 
83 #define LOAD_COLOR0(X,Y) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) > 0) { }
84 
86 #define LOAD_COLOR(X,Y,Z) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) <= 0){ WB_WARN_PRINT("%s - WARNING: can't find color %s, using default value %s\n", __FUNCTION__, X, Z); strcpy(Y,Z); }
87 
90 static void CheckInitScrollColors(void)
91 {
92  // TODO: consider freeing the colors with XFreeColors on exit
93  // TODO: consider not even bothering with 'XAllocColor' and just use PXM_RGBToPixel()
94 
96  {
97  static const char *szBorder2="#FFFFFF", *szBorder2W="#C8C6C0", *szBorder3="#9C9A94"; // for 3D borders
98  char szFG[16], szBG[16], szBD[16], szHFG[16], szHBG[16], szAFG[16], szABG[16]; // must be at least 14 characters
99  static const char szFGName[]="Scrollbar.foreground";
100  static const char szBGName[]="Scrollbar.background";
101  static const char szHFGName[]="Scrollbar.highlightForeground";
102  static const char szHBGName[]="Scrollbar.highlightBackground";
103  static const char szAFGName[]="Scrollbar.activeForeground";
104  static const char szABGName[]="Scrollbar.activeBackground";
105  static const char szBDName[]="Scrollbar.border";
106 
107  Colormap colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
108 
109 
110  LOAD_COLOR0(szFGName,szFG) else LOAD_COLOR0("*Dialog.foreground",szFG) else LOAD_COLOR0("*Form.foreground", szFG)
111  else LOAD_COLOR0("*WmDialogShell.foreground",szFG) else LOAD_COLOR0("*WmForm.foreground", szFG)
112  else LOAD_COLOR("*foreground", szFG, "#000000");
113 
114  LOAD_COLOR0(szBGName,szBG) else LOAD_COLOR0("*Dialog.background",szBG) else LOAD_COLOR0("*Form.background", szBG)
115  else LOAD_COLOR0("*WmDialogShell.background",szBG)
116  else LOAD_COLOR("*WmForm.background", szBG, "#dcdad5"); // default for gnome is dcdad5
117 
118  LOAD_COLOR(szHFGName,szHFG,szFG);
119  LOAD_COLOR(szHBGName,szHBG,szBG);
120  LOAD_COLOR(szAFGName,szAFG,szFG);
121  LOAD_COLOR(szABGName,szABG,szBG);
122 
123  LOAD_COLOR0(szBDName,szBD) else LOAD_COLOR0("*Dialog.border",szBD) else LOAD_COLOR0("*Form.border", szBD)
124  else LOAD_COLOR0("*WmDialogShell.border",szBD) else LOAD_COLOR0("*WmForm.border", szBD)
125  else LOAD_COLOR0("*borderColor", szBD)
126  else LOAD_COLOR("*border", szBD, "black"); // default for gnome
127 
128  XParseColor(WBGetDefaultDisplay(), colormap, szFG, &clrScrollFG);
129  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollFG);
130  XParseColor(WBGetDefaultDisplay(), colormap, szBG, &clrScrollBG);
131  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBG);
132  XParseColor(WBGetDefaultDisplay(), colormap, szAFG, &clrScrollAFG);
133  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollAFG);
134  XParseColor(WBGetDefaultDisplay(), colormap, szABG, &clrScrollABG);
135  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollABG);
136  XParseColor(WBGetDefaultDisplay(), colormap, szHFG, &clrScrollHFG);
137  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollHFG);
138  XParseColor(WBGetDefaultDisplay(), colormap, szHBG, &clrScrollHBG);
139  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollHBG);
140  XParseColor(WBGetDefaultDisplay(), colormap, szBD, &clrScrollBD);
141 
142  // 3D border colors for now these are hard-coded - later derive them from FG and BG colors
143  if(clrScrollBG.red >= 60000 && clrScrollBG.green >= 60000 &&
144  clrScrollBG.blue >= 60000) // note see man page on XColor, values 0 through 65535 for RGB
145  {
146  XParseColor(WBGetDefaultDisplay(), colormap, szBorder2W, &clrScrollBD2);
147  }
148  else
149  {
150  XParseColor(WBGetDefaultDisplay(), colormap, szBorder2, &clrScrollBD2);
151  }
152 
153  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBD2);
154  XParseColor(WBGetDefaultDisplay(), colormap, szBorder3, &clrScrollBD3);
155  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBD3);
156 
158  }
159 }
160 
161 
164 static unsigned char isqrt(unsigned char iVal)
165 {
166 unsigned char aAnswers[256] =
167 {
168  0,1,1,2,2,2,2,3,3,3,3,3,3,4,4,4,
169  4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,
170  6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,
171  7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,
172  8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,
173  9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,
174  10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,
175  11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
176  11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,
177  12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,
178  13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
179  13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,
180  14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
181  14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,
182  15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
183  15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16
184 };
185 
186 
187  return aAnswers[iVal & 0xff];
188 }
189 
192 static unsigned char icos(unsigned char iVal)
193 {
194 unsigned char aAnswers[256] =
195 {
196 255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,
197 254,254,253,253,253,253,253,252,252,252,252,252,251,251,251,250,
198 250,250,249,249,249,248,248,248,247,247,247,246,246,245,245,244,
199 244,244,243,243,242,242,241,241,240,240,239,238,238,237,237,236,
200 236,235,234,234,233,232,232,231,231,230,229,228,228,227,226,226,
201 225,224,223,223,222,221,220,220,219,218,217,216,215,215,214,213,
202 212,211,210,209,208,208,207,206,205,204,203,202,201,200,199,198,
203 197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,181,
204 180,179,178,177,176,175,174,172,171,170,169,168,167,165,164,163,
205 162,161,159,158,157,156,154,153,152,151,149,148,147,146,144,143,
206 142,140,139,138,136,135,134,132,131,130,128,127,126,124,123,122,
207 120,119,117,116,115,113,112,110,109,108,106,105,103,102,100,99,
208 98,96,95,93,92,90,89,87,86,84,83,81,80,79,77,76,
209 74,73,71,70,68,67,65,63,62,60,59,57,56,54,53,51,
210 50,48,47,45,44,42,41,39,37,36,34,33,31,30,28,27,
211 25,23,22,20,19,17,16,14,13,11,9,8,6,5,3,2
212 };
213 
214 
215  return aAnswers[iVal & 0xff];
216 }
217 
218 
219 #if 0 /* this function not currently used. consider removeing it in a refactor */
220 static char ilog2n(unsigned char y)
221 {
222  if(y & 0x08)
223  return 4;
224  else if(y & 0x04)
225  return 3;
226  else if(y & 0x02)
227  return 2;
228  else if(y & 0x01)
229  return 1;
230  else
231  return 0;
232 }
233 #endif // 0
234 
235 #if 0 /* this function not currently used. consider removeing it in a refactor */
236 static char ilog2c(unsigned char y)
237 {
238  if(y & 0xf0)
239  return ilog2n(y >> 4) + 4;
240 
241  return ilog2n(y);
242 }
243 #endif // 0
244 
245 #if 0 /* this function not currently used. consider removeing it in a refactor */
246 static int ilog2s(unsigned short y)
247 {
248  if(y & 0xff00)
249  {
250  return ilog2c((unsigned char)(y >> 8)) + 8;
251  }
252 
253  return ilog2c((unsigned char)y);
254 }
255 #endif // 0
256 
257 #if 0 /* this function not currently used. consider removeing it in a refactor */
258 static int ilog2(unsigned int y)
259 {
260  if(y & 0xffff0000)
261  {
262  return ilog2s((unsigned short)(y >> 16)) + 16;
263  }
264 
265  return ilog2s((unsigned short)y);
266 }
267 #endif // 0
268 
269 #if 0 /* this function not currently used. consider removeing it in a refactor */
270 static int ilog2ll(WB_UINT64 y)
271 {
272  if(y & 0xffffffff00000000LL)
273  {
274  return ilog2((unsigned int)(y >> 32)) + 32;
275  }
276 
277  return ilog2((unsigned int)y);
278 }
279 #endif // 0
280 
281 void WBCalcHScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth,
282  int iHScrollHeight, int nListItems, int nPos)
283 {
284 int /*iKnobSize, iKnobPos,*/ iBarHeight, iBarWidth;
285 //int i1, i2;
286 
287  iBarHeight = pgeomClient->height;
288  iBarWidth = pgeomClient->width;
289 
290  if(pScrollInfo->iVBarHeight == iBarHeight &&
291  pScrollInfo->iHBarWidth == iBarWidth &&
292  pScrollInfo->iVBarHeight == iBarHeight &&
293  pScrollInfo->iHBarWidth == iBarWidth &&
294  pScrollInfo->iVKnob >= 0 &&
295  pScrollInfo->iVKnobSize >= 0 &&
296  pScrollInfo->iVPos == nPos &&
297  pScrollInfo->iVMin == 0 &&
298  pScrollInfo->iVMax == (nListItems - 1))
299  {
300  // assume it's set up correctly
301 
302 // WB_ERROR_TEXT("TEMPORARY: short cycling calc scroll info\n");
303 // return;
304  }
305 
306  if(pScrollInfo->iVBarHeight != iBarHeight ||
307  pScrollInfo->iHBarWidth != iBarWidth ||
308  pScrollInfo->iVBarHeight != iBarHeight ||
309  pScrollInfo->iHBarWidth != iBarWidth)
310  {
311  // client size change detected
312  // zero out the V Scroll info so that it forces re-calculation next time
313  pScrollInfo->iVKnob = pScrollInfo->iVKnobSize = pScrollInfo->iVPos = pScrollInfo->iVMin = pScrollInfo->iVMax = 0;
314  }
315 
316  pScrollInfo->iVScrollWidth = iVScrollWidth;
317  pScrollInfo->iHScrollHeight = iHScrollHeight;
318  pScrollInfo->iVBarHeight = iBarHeight;
319  pScrollInfo->iHBarWidth = iBarWidth;
320 
321  pScrollInfo->iHMin = 0;
322  pScrollInfo->iHMax = nListItems - 1;
323  if(nPos == -1 ||
324  (nPos >= 0 && nPos < nListItems))
325  {
326  pScrollInfo->iHPos = nPos;
327  }
328  else
329  {
330  pScrollInfo->iHPos = nPos = -1;
331  }
332 
333 
334 
335  // TODO: calculate the geometries
336 
337 }
338 
339 int WBCalcVScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iY)
340 {
341  if(pScrollInfo &&
342  (pScrollInfo->iVMax >= pScrollInfo->iVMin))
343  {
344  int nListItems = pScrollInfo->iVMax - pScrollInfo->iVMin + 1;
345  int iKnobSize = pScrollInfo->geomVKnob.height;
346  int iKnobPos = iY - iKnobSize / 3
347  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height);
348 
349  int iBarScrollArea = pScrollInfo->geomVDown.y
350  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height)
351  - iKnobSize
352  - 1; // inclusive value
353 
354  if(iBarScrollArea <= 0)
355  {
356  return pScrollInfo->iVMin; // always assume 1st item's index
357  }
358  else
359  {
360  int nPos = (WB_INT64)iKnobPos * (WB_INT64)(nListItems - 1)
361  / (WB_INT64)iBarScrollArea;
362 
363  WB_ERROR_PRINT("TEMPORARY: iY=%d; nLI=%d KS=%d KP=%d BSA=%d nP=%d\n",
364  iY, nListItems, iKnobSize, iKnobPos, iBarScrollArea, nPos);
365 
366  if(nPos < pScrollInfo->iVMin)
367  {
368  return pScrollInfo->iVMin;
369  }
370  else if(nPos > pScrollInfo->iVMax)
371  {
372  return pScrollInfo->iVMax;
373  }
374  else
375  {
376  return nPos;
377  }
378  }
379  }
380 
381  return -1; // can't evaluate, so return -1
382 }
383 
384 int WBCalcHScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iX)
385 {
386  return -1; // for now, until implemented
387 }
388 
389 void WBCalcVScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth,
390  int iHScrollHeight, int nListItems, int nPos)
391 {
392 int iKnobSize, iKnobPos, iBarHeight, iBarWidth;
393 int i1, i2;
394 
395  iBarHeight = pgeomClient->height;
396  iBarWidth = pgeomClient->width;
397 
398  if(pScrollInfo->iVBarHeight == iBarHeight &&
399  pScrollInfo->iHBarWidth == iBarWidth &&
400  pScrollInfo->iVBarHeight == iBarHeight &&
401  pScrollInfo->iHBarWidth == iBarWidth &&
402  pScrollInfo->iVKnob >= 0 &&
403  pScrollInfo->iVKnobSize >= 0 &&
404  pScrollInfo->iVPos == nPos &&
405  pScrollInfo->iVMin == 0 &&
406  pScrollInfo->iVMax == (nListItems - 1))
407  {
408  // assume it's set up correctly
409 
410 // WB_ERROR_TEXT("TEMPORARY: short cycling calc scroll info\n");
411 // return;
412  }
413 
414  if(pScrollInfo->iVBarHeight != iBarHeight ||
415  pScrollInfo->iHBarWidth != iBarWidth ||
416  pScrollInfo->iVBarHeight != iBarHeight ||
417  pScrollInfo->iHBarWidth != iBarWidth)
418  {
419  // client size change detected
420  // zero out the H Scroll info so that it forces re-calculation next time
421  pScrollInfo->iHKnob = pScrollInfo->iHKnobSize = pScrollInfo->iHPos = pScrollInfo->iHMin = pScrollInfo->iHMax = 0;
422  }
423 
424 
425 // WB_ERROR_PRINT("TEMPORARY: %d %d %d %d %d\n",
426 // iBarHeight, iVScrollWidth, iHScrollHeight, nListItems, nPos);
427 
428  pScrollInfo->iVScrollWidth = iVScrollWidth;
429  pScrollInfo->iHScrollHeight = iHScrollHeight;
430  pScrollInfo->iVBarHeight = iBarHeight;
431  pScrollInfo->iHBarWidth = iBarWidth;
432 
433  pScrollInfo->iVMin = 0;
434  pScrollInfo->iVMax = nListItems - 1;
435  if(nPos == -1 ||
436  (nPos >= 0 && nPos < nListItems))
437  {
438  pScrollInfo->iVPos = nPos;
439  }
440  else
441  {
442  pScrollInfo->iVPos = nPos = -1;
443  }
444 
445  // knob height equals 'nListItems / nListItems!' multiplied by
446  // the available knob height, for a minimum value of 'iHScrollHeight'
447 
448  iKnobSize = (iBarHeight - 4 * iHScrollHeight - 2);
449  if(iKnobSize > iHScrollHeight / 2)
450  {
451  i1 = iHScrollHeight * (2 * iHScrollHeight + 1); // 'twice scroll height' factorial
452  i2 = iHScrollHeight * 2;
453 
454  while(i2 > 2 && i1 > iKnobSize) // using the above starting point get 'max factorial less than height'
455  {
456  i1 -= i2;
457  i2--;
458  }
459 
460  if(nListItems >= i2) // more than twice scroll height?
461  {
462  if(nListItems > iKnobSize || iKnobSize - i1 < iHScrollHeight / 2)
463  {
464  iKnobSize = -1; // to fix later
465  }
466  else
467  {
468  iKnobSize -= i1; // twice scroll height factorial
469  iKnobSize -= (nListItems - iHScrollHeight * 2 + 1);
470  }
471  }
472  else
473  {
474  iKnobSize -= i1 // 'twice knob height' factorial
475  - (nListItems + 1) * nListItems / 2; // 'nListItems' factorial
476  }
477 
478  if(iKnobSize < 3 * iHScrollHeight / 4)
479  {
480  iKnobSize = 3 * iHScrollHeight / 4; // minimum size
481  }
482  }
483  else
484  {
485  iKnobSize = 3 * iHScrollHeight / 4; // worst case use this anyway
486  }
487 
488  // cache these geometries because I need them for mouse handling
489 
490  pScrollInfo->geomVBar.y = pgeomClient->y + 1;
491  pScrollInfo->geomVBar.height = pgeomClient->height - 2;
492  pScrollInfo->geomVBar.width = pScrollInfo->iVScrollWidth;
493  pScrollInfo->geomVBar.x = pgeomClient->x + pgeomClient->width
494  - pScrollInfo->geomVBar.width - 1;
495 
496  pScrollInfo->geomVDown.x = pScrollInfo->geomVUp.x
497  = pScrollInfo->geomVBar.x + 1;
498  pScrollInfo->geomVDown.width = pScrollInfo->geomVUp.width
499  = pScrollInfo->geomVBar.width - 2;
500  pScrollInfo->geomVDown.height = pScrollInfo->geomVUp.height
501  = pScrollInfo->iHScrollHeight - 1;
502 
503  pScrollInfo->geomVUp.y = pScrollInfo->geomVBar.y + 1;
504  pScrollInfo->geomVDown.y = pScrollInfo->geomVBar.y
505  + pScrollInfo->geomVBar.height
506  - pScrollInfo->geomVDown.height - 1;
507 
508  pScrollInfo->geomVKnob.x = pScrollInfo->geomVDown.x;
509  pScrollInfo->geomVKnob.width = pScrollInfo->geomVDown.width;
510  pScrollInfo->geomVKnob.height = pScrollInfo->iVKnobSize
511  = iKnobSize;
512 
513  // now that I have a reasonable estimate of the knob size, calculate
514  // the starting vertical position of the knob
515 
516  if(nPos <= 0 || nListItems <= 0)
517  {
518  iKnobPos = 0;
519  }
520  else
521  {
522  int iBarScrollArea = pScrollInfo->geomVDown.y
523  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height)
524  - iKnobSize
525  - 1; // inclusive value
526 
527  if(nPos >= (nListItems - 1))
528  {
529  iKnobPos = iBarScrollArea;
530  }
531  else
532  {
533  iKnobPos = (WB_INT64)nPos * (WB_INT64)iBarScrollArea
534  / (WB_INT64)(nListItems - 1);
535  }
536  }
537 
538 
539  pScrollInfo->geomVKnob.y = (pScrollInfo->iVKnob = iKnobPos)
540  + pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height;
541 
542  // fixed values go here
543  pScrollInfo->geomVBar.border = 1;
544  pScrollInfo->geomVUp.border = 0;
545  pScrollInfo->geomVDown.border = 0;
546  pScrollInfo->geomVKnob.border = 0;
547 
548 }
549 
550 void WBDrawBorderRect(Display *pDisplay, Drawable wID, GC gc,
551  WB_GEOM *pgeomBorder, unsigned long lBorderColor)
552 {
553 XPoint xpt[5];
554 
555  XSetForeground(pDisplay, gc, lBorderColor);
556 
557  xpt[0].x=pgeomBorder->x;
558  xpt[0].y=pgeomBorder->y;
559 
560  xpt[1].x = xpt[0].x
561  + pgeomBorder->width
562  - 1; // 'inclusive' values
563 
564  xpt[1].y = xpt[0].y;
565 
566  xpt[2].x = xpt[1].x;
567  xpt[2].y = xpt[1].y
568  + pgeomBorder->height
569  - 1;
570 
571  xpt[3].x = xpt[0].x;
572  xpt[3].y = xpt[2].y;
573 
574  xpt[4].x = xpt[0].x;
575  xpt[4].y = xpt[0].y + 1; // exclude final point
576 
577  XDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
578 }
579 
580 void WBDraw3DBorderRect(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomBorder,
581  unsigned long lBorderColor1, unsigned long lBorderColor2)
582 {
583 XPoint xpt[4];
584 XColor clr;
585 int iR, iG, iB;
586 
587 
588  XSetForeground(pDisplay, gc, lBorderColor1);
589  xpt[0].x = pgeomBorder->x;
590  xpt[0].y = pgeomBorder->y
591  + pgeomBorder->height - 1 - 1; // exclude first point
592 
593  xpt[1].x = xpt[0].x;
594  xpt[1].y = pgeomBorder->y;
595 
596  xpt[2].x = xpt[0].x
597  + pgeomBorder->width - 1 - 1; // exclude last point
598  xpt[2].y = xpt[1].y;
599 
600  XDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
601 
602  XSetForeground(pDisplay, gc, lBorderColor2);
603 
604  xpt[0].x = pgeomBorder->x
605  + pgeomBorder->width - 1;
606  xpt[0].y = pgeomBorder->y + 1; // exclude first point
607 
608  xpt[1].x = xpt[0].x;
609  xpt[1].y = pgeomBorder->y
610  + pgeomBorder->height - 1;
611 
612  xpt[2].x = pgeomBorder->x + 1; // exclude final point
613  xpt[2].y = xpt[1].y;
614 
615  XDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
616 
617  // Use the RGB info to calculate an 'average' color for the corners
618 
619  bzero(&clr, sizeof(clr));
620  clr.pixel = lBorderColor1;
621 
622  PXM_PixelToRGB(NULL, &clr);
623 
624  iR = (clr.flags & DoRed) ? (unsigned int)clr.red : 0;
625  iG = (clr.flags & DoGreen) ? (unsigned int)clr.green : 0;
626  iB = (clr.flags & DoBlue) ? (unsigned int)clr.blue : 0;
627 
628  bzero(&clr, sizeof(clr));
629  clr.pixel = lBorderColor2;
630 
631  PXM_PixelToRGB(NULL, &clr);
632 
633  iR += (clr.flags & DoRed) ? (unsigned int)clr.red : 0;
634  iG += (clr.flags & DoGreen) ? (unsigned int)clr.green : 0;
635  iB += (clr.flags & DoBlue) ? (unsigned int)clr.blue : 0;
636 
637  bzero(&clr, sizeof(clr));
638 
639  clr.red = iR >> 1;
640  clr.green = iG >> 1;
641  clr.blue = iB >> 1;
642 
643  PXM_RGBToPixel(NULL, &clr); // TODO: alloc the color as well?
644 
645 // WB_ERROR_PRINT("TEMPORARY: %s - average of %08xH and %08xH is %08xH (%d, %d, %d)\n", __FUNCTION__,
646 // (unsigned int)lBorderColor1, (unsigned int)lBorderColor2,
647 // (unsigned int)clr.pixel, clr.red, clr.green, clr.blue);
648 
649  XSetForeground(pDisplay, gc, clr.pixel);
650 
651  xpt[0].x = pgeomBorder->x;
652  xpt[1].y = pgeomBorder->y;
653 
654  xpt[1].x = xpt[0].x + pgeomBorder->width - 1;
655  xpt[0].y = xpt[1].y + pgeomBorder->height - 1;
656 
657  XDrawPoints(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
658 
659  XSetForeground(pDisplay, gc, lBorderColor1);
660 
661 }
662 
663 void WBDrawDashedRect(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
664 {
665 static const char dash_list[4]={1,2,2,1};
666 GC gc2;
667 
668 
669  gc2 = WBGetWindowCopyGC2(wID, gc);
670 
671  if(gc2)
672  {
673  WBDrawBorderRect(pDisplay, wID, gc2, pgeomRect, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
674  XSetDashes(pDisplay, gc2, 1, dash_list, 4);
675  XSetLineAttributes(pDisplay, gc2, 1, LineOnOffDash, CapNotLast, JoinBevel);
676  XSetBackground(pDisplay, gc2, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
677  WBDrawBorderRect(pDisplay, wID, gc2, pgeomRect, lColor);
678 
679  XFreeGC(pDisplay, gc2);
680  }
681  else
682  {
683  WB_ERROR_PRINT("%s:%d - unable to create GC\n", __FUNCTION__, __LINE__);
684  }
685 }
686 
687 // this assumes WB_SCROLLINFO is valid. TO make it so, call ListCalcVScrollBar or similar
688 void WBPaintVScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID,
689  GC gc, WB_GEOM *pgeomClient)
690 {
692 
693  // fill scrollbar with background color
694  XSetForeground(pDisplay, gc, clrScrollBG.pixel);
695  XFillRectangle(pDisplay, wID, gc, pScrollInfo->geomVBar.x - 1, pScrollInfo->geomVBar.y,
696  pScrollInfo->geomVBar.width + 1, pScrollInfo->geomVBar.height);
697 
698  // draw 3D borders around everything
699 
700  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVBar),
701  clrScrollBD3.pixel, clrScrollBD2.pixel);
702 
703  // if the scrollbar is DISABLED, do not draw the rest of it
704  if(pScrollInfo->iVPos < pScrollInfo->iVMin ||
705  pScrollInfo->iVPos > pScrollInfo->iVMax ||
706  pScrollInfo->iVMax < pScrollInfo->iVMin)
707  {
708 // WB_ERROR_PRINT("TEMPORARY: grey out %d %d %d\n",
709 // pScrollInfo->iVPos, pScrollInfo->iVMin, pScrollInfo->iVMax);
710  return; // I am done (greyed out bar)
711  }
712 
713  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVUp),
714  clrScrollBD2.pixel, clrScrollBD3.pixel);
715  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVDown),
716  clrScrollBD2.pixel, clrScrollBD3.pixel);
717  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVKnob),
718  clrScrollBD2.pixel, clrScrollBD3.pixel);
719 
720  // draw arrows
721 
722  WBDrawUpArrow(pDisplay, wID, gc, &(pScrollInfo->geomVUp), clrScrollFG.pixel);
723  WBDrawDownArrow(pDisplay, wID, gc, &(pScrollInfo->geomVDown), clrScrollFG.pixel);
724 }
725 
726 // this assumes WB_SCROLLINFO is valid. TO make it so, call ListCalcHScrollBar or similar
727 void WBPaintHScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID,
728  GC gc, WB_GEOM *pgeomClient)
729 {
731 
732  // fill scrollbar with background color
733  XSetForeground(pDisplay, gc, clrScrollBG.pixel);
734  XFillRectangle(pDisplay, wID, gc, pScrollInfo->geomHBar.x - 1, pScrollInfo->geomHBar.y,
735  pScrollInfo->geomHBar.width + 1, pScrollInfo->geomHBar.height);
736 
737  // draw 3D borders around everything
738 
739  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHBar),
740  clrScrollBD3.pixel, clrScrollBD2.pixel);
741 
742  // if the scrollbar is DISABLED, do not draw the rest of it
743  if(pScrollInfo->iHPos < pScrollInfo->iHMin ||
744  pScrollInfo->iHPos > pScrollInfo->iHMax ||
745  pScrollInfo->iHMax < pScrollInfo->iHMin)
746  {
747 // WB_ERROR_PRINT("TEMPORARY: grey out %d %d %d\n",
748 // pScrollInfo->iVPos, pScrollInfo->iVMin, pScrollInfo->iVMax);
749  return; // I am done (greyed out bar)
750  }
751 
752  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHLeft),
753  clrScrollBD2.pixel, clrScrollBD3.pixel);
754  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHRight),
755  clrScrollBD2.pixel, clrScrollBD3.pixel);
756  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHKnob),
757  clrScrollBD2.pixel, clrScrollBD3.pixel);
758 
759  // draw arrows
760 
761  WBDrawLeftArrow(pDisplay, wID, gc, &(pScrollInfo->geomHLeft), clrScrollFG.pixel);
762  WBDrawRightArrow(pDisplay, wID, gc, &(pScrollInfo->geomHRight), clrScrollFG.pixel);
763 }
764 
765 
766 void WBDrawLeftArrow(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
767 {
768 XPoint xpt[5];
769 long lBG, lFG;
770 
771  lBG = WBGetGCBGColor(pDisplay, gc);
772  lFG = WBGetGCFGColor(pDisplay, gc); // save color context
773 
774  XSetForeground(pDisplay, gc, lColor);
775  XSetBackground(pDisplay, gc, lColor);
776 
777  // LEFT ARROW
778  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2);
779  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2) + (pgeomRect->height >> 2);
780  xpt[1].x = xpt[0].x + (pgeomRect->width >> 1) - 1;
781  xpt[1].y = pgeomRect->y + (pgeomRect->height >> 2);
782  xpt[2].x = xpt[1].x;
783  xpt[2].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
784  xpt[3].x = xpt[0].x;
785  xpt[3].y = xpt[2].y - (pgeomRect->height >> 2);
786  xpt[4].x = xpt[0].x;
787  xpt[4].y = xpt[0].y;
788 
789  XDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
790  XFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
791 
792  XSetForeground(pDisplay, gc, lFG);
793  XSetBackground(pDisplay, gc, lBG); // restore color context
794 }
795 
796 void WBDrawUpArrow(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
797 {
798 XPoint xpt[5];
799 long lBG, lFG;
800 
801  lBG = WBGetGCBGColor(pDisplay, gc);
802  lFG = WBGetGCFGColor(pDisplay, gc); // save color context
803 
804  XSetForeground(pDisplay, gc, lColor);
805  XSetBackground(pDisplay, gc, lColor);
806 
807  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2) + (pgeomRect->width >> 2);
808  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2);
809  xpt[1].x = pgeomRect->x + (pgeomRect->width >> 2);
810  xpt[1].y = xpt[0].y + (pgeomRect->height >> 1) - 1;
811  xpt[2].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
812  xpt[2].y = xpt[1].y;
813  xpt[3].x = xpt[2].x - (pgeomRect->width >> 2);
814  xpt[3].y = xpt[0].y;
815  xpt[4].x = xpt[0].x;
816  xpt[4].y = xpt[0].y;
817 
818  XDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
819  XFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
820 
821  XSetForeground(pDisplay, gc, lFG);
822  XSetBackground(pDisplay, gc, lBG); // restore color context
823 }
824 
825 void WBDrawRightArrow(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
826 {
827 XPoint xpt[5];
828 long lBG, lFG;
829 
830  lBG = WBGetGCBGColor(pDisplay, gc);
831  lFG = WBGetGCFGColor(pDisplay, gc); // save color context
832 
833  XSetForeground(pDisplay, gc, lColor);
834  XSetBackground(pDisplay, gc, lColor);
835 
836  // RIGHT ARROW
837  xpt[0].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
838  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2) + (pgeomRect->height >> 2);
839  xpt[1].x = xpt[0].x - (pgeomRect->width >> 1) + 1;
840  xpt[1].y = pgeomRect->y + (pgeomRect->height >> 2);
841  xpt[2].x = xpt[1].x;
842  xpt[2].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
843  xpt[3].x = xpt[0].x;
844  xpt[3].y = xpt[2].y - (pgeomRect->height >> 2);
845  xpt[4].x = xpt[0].x;
846  xpt[4].y = xpt[0].y;
847 
848  XDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
849  XFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
850 
851  XSetForeground(pDisplay, gc, lFG);
852  XSetBackground(pDisplay, gc, lBG); // restore color context
853 }
854 
855 void WBDrawDownArrow(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
856 {
857 XPoint xpt[5];
858 long lBG, lFG;
859 
860  lBG = WBGetGCBGColor(pDisplay, gc);
861  lFG = WBGetGCFGColor(pDisplay, gc); // save color context
862 
863  XSetForeground(pDisplay, gc, lColor);
864  XSetBackground(pDisplay, gc, lColor);
865 
866  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2) + (pgeomRect->width >> 2);
867  xpt[0].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
868  xpt[1].x = pgeomRect->x + (pgeomRect->width >> 2);
869  xpt[1].y = xpt[0].y - (pgeomRect->height >> 1) + 1;
870  xpt[2].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
871  xpt[2].y = xpt[1].y;
872  xpt[3].x = xpt[2].x - (pgeomRect->width >> 2);
873  xpt[3].y = xpt[0].y;
874  xpt[4].x = xpt[0].x;
875  xpt[4].y = xpt[0].y;
876 
877  XDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
878  XFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
879 
880  XSetForeground(pDisplay, gc, lFG);
881  XSetBackground(pDisplay, gc, lBG); // restore color context
882 }
883 
884 
885 void WBDraw3DBorderTab(Display *pDisplay, Drawable dw, GC gc, WB_GEOM *pgeomOutline,
886  int fFocus, unsigned long lFGColor, unsigned long lBGColor,
887  unsigned long lBorderColor1, unsigned long lBorderColor2,
888  unsigned long lHighlightColor,
889  XFontSet fontSet, XFontSet fontSetBold,
890  Atom aGraphic, const char *szText)
891 {
892 XPoint xpt[13];
893 XColor clrAvg, clrTemp;
894 int iFontHeight, bFocus;
895 int i1, i2, iR, iG, iB, iY, iU, iV, iYBG;
896 Region rgnClip;
897 GC gc2;
898 WB_RECT rctTemp;
899 
900 
901  if(fontSet == None)
902  {
903  fontSet = WBGetDefaultFontSet(pDisplay);
904  }
905 
906  if(fontSetBold == None)
907  {
908  fontSetBold = WBGetDefaultFontSet(pDisplay);
909  }
910 
911  iFontHeight = WBFontSetHeight(pDisplay, fontSet);
912 
913 
914  // begin by creating a region that consists of my 'rounded rect' polygon
915 
916  // create a rounded-corner trapezoid the encompasses the tab. corner pixels will
917  // be averages of the border colors.
918 
919  // lower left corner
920  xpt[0].x = pgeomOutline->x;
921  xpt[0].y = pgeomOutline->y + pgeomOutline->height + 1; // for clip rgn, I do this
922 
923  // left side
924  xpt[1].x = xpt[0].x + 2; // slight trapezoid
925  xpt[1].y = pgeomOutline->y + 3; // room for corner
926 
927  // upper left corner
928  xpt[2].x = xpt[1].x + 1;
929  xpt[2].y = xpt[1].y - 1; // 45 degrees
930  xpt[3].x = xpt[2].x + 1;
931  xpt[3].y = xpt[2].y - 1; // again
932  xpt[4].x = xpt[3].x + 1;
933  xpt[4].y = xpt[3].y - 1; // now we're "on point"
934 
935  // top row
936  xpt[5].x = xpt[0].x + pgeomOutline->width - 5;
937  xpt[5].y = xpt[4].y;
938 
939  // upper right corner
940  xpt[6].x = xpt[5].x + 1;
941  xpt[6].y = xpt[5].y + 1; // 45 degrees
942  xpt[7].x = xpt[6].x + 1;
943  xpt[7].y = xpt[6].y + 1; // 45 degrees
944  xpt[8].x = xpt[7].x + 1;
945  xpt[8].y = xpt[7].y + 1; // 45 degrees
946 
947  // right side
948  xpt[9].x = pgeomOutline->x + pgeomOutline->width;
949  xpt[9].y = xpt[0].y; // same y as 1st point
950 
951  xpt[10].x = xpt[0].x;
952  xpt[10].y = xpt[0].y; // close up the polygon
953 
954  rgnClip = XPolygonRegion(xpt, 11, WindingRule);
955  if(rgnClip == None)
956  {
957  WB_ERROR_PRINT("ERROR: %s - unable to create polygon region\n", __FUNCTION__);
958  return;
959  }
960 
961  // create GC copy and select the clipping region
962 
963  gc2 = WBCopyDrawableGC(pDisplay, dw, gc);
964 
965  if(gc2 == None)
966  {
967  XDestroyRegion(rgnClip);
968 
969  WB_ERROR_PRINT("ERROR: %s - unable to create GC\n", __FUNCTION__);
970  return;
971  }
972 
973  // select the clip region
974  XSetRegion(pDisplay, gc2, rgnClip);
975 
976  // set 'bFocus' to indicate if I have focus. 'fFocus' also indicates 'x' button state
977  // 0 or < -1 is "I do not have focus". -1 or > 0 is "I have focus". negative is 'x button clicked'
978 
979  bFocus = fFocus > 0 || fFocus == -1;
980 
981  if(bFocus)
982  {
983  // do the background color in the tab. this will use the clip region to help me
984 
985  clrTemp.pixel = lBGColor; // default background color
986  PXM_PixelToRGB(NULL, &clrTemp);
987 
988  iR = clrTemp.red >> 8;
989  iG = clrTemp.green >> 8;
990  iB = clrTemp.blue >> 8;
991 
992  PXM_RGBToYUV(iR, iG, iB, &iYBG, NULL, NULL); // get 'Y' for the background (assume grey)
993 
994  i2 = 3 * (xpt[0].y - xpt[5].y - 2) / 5;
995 
996 // WB_ERROR_PRINT("TEMPORARY: %s - i2 is %d, from %d and %d\n", __FUNCTION__,
997 // i2, xpt[0].y, xpt[5].y);
998 
999  for(i1=xpt[5].y; i1 < xpt[0].y - 2; i1++)
1000  {
1001  XPoint xpt2[2];
1002  int iR2 = abs(i1 - (xpt[5].y + i2));
1003 
1004 // iR2 *= iR2;
1005  iR2 = icos(iR2 * 232 / i2); // 255 would be pi/2, so go slightly less than that
1006 // iR2 = isqrt(iR2);
1007 
1008  clrTemp.pixel = lHighlightColor;
1009  PXM_PixelToRGB(NULL, &clrTemp);
1010 
1011  iR = clrTemp.red >> 8;
1012  iG = clrTemp.green >> 8;
1013  iB = clrTemp.blue >> 8;
1014 
1015  PXM_RGBToYUV(iR, iG, iB, &iY, &iU, &iV);
1016 
1017  iY = iYBG * 3 / 4 + ((384 - iYBG) * iR2) / 384; // allows brightness to drop to a bit less than the background's brightness
1018 
1019  if(iY > 255)
1020  {
1021  iU = 128 + (iU - 128) * 255 / iY * 255 / iY;
1022  iV = 128 + (iV - 128) * 255 / iY * 255 / iY;
1023  iY = 255;
1024  }
1025 
1026  PXM_YUVToRGB(iY, iU, iV, &iR, &iG, &iB);
1027 
1028  clrTemp.red = (iR << 8) + 128;
1029  clrTemp.green = (iG << 8) + 128;
1030  clrTemp.blue = (iB << 8) + 128;
1031  clrTemp.flags = DoRed | DoGreen | DoBlue;
1032 
1033  PXM_RGBToPixel(NULL, &clrTemp);
1034 
1035 // WB_ERROR_PRINT("TEMPORARY: %s - YUV is %d, %d, %d, RGB is %d, %d, %d for %lu (%08lxH)\n", __FUNCTION__,
1036 // iY, iU, iV,
1037 // clrTemp.red, clrTemp.green, clrTemp.blue, clrTemp.pixel, clrTemp.pixel);
1038 
1039  XSetForeground(pDisplay, gc2, clrTemp.pixel); // select this color
1040 
1041  xpt2[0].x = pgeomOutline->x + 1;
1042  xpt2[0].y = i1;
1043  xpt2[1].x = pgeomOutline->x + pgeomOutline->width - 2;
1044  xpt2[1].y = xpt2[0].y;
1045 
1046  if(i1 < xpt[5].y + 2) // corner hack, based on observation
1047  {
1048  xpt2[0].x += (xpt[5].y + 2) - i1;
1049  xpt2[1].x -= (xpt[5].y + 2) - i1;
1050  }
1051 
1052  // draw the line
1053  XDrawLines(pDisplay, dw, gc2, xpt2, 2, CoordModeOrigin); // stop at point 6 (don't paint 6 to 7)
1054  }
1055  }
1056 
1057 
1058  // next, squeeze in the right/left edges of my points. I've observed I need to do this
1059  // as a hack, don't do the left squeeze for the 'focus' tab
1060 
1061  if(!bFocus)
1062  {
1063  for(i1=0; i1 < 5; i1++)
1064  {
1065  xpt[i1].x ++;
1066  }
1067  }
1068 
1069  for(i1=5; i1 < 10; i1++)
1070  {
1071  xpt[i1].x --;
1072  }
1073 
1074  if(!bFocus)
1075  {
1076  xpt[0].y -= 3; // one above 'bottom' (where I'll draw a line)
1077  }
1078  else
1079  {
1080  xpt[0].y -= 2;
1081  }
1082 
1083  xpt[9].y = xpt[0].y; // same y as 1st point
1084 
1085  xpt[10].x = xpt[0].x; // re-close up polygon (again)
1086  xpt[10].y = xpt[0].y; // close up the polygon
1087 
1088 
1089  // make a copy of the GC
1090 
1091  XSetForeground(pDisplay, gc2, lFGColor);
1092  XSetBackground(pDisplay, gc2, lBGColor);
1093 
1094  // Use the RGB info to calculate an 'average' color for the corner transition
1095 
1096  bzero(&clrAvg, sizeof(clrAvg));
1097  clrAvg.pixel = lBorderColor1;
1098 
1099  PXM_PixelToRGB(NULL, &clrAvg);
1100 
1101  iR = (clrAvg.flags & DoRed) ? (unsigned int)clrAvg.red : 0;
1102  iG = (clrAvg.flags & DoGreen) ? (unsigned int)clrAvg.green : 0;
1103  iB = (clrAvg.flags & DoBlue) ? (unsigned int)clrAvg.blue : 0;
1104 
1105  bzero(&clrAvg, sizeof(clrAvg));
1106  clrAvg.pixel = lBorderColor2;
1107 
1108  PXM_PixelToRGB(NULL, &clrAvg);
1109 
1110  iR += (clrAvg.flags & DoRed) ? (unsigned int)clrAvg.red : 0;
1111  iG += (clrAvg.flags & DoGreen) ? (unsigned int)clrAvg.green : 0;
1112  iB += (clrAvg.flags & DoBlue) ? (unsigned int)clrAvg.blue : 0;
1113 
1114  bzero(&clrAvg, sizeof(clrAvg));
1115 
1116  clrAvg.red = iR >> 1;
1117  clrAvg.green = iG >> 1;
1118  clrAvg.blue = iB >> 1;
1119 
1120  PXM_RGBToPixel(NULL, &clrAvg); // TODO: alloc the color as well?
1121 
1122  // next, draw polygon using 3D colors
1123 
1124  XSetForeground(pDisplay, gc2, lBorderColor1);
1125  XDrawLines(pDisplay, dw, gc2, xpt, 7, CoordModeOrigin); // stop at point 6 (don't paint 6 to 7)
1126 
1127  XSetForeground(pDisplay, gc2, lBorderColor2);
1128  XDrawLines(pDisplay, dw, gc2, xpt + 8, 2, CoordModeOrigin); // stop at point 6 (don't paint 6 or 7)
1129 
1130  if(bFocus)
1131  {
1132  // for non-focus, draw the bottom (7 to 8) using border color 2. for focus, draw as background color
1133 
1134  XSetForeground(pDisplay, gc2, lBGColor);
1135  }
1136 
1137  XDrawLines(pDisplay, dw, gc2, xpt + 9, 2, CoordModeOrigin); // the bottom line
1138 
1139  // paint pixels 6 and 7 with the 'average' color
1140  XSetForeground(pDisplay, gc2, clrAvg.pixel);
1141  XDrawPoints(pDisplay, dw, gc2, xpt + 6, 2, CoordModeOrigin);
1142 
1143  if(!bFocus)
1144  {
1145  // when not in focus, also do avg color for the first pixel. this completes the 3D effect 'color transition'
1146  XDrawPoints(pDisplay, dw, gc2, xpt, 1, CoordModeOrigin);
1147  }
1148 
1149 
1150 
1151  // TAB TEXT (TODO: image atom)
1152 
1153  rctTemp.left = pgeomOutline->x;
1154  rctTemp.top = pgeomOutline->y;
1155  rctTemp.right = rctTemp.left + pgeomOutline->width;
1156  rctTemp.bottom = rctTemp.top + pgeomOutline->height;
1157 
1158  if(!szText)
1159  {
1160  szText = "{untitled}";
1161  }
1162 
1163  XSetForeground(pDisplay, gc2, lFGColor);
1164 
1165  // for now just do centered text
1166  DTDrawSingleLineText(fontSet, szText, pDisplay, gc2, dw, 0, 0, &rctTemp,
1168 
1169 
1170  // NOW, I need to draw the 'x' for the close button. Fist, I calculate its rect
1171 
1172  rctTemp.top = pgeomOutline->y + 2; // top plus 2 pixels
1173  rctTemp.bottom = rctTemp.top + iFontHeight; // height is font height
1174  rctTemp.right = pgeomOutline->x + pgeomOutline->width - 6; // right is 6 pixels from right edge
1175  rctTemp.left = rctTemp.right - iFontHeight + 2; // left is 2 pixels + font height from right
1176 
1177  if(fFocus < 0) // clicking 'x' ?
1178  {
1179  XSetForeground(pDisplay, gc2, lHighlightColor);
1180  XSetBackground(pDisplay, gc2, lHighlightColor);
1181  }
1182  else
1183  {
1184  XSetForeground(pDisplay, gc2, lBGColor);
1185  XSetBackground(pDisplay, gc2, lBGColor);
1186  }
1187 
1188  // fill in with selected colors
1189 
1190  XFillRectangle(pDisplay, dw, gc2, rctTemp.left, rctTemp.top, rctTemp.right - rctTemp.left, rctTemp.bottom - rctTemp.top);
1191 
1192  if(fFocus < 0) // clicking 'x' ?
1193  {
1194  XSetForeground(pDisplay, gc2, lBGColor);
1195  }
1196  else
1197  {
1198  XSetForeground(pDisplay, gc2, lHighlightColor);
1199  }
1200 
1201  // now draw the '+' using a BOLD font
1202 
1203  rctTemp.left -=2;
1204  rctTemp.right += 2;
1205  rctTemp.top -= 2;
1206  rctTemp.bottom += 2; // big enough to 'center' properly
1207 
1208  DTDrawSingleLineText(fontSetBold, "x", pDisplay, gc2, dw, 0, 0, &rctTemp,
1210 
1211 
1212  XFreeGC(pDisplay, gc2);
1213  XDestroyRegion(rgnClip);
1214 
1215 
1216 // WB_ERROR_PRINT("TEMPORARY: %s - only partially implemented\n", __FUNCTION__);
1217 }
1218 
1219 
1220