X11workbench Toolkit  1.0
dialog_impl.c
Go to the documentation of this file.
1 // _ _ _ _ _ //
3 // __| |(_) __ _ | | ___ __ _ (_) _ __ ___ _ __ | | ___ //
4 // / _` || | / _` || | / _ \ / _` | | || '_ ` _ \ | '_ \ | | / __| //
5 // | (_| || || (_| || || (_) || (_| | | || | | | | || |_) || | _| (__ //
6 // \__,_||_| \__,_||_| \___/ \__, |_____|_||_| |_| |_|| .__/ |_|(_)\___| //
7 // |___/|_____| |_| //
8 // //
9 // implementation of standard modal dialogs //
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 
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  MIT-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  MIT-like license. See COPYING and README files for more information.
43 
44 
45  Additional information at http://sourceforge.net/projects/X11workbench
46 
47 ******************************************************************************/
48 
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <memory.h>
61 #include <string.h>
62 #include <strings.h>
63 #include <signal.h>
64 #include <time.h>
65 
66 #ifndef XK_Delete /* moslty for interix */
67 #define XK_MISCELLANY /* mostly for interix */
68 #include <X11/keysymdef.h> // some platforms don't automatically include this with X headers
69 #endif // XK_Delete
70 
71 #include "window_helper.h"
72 #include "pixmap_helper.h" // pixmap helpers, including pre-defined icons
73 #include "dialog_window.h"
74 #include "dialog_controls.h"
75 #include "conf_help.h"
76 #include "file_help.h"
77 #include "draw_text.h"
78 
79 
80 #define THIS_SUBSYSTEM DebugSubSystem_Dialog
81 
82 //-------------------------------------------------------------------
83 //
84 // alteration of 'gleam' behavior for 'Splash' dialog
85 // default is the 'wide' gleam that uses 1/r^2
86 //
87 //#define GLEAM_OLD /* use this to do the 'old' gleam behavior */
88 //#define GLEAM_NARROW /* use this to produce the 'narrow' gleam */
89 //
90 //------------------------------------------------------------------
91 
92 
94 // MESSAGE BOX
96 
97 struct _MESSAGE_BOX_
98 {
99  int iType;
100  const char *szTitle;
101  const char *szMessage;
102 };
103 
104 static int GetMessageBoxIconPixmapID(int iMBIconMask)
105 {
106  switch(iMBIconMask & MessageBox_ICON_MASK)
107  {
108  case MessageBox_Error:
109  return ID_ICON_STOP;
110  case MessageBox_Warning:
111  return ID_ICON_WARN;
112  case MessageBox_Info:
113  return ID_ICON_OK;
114  case MessageBox_Asterisk:
115  return ID_ICON_SPLAT;
116  case MessageBox_Question:
117  return ID_ICON_WHAT;
119  return ID_ICON_WHAT_BOLD;
120  case MessageBox_WTF:
121  return ID_ICON_WTF;
122  case MessageBox_Bang:
123  return ID_ICON_BANG;
124  case MessageBox_Triangle:
125  return ID_ICON_TRIANGLE;
127  return ID_ICON_DEATH;
129  return ID_ICON_SKULL;
130  case MessageBox_ThumbsUp:
131  return ID_ICON_THUMBUP;
133  return ID_ICON_THUMBDOWN;
135  return ID_ICON_FINGER;
137  return ID_ICON_BEAR;
138  case MessageBox_Barney:
139  return ID_ICON_BARNEY;
140  case MessageBox_App:
141  return ID_ICON_APP;
142 
143 // default:
144 // pixmap = None;
145  }
146 
147  return -1;
148 }
149 
150 static int MessageBoxCallback(Window wID, XEvent *pEvent)
151 {
153 struct _MESSAGE_BOX_ *pUserData = (struct _MESSAGE_BOX_ *)(pDlg ? pDlg->pUserData : NULL);
154 //#ifndef NO_DEBUG
155 //WB_UINT64 ullTime = WBGetTimeIndex();
156 //#endif // NO_DEBUG
157 
158 
159  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
160  {
161  if(!pDlg)
162  {
163  WB_ERROR_PRINT("MessageBoxCallback - no WBDialogWindow structure in DIALOG_INIT for %d (%08xH) %p %08xH %08xH\n",
164  (unsigned int)wID, (unsigned int)wID, WBGetWindowData(wID, 0), DIALOG_WINDOW_TAG, ((WBDialogWindow *)WBGetWindowData(wID, 0))->ulTag);
165  return 0; // can't process any messages now
166  }
167  else
168  {
169  // assigning the correct icon
170 
171  Window wIDIcon = DLGGetDialogControl(pDlg, 1000); // ID 1000 for icon
172  WBDialogControl *pCtrl = DLGGetDialogControlStruct(wIDIcon);
173 
174  if(pCtrl)
175  {
176  Pixmap pixmap2 = None;
177  Pixmap pixmap = PXM_GetIconPixmap(GetMessageBoxIconPixmapID(pUserData->iType & MessageBox_ICON_MASK),
178  NULL, &pixmap2);
179 
180  if(pixmap != None)
181  {
182  WBDialogControlSetIconPixmap(pCtrl, pixmap, pixmap2);
183  }
184  }
185  }
186 
187  // assign the caption text to the caption window (which varies and must be assigned at run time)
188 
189  DLGSetControlCaption((WBDialogWindow *)pDlg, 1001, pUserData->szMessage);
190 
191 // WB_ERROR_PRINT("TEMPORARY: %s line %d delta tick %lld\n", __FUNCTION__, __LINE__, (WBGetTimeIndex() - ullTime));
192 
193  return 1;
194  }
195 
196  if(!pDlg)
197  {
198  WB_WARN_PRINT("MessageBoxCallback - no WBDialogWindow structure\n");
199  return 0; // can't process any messages now
200  }
201 
202  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aCONTROL_NOTIFY)
203  {
204  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
205  "%s - MessageBox ClientMessage CONTROL_NOTIFY\n", __FUNCTION__);
206 
207  switch(pEvent->xclient.data.l[1]) // control ID
208  {
209  case IDOK:
210  case IDCANCEL:
211  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
212  {
213  WBEndModal(wID, pEvent->xclient.data.l[1]);
214  }
215  break;
216 
217  default:
218  WB_WARN_PRINT("%s - MessageBox ClientMessage CONTROL_NOTIFY client id=%lx\n",
219  __FUNCTION__, pEvent->xclient.data.l[1]);
220  }
221  }
222 
223 
224 
225 
226 
227 
228  return 0;
229 }
230 
231 int DLGMessageBox(int iType, Window wIDOwner, const char *szTitle, const char *szMessage)
232 {
233 static const char szOKBox[]=
234  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
235  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
236  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
237  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
238  "END_DIALOG\n";
239 static const char szNoBox[]=
240  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
241  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
242  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
243  " CONTROL:DefPushButton ID:IDCANCEL TITLE:No X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
244  "END_DIALOG\n";
245 static const char szYesBox[]=
246  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
247  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
248  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
249  " CONTROL:DefPushButton ID:IDYES TITLE:Yes X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
250  "END_DIALOG\n";
251 static const char szCancelBox[]=
252  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
253  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
254  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
255  " CONTROL:DefPushButton ID:IDCANCEL TITLE:Cancel X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
256  "END_DIALOG\n";
257 static const char szAbortBox[]=
258  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
259  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
260  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
261  " CONTROL:DefPushButton ID:IDABORT TITLE:Abort X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
262  "END_DIALOG\n";
263 static const char szRetryBox[]=
264  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
265  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
266  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
267  " CONTROL:DefPushButton ID:IDRETRY TITLE:Retry X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
268  "END_DIALOG\n";
269 static const char szIgnoreBox[]=
270  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK Box\"\n"
271  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
272  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
273  " CONTROL:DefPushButton ID:IDIGNORE TITLE:Ignore X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
274  "END_DIALOG\n";
275 static const char szOKCancelBox[]=
276  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"OK/Cancel Box\"\n"
277  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
278  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
279  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:40 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
280  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:120 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
281  "END_DIALOG\n";
282 static const char szYesNoBox[]=
283  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"Yes/No Box\"\n"
284  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
285  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
286  " CONTROL:DefPushButton ID:IDYES TITLE:_Yes X:40 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
287  " CONTROL:CancelButton ID:IDNO TITLE:_No X:120 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
288  "END_DIALOG\n";
289 static const char szYesNoCancelBox[]=
290  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"Yes/No Box\"\n"
291  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
292  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
293  " CONTROL:DefPushButton ID:IDYES TITLE:_Yes X:20 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
294  " CONTROL:PushButton ID:IDNO TITLE:_No X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
295  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:140 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
296  "END_DIALOG\n";
297 static const char szAbortRetryBox[]=
298  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"Yes/No Box\"\n"
299  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
300  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
301  " CONTROL:DefPushButton ID:IDABORT TITLE:_Abort X:40 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
302  " CONTROL:CancelButton ID:IDRETRY TITLE:_Retry X:120 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
303  "END_DIALOG\n";
304 static const char szAbortRetryIgnoreBox[]=
305  "BEGIN_DIALOG FONT:Variable HEIGHT:50 WIDTH:200 TITLE:\"Yes/No Box\"\n"
306  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
307  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
308  " CONTROL:DefPushButton ID:IDYES TITLE:_Abort X:20 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
309  " CONTROL:PushButton ID:IDRETRY TITLE:_Retry X:80 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
310  " CONTROL:CancelButton ID:IDIGNORE TITLE:_Ignore X:140 Y:28 WIDTH:40 HEIGHT:18 VISIBLE\n"
311  "END_DIALOG\n";
312 
313 struct _MESSAGE_BOX_ mbox;
314 const char *pRes;
315 WBDialogWindow *pDlg;
316 WB_GEOM geomParent;
317 Window wIDDlg;
318 int iRval, iX, iY;
319 
320 
321 // for now I determine the standard message box size THIS way
322 #define MESSAGE_BOX_WIDTH 400
323 #define MESSAGE_BOX_HEIGHT 100
324 #define MESSAGE_BOX_OFFSET 50
325 
326  mbox.iType = iType;
327  mbox.szTitle = szTitle;
328  mbox.szMessage = szMessage;
329 
330  bzero(&geomParent, sizeof(geomParent));
331 
332  if(wIDOwner != None)
333  {
334  WBGetWindowGeom0(wIDOwner, &geomParent); // parent geometry in absolute coordinates
335 
336  iX = geomParent.x + geomParent.border + MESSAGE_BOX_OFFSET;
337  iY = geomParent.y + geomParent.border + MESSAGE_BOX_OFFSET;
338  }
339  else
340  {
341  // center in screen with slight random offset (so that every window won't always appear in exactly the same place)
342  iY = (DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
343  - MESSAGE_BOX_HEIGHT + MESSAGE_BOX_OFFSET - (int)(WBGetTimeIndex() % (2 * MESSAGE_BOX_OFFSET)))
344  / 2;
345 
346  iX = (DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
347  - MESSAGE_BOX_WIDTH + MESSAGE_BOX_OFFSET - (int)((~WBGetTimeIndex()) % (2 * MESSAGE_BOX_OFFSET)))
348  / 2;
349  }
350 
351  switch(iType & MessageBox_BUTTON_MASK)
352  {
353  case MessageBox_OK:
354  pRes = szOKBox;
355  break;
356 
357  case MessageBox_Yes:
358  pRes = szYesBox;
359  break;
360 
361  case MessageBox_No:
362  pRes = szNoBox;
363  break;
364 
365  case MessageBox_Cancel:
366  pRes = szCancelBox;
367  break;
368 
369  case MessageBox_Abort:
370  pRes = szAbortBox;
371  break;
372 
373  case MessageBox_Retry:
374  pRes = szRetryBox;
375  break;
376 
377  case MessageBox_Ignore:
378  pRes = szIgnoreBox;
379  break;
380 
382  pRes = szOKCancelBox;
383  break;
384 
386  pRes = szYesNoBox;
387  break;
388 
390  pRes = szYesNoCancelBox;
391  break;
392 
394  pRes = szAbortRetryBox;
395  break;
396 
398  pRes = szAbortRetryIgnoreBox;
399  break;
400 
401  default:
402  if((iType & MessageBox_Abort) || (iType & MessageBox_Retry) || (iType & MessageBox_Ignore))
403  {
404  pRes = szAbortRetryIgnoreBox;
405  }
406  else if((iType & MessageBox_Yes) || (iType & MessageBox_No) || (iType & MessageBox_Cancel))
407  {
408  pRes = szYesNoCancelBox;
409  }
410  else
411  {
412  pRes = szOKBox;
413  }
414  }
415 
416 
417  pDlg = DLGCreateDialogWindow(wIDOwner, szTitle, pRes,
418  iX, iY, MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT, // TODO: derive from ???
419  MessageBoxCallback,
420  WBDialogWindow_VISIBLE, &mbox);
421 
422  if(pDlg)
423  {
424  wIDDlg = pDlg->wID;
425 
426  WBSetWindowIcon(wIDDlg, GetMessageBoxIconPixmapID(iType & MessageBox_ICON_MASK));
427 
428 // WB_ERROR_PRINT("TEMPORARY: %s - calling WBShowModal\n", __FUNCTION__);
429 
430  iRval = WBShowModal(wIDDlg, 0);
431 
432  return iRval;
433  }
434 
435  return -1; // by default return -1 on error
436 }
437 
438 
440 // INPUT BOX
442 
443 struct _INPUT_BOX_
444 {
445  const char *szTitle;
446  const char *szMessage;
447  char *szRval;
448 };
449 
450 
451 static int InputBoxCallback(Window wID, XEvent *pEvent)
452 {
454 struct _INPUT_BOX_ *pUserData = (struct _INPUT_BOX_ *)(pDlg ? pDlg->pUserData : NULL);
455 
456 
457  if(!pDlg)
458  return 0; // can't process any messages now
459 
460  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
461  {
462  // assigning the correct icon
463  {
464  WBDialogControl *pCtrl = DLGGetDialogControlStructFromID(pDlg, 1000); // ID 1000 for icon
465 
466  if(pCtrl)
467  {
468  Pixmap pixmap2 = None;
469  Pixmap pixmap = PXM_GetIconPixmap(ID_ICON_WHAT, NULL, &pixmap2);
470 
471  if(pixmap != None)
472  {
473  WBDialogControlSetIconPixmap(pCtrl, pixmap, pixmap2);
474  }
475  }
476  }
477 
478  // assign the caption text to the caption window (which varies and must be assigned at run time)
479 
480  DLGSetControlCaption((WBDialogWindow *)pDlg, 1001, pUserData->szMessage);
481 
482  if(pUserData->szRval)
483  {
484  DLGSetControlCaption(pDlg, 1002, pUserData->szRval);
485  }
486 
487  return 1;
488  }
489 
490  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aCONTROL_NOTIFY)
491  {
492  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
493  "%s - MessageBox ClientMessage CONTROL_NOTIFY\n", __FUNCTION__);
494 
495  switch(pEvent->xclient.data.l[1]) // control ID
496  {
497  case IDOK:
498  case IDCANCEL:
499  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
500  {
501  const char *pText = DLGGetControlCaption(pDlg, 1002);
502 
503  if(pUserData->szRval)
504  {
505  WBFree(pUserData->szRval);
506  }
507  if(pText)
508  {
509  pUserData->szRval = WBCopyString(pText);
510  }
511  else
512  {
513  WB_ERROR_PRINT("TEMPORARY: %s - NULL 'pText' for edit control\n", __FUNCTION__);
514  pUserData->szRval = NULL; // empty string
515  }
516 
517  WBEndModal(wID, pEvent->xclient.data.l[1]);
518  }
519  break;
520 
521  case 1002:
522  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
523  "%s - INPUT BOX 'EDIT' NOTIFICATION %ld\n",
524  __FUNCTION__, pEvent->xclient.data.l[0]);
525 
526  // TODO: update window text
527  break;
528 
529  default:
530  WB_WARN_PRINT("%s - MessageBox ClientMessage CONTROL_NOTIFY client id=%lx\n",
531  __FUNCTION__, pEvent->xclient.data.l[0]);
532  }
533  }
534 
535  return 0;
536 }
537 
538 #define INPUT_BOX_WIDTH 400
539 #define INPUT_BOX_HEIGHT 120
540 
541 char *DLGInputBox(Window wIDOwner, const char *szTitle, const char *szPrompt, const char *szDefault,
542  int iWidth, int iMaxChar)
543 {
544 static const char szInputDialogRes[]=
545  "BEGIN_DIALOG FONT:Variable HEIGHT:60 WIDTH:200 TITLE:\"User Input\"\n"
546  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
547  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
548  " CONTROL:Edit ID:1002 X:2 Y:22 WIDTH:196 HEIGHT:16 VISIBLE\n"
549  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:40 Y:40 WIDTH:40 HEIGHT:18 VISIBLE\n"
550  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:120 Y:40 WIDTH:40 HEIGHT:18 VISIBLE\n"
551  "END_DIALOG\n";
552 WBDialogWindow *pDlg;
553 struct _INPUT_BOX_ sRval;
554 int iX, iY, iRval;
555 Window wIDDlg;
556 WB_GEOM geomParent;
557 
558 
559  sRval.szTitle = szTitle;
560  sRval.szMessage = szPrompt;
561  if(szDefault && *szDefault)
562  {
563  sRval.szRval = WBCopyString(szDefault); // a copy of the default value
564  }
565  else
566  {
567  sRval.szRval = NULL;
568  }
569 
570  bzero(&geomParent, sizeof(geomParent));
571 
572  if(wIDOwner != None)
573  {
574  WBGetWindowGeom0(wIDOwner, &geomParent); // parent geometry in absolute coordinates
575 
576  iX = geomParent.x + geomParent.border + MESSAGE_BOX_OFFSET;
577  iY = geomParent.y + geomParent.border + MESSAGE_BOX_OFFSET;
578  }
579  else
580  {
581  // center in screen with slight random offset (so that every window won't always appear in exactly the same place)
582  iY = (DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
583  - INPUT_BOX_HEIGHT + MESSAGE_BOX_OFFSET - (int)(WBGetTimeIndex() % (2 * MESSAGE_BOX_OFFSET)))
584  / 2;
585 
586  iX = (DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
587  - INPUT_BOX_WIDTH + MESSAGE_BOX_OFFSET - (int)((~WBGetTimeIndex()) % (2 * MESSAGE_BOX_OFFSET)))
588  / 2;
589  }
590 
591 
592  pDlg = DLGCreateDialogWindow(wIDOwner, szTitle,szInputDialogRes,
593  iX,iY,INPUT_BOX_WIDTH,INPUT_BOX_HEIGHT,
594  InputBoxCallback,
595  WBDialogWindow_VISIBLE,&sRval);
596 
597  if(pDlg)
598  {
599  wIDDlg = pDlg->wID;
600 
601  iRval = WBShowModal(pDlg->wID, 0);
602 
603  if(iRval == IDOK)
604  {
605  return sRval.szRval;
606  }
607  else if(iRval != IDCANCEL)
608  {
609  WB_ERROR_PRINT("TEMPORARY - %s - iRval is %d\n", __FUNCTION__, iRval);
610  }
611  }
612 
613  // it ends up here on 'cancel', etc. - so if a buffer was allocated, free it
614 
615  if(sRval.szRval)
616  {
617  WBFree(sRval.szRval);
618  }
619 
620  return NULL;
621 }
622 
623 
624 
626 // FILE DIALOG
628 
629 struct _FILE_DIALOG_
630 {
631  const char *szDefPath;
632  const char *szDefName;
633  const char *szExtAndDescList;
634  char *szPathName; // WBAlloc'd
635 };
636 
637 
638 #define FILE_DIALOG_PATH_TREE_CONTROL 1000
639 #define FILE_DIALOG_FILE_LIST_CONTROL 1001
640 #define FILE_DIALOG_FILE_NAME_CONTROL 1002
641 
642 static int FileDialogCallback(Window wID, XEvent *pEvent)
643 {
645 struct _FILE_DIALOG_ *pUserData = (struct _FILE_DIALOG_ *)(pDlg ? pDlg->pUserData : NULL);
646 //Display *pDisplay = WBGetWindowDisplay(wID);
647 char *p1, *p2;
648 
649 
650  if(!pDlg)
651  return 0; // can't process any messages now
652 
653  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
654  {
655  if(!pUserData->szPathName || !*(pUserData->szPathName) ||
656  (!strchr(pUserData->szPathName, '/') && !WBIsDirectory(pUserData->szPathName)))
657  {
658  if(!pUserData->szDefPath || !*(pUserData->szDefPath))
659  {
660  // set the 'DLGC_PATH' property for appropriate controls
661  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
662  aDLGC_PATH, "."); // set path to '.' if not specified already
663  }
664  else
665  {
666  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
667  aDLGC_PATH, pUserData->szDefPath);
668  }
669  }
670  else
671  {
672  p1 = WBCopyString(pUserData->szDefPath);
673  if(!p1)
674  {
675  WB_ERROR_PRINT("%s - no memory to copy path string (a)\n", __FUNCTION__);
676  }
677  else
678  {
679  p2 = strrchr(p1, '/');
680  if(p2)
681  {
682  p2[1] = 0; // keep the '/'
683  }
684 
685  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
686  aDLGC_PATH, p1);
687 
688  WBFree(p1);
689  }
690  }
691 
692  return 1;
693  }
694 
695  if(pEvent->type != ClientMessage)
696  {
697  return 0; // unhandled at this time
698  }
699 
700  // EVERYTHING AT THIS POINT IS A CLIENT MESSAGE
701 
702  if(pEvent->xclient.message_type == aCONTROL_NOTIFY)
703  {
704  // l[0] == message
705  // l[1] == control ID
706  // l[2] ==
707  switch(pEvent->xclient.data.l[1])
708  {
709  case IDOK:
710  case IDCANCEL:
711  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
712  {
713  if(pEvent->xclient.data.l[1] == IDOK)
714  {
715  const char *pPath = DLGGetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL);
716  const char *pDir = DLGGetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL, aDLGC_PATH);
717 
718  if(pUserData->szPathName)
719  {
720  WBFree(pUserData->szPathName);
721  }
722 
723  if(pPath && pPath[0] == '/')
724  {
725  pUserData->szPathName = WBCopyString(pPath); // absolute path assignment
726  }
727  else
728  {
729  if(pDir && *pDir)
730  {
731  pUserData->szPathName = WBCopyString(pDir);
732 
733  if(pUserData->szPathName && *pUserData->szPathName &&
734  pUserData->szPathName[strlen(pUserData->szPathName) - 1] != '/')
735  {
736  WBCatString(&(pUserData->szPathName), "/");
737  }
738  }
739  else
740  {
741  pUserData->szPathName = WBCopyString("./");
742  }
743 
744 // WB_ERROR_PRINT("TEMPORARY %s ---> dir=\"%s\" path=\"%s\" \n", __FUNCTION__, pUserData->szPathName, pPath);
745 
746  if(pUserData->szPathName && pPath)
747  {
748  WBCatString(&(pUserData->szPathName), pPath);
749  }
750 
751  // check for '/../' within path - if present, canonicalize it
752  if(pUserData->szPathName &&
753  (strstr(pUserData->szPathName, "/../") ||
754  (strlen(pUserData->szPathName) > 3 &&
755  (!memcmp(pUserData->szPathName, "../", 3) ||
756  !memcmp(pUserData->szPathName + strlen(pUserData->szPathName) - 3, "/..", 3)))))
757  {
758  p1 = WBGetCanonicalPath(pUserData->szPathName);
759  if(p1)
760  {
761  WBFree(pUserData->szPathName);
762  pUserData->szPathName = p1;
763  }
764  else
765  {
766  WB_ERROR_PRINT("ERROR - %s - Unable to get canonical path for \"%s\"\n", __FUNCTION__, pUserData->szPathName);
767  }
768  }
769  }
770 
771  if(pUserData->szPathName && *pUserData->szPathName &&
772  (pUserData->szPathName[strlen(pUserData->szPathName) - 1] == '/' || WBIsDirectory(pUserData->szPathName)))
773  {
774  // if it ends in a '/' it's supposed to be a DIRECTORY and I must change to it
775  p1 = WBCopyString(pUserData->szPathName);
776  if(p1 && (!*p1 || p1[strlen(p1) - 1] != '/'))
777  {
778  WBCatString(&p1, "/"); // make sure it ends in '/'
779  }
780 
781  if(!p1)
782  {
783  WB_ERROR_PRINT("%s - no memory to copy path string (b)\n", __FUNCTION__);
784  }
785  else
786  {
787  // TODO: do I do a chdir() ?
788 
789  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
790  aDLGC_PATH, p1);
791 
792 // WB_ERROR_PRINT("TEMPORARY %s ---> new path=\"%s\"\n", __FUNCTION__, p1);
793 
794  // also I want to make sure that the file name control contains the new path
795  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, p1);
796 
797  WBFree(p1);
798  }
799 
800  return 1; // handled (do not close the dialog box)
801  }
802  }
803 
804  WBEndModal(wID, pEvent->xclient.data.l[1]);
805  return 1; // handled!
806  }
807  break;
808 
809  case FILE_DIALOG_FILE_LIST_CONTROL:
810  if(pEvent->xclient.data.l[0] == aLIST_NOTIFY) // list control notifications
811  {
812  if(pEvent->xclient.data.l[2] == WB_LIST_SELCHANGE)
813  {
814  // assign the textbox value to the selected text
815  if(pEvent->xclient.data.l[3] >= 0)
816  {
817  WBDialogControl *pCtrl = DLGGetDialogControlStructFromID(pDlg, pEvent->xclient.data.l[1]);
818  if(pCtrl)
819  {
820  const char *pText = DLGGetControlListText(pCtrl, pEvent->xclient.data.l[3]);
821 
822  if(pText)
823  {
824 // WB_WARN_PRINT("%s - assigning control text \"%s\"\n", __FUNCTION__, pText);
825  if(*pText == '@')
826  {
827  char *p1 = WBCopyString(pText + 1);
828 
829  if(p1)
830  {
831  WBCatString(&p1, "/");
832  if(p1)
833  {
834  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, p1);
835  WBFree(p1);
836  }
837  }
838  }
839  else // assume '~'
840  {
841  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, pText + 1);
842  }
843  }
844  }
845  }
846 
847  return 1; // handled
848  }
849  else if(pEvent->xclient.data.l[2] == WB_LIST_DBLCLICK)
850  {
851  // NOTE: pEvent->xclient.data.l[3] contains the selection index
852 
853  // Rather than allowing the default handler to deal with it, post an 'OK' button notification
854  // so that the same code deals with THIS as with the OK button
855 
856 // XClientMessageEvent evt = {
857 // .type=ClientMessage,
858 // .serial=0,
859 // .send_event=0,
860 // .display=pDisplay,
861 // .window=wID,
862 // .message_type=aCONTROL_NOTIFY,
863 // .format=32
864 // };
865 // evt.data.l[0] = aBUTTON_PRESS;
866 // evt.data.l[1] = IDOK;
867 // evt.data.l[2] = 0;
868 // evt.data.l[3] = 0;
869 // evt.data.l[4] = 0;
870 //
871 // WBPostPriorityEvent(wID, (XEvent *)&evt);
872 
873  // build a 'click' notification event to make sure I capture the correct name
874  DLGNotifyDlg(pDlg, aCONTROL_NOTIFY, aLIST_NOTIFY, FILE_DIALOG_FILE_LIST_CONTROL,
875  WB_LIST_SELCHANGE, pEvent->xclient.data.l[3], 0); // duplicates a 'SEL CHANGE" event
876 
877  {
878 #ifndef NO_DEBUG
879  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
880  WB_WARN_PRINT("%s - LIST_NOTIFY WB_LIST_DBLCLICK control notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
881  __FUNCTION__, pEvent->xclient.data.l[0], p1,
882  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
883  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
884  if(p1)
885  {
886  WBFree(p1);
887  }
888 #endif // NO_DEBUG
889  }
890 
891  DLGNotifyDlgAsync(pDlg, aCONTROL_NOTIFY, aBUTTON_PRESS, IDOK, 0, 0, 0); // post a button press event
892 
893  return 1;
894  }
895 
896  return 0; // not handled
897  }
898  break;
899 
900  default:
901  {
902 #ifndef NO_DEBUG
903  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
904 
905  WB_WARN_PRINT("%s - TODO: control notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
906  __FUNCTION__, pEvent->xclient.data.l[0], p1,
907  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
908  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
909 
910  if(p1)
911  {
912  WBFree(p1);
913  }
914 #endif // NO_DEBUG
915  }
916  }
917  }
918  else if(pEvent->xclient.message_type == aGOTFOCUS)
919  {
920  // control ID is in pEvent->xclient.data.l[0]
921  return 0; // for now
922  }
923  else if(pEvent->xclient.message_type == aLOSTFOCUS)
924  {
925  // control ID is in pEvent->xclient.data.l[0]
926  return 0; // for now
927  }
928  else
929  {
930 #ifndef NO_DEBUG
931  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.message_type);
932  char *p2 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
933 
934  WB_WARN_PRINT("%s - unhandled notification %s %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
935  __FUNCTION__, p1,
936  pEvent->xclient.data.l[0], p2,
937  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
938  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
939 
940  if(p1)
941  {
942  WBFree(p1);
943  }
944  if(p2)
945  {
946  WBFree(p2);
947  }
948 #endif // NO_DEBUG
949  }
950 
951  return 0;
952 }
953 
954 #define FILE_DIALOG_WIDTH 520
955 #define FILE_DIALOG_HEIGHT 500
956 
957 char *DLGFileDialog(int iType, Window wIDOwner, const char *szDefPath, const char *szDefName,
958  const char *szExtAndDescList)
959 {
960 static const char szFileDialogRes[]=
961  "BEGIN_DIALOG FONT:Variable HEIGHT:250 WIDTH:260 TITLE:\"File Dialog\"\n"
962  " CONTROL:PathTree ID:1000 X:2 Y:2 HEIGHT:200 WIDTH:116 VISIBLE\n"
963  " CONTROL:FileList ID:1001 X:122 Y:2 HEIGHT:200 WIDTH:136 VISIBLE\n"
964  " CONTROL:Edit ID:1002 X:2 Y:206 WIDTH:296 HEIGHT:16 VISIBLE\n"
965  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:40 Y:230 WIDTH:40 HEIGHT:18 VISIBLE\n"
966  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:180 Y:230 WIDTH:40 HEIGHT:18 VISIBLE\n"
967  "END_DIALOG\n";
968 WBDialogWindow *pDlg;
969 struct _FILE_DIALOG_ data;
970 int iX, iY, iRval;
971 Window wIDDlg;
972 WB_GEOM geomParent;
973 
974 
975  bzero(&geomParent, sizeof(geomParent));
976 
977  if(wIDOwner != None)
978  {
979  WBGetWindowGeom0(wIDOwner, &geomParent); // parent geometry in absolute coordinates
980 
981  iX = geomParent.x + geomParent.border + MESSAGE_BOX_OFFSET;
982  iY = geomParent.y + geomParent.border + MESSAGE_BOX_OFFSET;
983  }
984  else
985  {
986  // center in screen with slight random offset (so that every window won't always appear in exactly the same place)
987  iY = (DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
988  - FILE_DIALOG_HEIGHT + MESSAGE_BOX_OFFSET - (int)(WBGetTimeIndex() % (2 * MESSAGE_BOX_OFFSET)))
989  / 2;
990 
991  iX = (DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
992  - FILE_DIALOG_WIDTH + MESSAGE_BOX_OFFSET - (int)((~WBGetTimeIndex()) % (2 * MESSAGE_BOX_OFFSET)))
993  / 2;
994  }
995 
996  data.szDefPath = szDefPath;
997  data.szDefName = szDefName;
998  data.szExtAndDescList = szExtAndDescList;
999  data.szPathName = NULL;
1000 
1001 
1002  pDlg = DLGCreateDialogWindow(wIDOwner, "File Select",szFileDialogRes,
1003  iX, iY,FILE_DIALOG_WIDTH,FILE_DIALOG_HEIGHT,
1004  FileDialogCallback,
1005  WBDialogWindow_VISIBLE,&data);
1006 
1007  if(pDlg)
1008  {
1009  wIDDlg = pDlg->wID;
1010 
1011  iRval = WBShowModal(pDlg->wID, 0);
1012 
1013  if(iRval == IDOK)
1014  {
1015  if(data.szPathName)
1016  {
1017  return data.szPathName;
1018  }
1019  else
1020  {
1021  return NULL; // for now, to prevent page fault
1022  }
1023  }
1024  }
1025 
1026  // it ends up here on 'cancel', etc. - so if a buffer was allocated, free it
1027 
1028  if(data.szPathName)
1029  {
1030  WBFree(data.szPathName);
1031  }
1032 
1033  return NULL;
1034 }
1035 
1036 
1038 // COLOR DIALOG
1040 
1041 struct _COLOR_DIALOG_
1042 {
1043  int iLuma, iChroma, iSaturation;
1044  int iRed, iGreen, iBlue; // 0-255 RGB values
1045  unsigned long lPixel; // XColor pixel value
1046  XStandardColormap stdColorMap;
1047  XColor *pColor; // to be assigned on exit
1048 
1049  // 'old' control values for when values change
1050  int iOldL, iOldC, iOldS, iOldR, iOldG, iOldB;
1051  unsigned long lOldP;
1052 
1053  // TODO: additional cached internal values for image and pixmap
1054 
1055  int iXLumaSat, iYLumaSat, iXChroma, iOldXLS, iOldYLS, iOldXC;
1056  XImage *pimgLumaSat, *pimgChroma;
1057  Pixmap pixmapLumaSat, pixmapChroma;
1058 };
1059 
1060 #define LUMA_SAT_PICKER 1001
1061 #define CHROMA_PICKER 1002
1062 #define LUMA_BOX 1003
1063 #define CHROMA_BOX 1004
1064 #define SAT_BOX 1005
1065 #define RED_BOX 1006
1066 #define GREEN_BOX 1007
1067 #define BLUE_BOX 1008
1068 #define COLORBOX 1009
1069 #define COLORBOX_VALUE 1010
1070 
1071 #define COLOR_IMAGE_SIZE 256 /* note that dialog units are 2 pixels each */
1072 #define CHROMA_RIBBON_HEIGHT 24 /* note that dialog units are 2 pixels each */
1073 #define COLOR_IMAGE_COLOR_FACTOR 1 /* multiply by this to get 0-255 [effectively] */
1074 #define COLORBOX_PIXMAP_WIDTH 96 /* width of 'colorbox' pixmap */
1075 #define COLORBOX_PIXMAP_HEIGHT 24 /* height of 'colorbox' pixmap */
1076 
1077 #ifdef COMPILER_SUPPORTS_UNUSED_ATTRIBUTE
1078 // prototype needed so I can declare it 'WB_UNUSED'
1079 static void ColorDialogDumpData(const char *szCaption, struct _COLOR_DIALOG_ *pData) WB_UNUSED;
1080 #endif // COMPILER_SUPPORTS_UNUSED_ATTRIBUTE
1081 
1082 static void ColorDialogDumpData(const char *szCaption, struct _COLOR_DIALOG_ *pData)
1083 {
1084  WBDebugPrint("ColorDialogDumpData - %s\n", szCaption);
1085  WBDebugPrint(" iLuma=%-3d iChroma=%-3d iSaturation=%-3d\n",
1086  pData->iLuma, pData->iChroma, pData->iSaturation);
1087  WBDebugPrint(" iRed=%-3d iGreen=%-3d iBlue=%-3d\n",
1088  pData->iRed, pData->iGreen, pData->iBlue);
1089 
1090  WBDebugPrint(" iOldL=%-3d iOldC=%-3d iOldS=%-3d\n",
1091  pData->iOldL, pData->iOldC, pData->iOldS);
1092  WBDebugPrint(" iOldR=%-3d iOldG=%-3d iOldB=%-3d\n",
1093  pData->iOldR, pData->iOldG, pData->iOldB);
1094 
1095  WBDebugPrint(" lPixel = %-8lu \"#%-6.6lX\"\n", pData->lPixel, pData->lPixel);
1096  WBDebugPrint(" lOldP = %-8lu \"#%-6.6lX\"\n\n", pData->lOldP, pData->lOldP);
1097 
1098  WBDebugPrint(" iXLumaSat = %-3d iYLumaSat = %-3d iXChroma = %-3d\n"
1099  " iOldXLS = %-3d iOldYLS = %-3d iOldXC = %-3d\n\n",
1100  pData->iXLumaSat, pData->iYLumaSat, pData->iXChroma,
1101  pData->iOldXLS, pData->iOldYLS, pData->iOldXC);
1102 
1103  WBDebugPrint(" pimgLumaSat = %p\n", pData->pimgLumaSat);
1104  WBDebugPrint(" pimgChroma = %p\n", pData->pimgChroma);
1105 
1106  WBDebugPrint(" pixmapLumaSat = %lu (%lxH)\n",
1107  (unsigned long)pData->pimgLumaSat, (unsigned long)pData->pimgLumaSat);
1108  WBDebugPrint(" pixmapChroma = %lu (%lxH)\n",
1109  (unsigned long)pData->pimgChroma, (unsigned long)pData->pimgChroma);
1110  WBDebugPrint("**********************************************************************\n");
1111 }
1112 
1113 static XImage * CreateLumaSaturationImage(Display *pDisplay, XStandardColormap *pSCM, int nChroma)
1114 {
1115 int iR, iG, iB, iSat, iLum;
1116 XImage *pImage;
1117 
1118 
1119  pImage = WBXGetImage(WBGetDefaultDisplay(), None, 0, 0, COLOR_IMAGE_SIZE, COLOR_IMAGE_SIZE,
1120  0xffffffff, XYPixmap);
1121 
1122  if(pImage == None)
1123  {
1124  return None;
1125  }
1126 
1127 // pData->cbImageData = PXM_GetImageDataLength(pI);
1128 // pData->pImageData = WBAlloc(pData->cbImageData + 4);
1129 //
1130 // if(pData->pImageData)
1131 // {
1132 // memcpy(pData->pImageData, PXM_GetImageDataPtr(pI), pData->cbImageData);
1133 // }
1134 
1135 // PXM_RGBToHSV(iR, iG, iB, &nChroma, &iSat, &iLum);
1136 
1137  for(iSat = COLOR_IMAGE_SIZE - 1; iSat >= 0; iSat--)
1138  {
1139  for(iLum = 0; iLum < COLOR_IMAGE_SIZE; iLum++)
1140  {
1141  XColor clr;
1142 
1143  PXM_HSVToRGB(nChroma,
1144  iSat * COLOR_IMAGE_COLOR_FACTOR,
1145  iLum * COLOR_IMAGE_COLOR_FACTOR,
1146  &iR, &iG, &iB);
1147 
1148  RGB255_TO_XCOLOR(iR, iG, iB, clr);
1149  PXM_RGBToPixel(pSCM, &clr); // make sure the RGB members are correct
1150 
1151  // use XPutPixel to put the pixel at row 'iSat', column 'iLum'
1152 
1153  XPutPixel(pImage, iLum, iSat, clr.pixel); // this should actually be VERY fast
1154  }
1155  }
1156 
1157  return pImage;
1158 }
1159 
1160 static XImage * CreateChromaImage(Display *pDisplay, XStandardColormap *pSCM)
1161 {
1162 int iR, iG, iB, iChroma, iRow;
1163 XImage *pImage;
1164 
1165 
1166  pImage = WBXGetImage(pDisplay, None, 0, 0, COLOR_IMAGE_SIZE, CHROMA_RIBBON_HEIGHT,
1167  0xffffffff, XYPixmap);
1168 
1169  if(pImage == None)
1170  {
1171  return None;
1172  }
1173 
1174  for(iChroma=0; iChroma < COLOR_IMAGE_SIZE; iChroma++)
1175  {
1176  XColor clr;
1177 
1178  PXM_HSVToRGB(iChroma * COLOR_IMAGE_COLOR_FACTOR,
1179  255, 255, &iR, &iG, &iB);
1180 
1181  RGB255_TO_XCOLOR(iR, iG, iB, clr);
1182  PXM_RGBToPixel(pSCM, &clr); // make sure the RGB members are correct
1183 
1184  // use XPutPixel to put the pixel at row 'iSat', column 'iLum'
1185  for(iRow=0; iRow < CHROMA_RIBBON_HEIGHT; iRow++)
1186  {
1187  XPutPixel(pImage, iChroma, iRow, clr.pixel); // this should actually be VERY fast
1188  }
1189  }
1190 
1191  return pImage;
1192 }
1193 
1194 static void ColorDialogImagesFromData(Display *pDisplay, WBDialogControl *pctrlLumaSat,
1195  WBDialogControl *pctrlChroma, struct _COLOR_DIALOG_ *pUserData)
1196 {
1197 // int iXLumaSat, iYLumaSat, iXChroma, iOldXLS, iOldYLS, iOldXC;
1198 
1199 
1200 
1201 }
1202 
1203 static void ColorDialogDataFromPixel(struct _COLOR_DIALOG_ *pUserData)
1204 {
1205 XColor clr;
1206 
1207  clr.pixel = pUserData->lPixel;
1208 
1209  PXM_PixelToRGB(&(pUserData->stdColorMap), &clr); // make sure the RGB members are correct
1210 
1211  RGB255_FROM_XCOLOR(clr, pUserData->iRed, pUserData->iGreen, pUserData->iBlue);
1212 
1213  PXM_RGBToHSV(pUserData->iRed, pUserData->iGreen, pUserData->iBlue,
1214  &pUserData->iChroma,
1215  &pUserData->iSaturation,
1216  &pUserData->iLuma);
1217 
1218 
1219  // fix all of the 'old' values to match
1220  pUserData->iOldR = pUserData->iRed;
1221  pUserData->iOldG = pUserData->iGreen;
1222  pUserData->iOldB = pUserData->iBlue;
1223 
1224  pUserData->iOldC = pUserData->iChroma;
1225  pUserData->iOldL = pUserData->iLuma;
1226  pUserData->iOldS = pUserData->iSaturation;
1227 
1228  pUserData->lOldP = pUserData->lPixel;
1229 }
1230 
1231 static int ColorDialogRGBFromHSV(struct _COLOR_DIALOG_ *pUserData)
1232 {
1233 XColor clr;
1234 int iRval;
1235 
1236  PXM_HSVToRGB(pUserData->iChroma, pUserData->iSaturation, pUserData->iLuma,
1237  &pUserData->iRed,
1238  &pUserData->iGreen,
1239  &pUserData->iBlue);
1240 
1241  RGB255_TO_XCOLOR(pUserData->iRed, pUserData->iGreen, pUserData->iBlue, clr);
1242  PXM_RGBToPixel(&(pUserData->stdColorMap), &clr); // make sure the pixel is correct
1243 
1244  pUserData->lPixel = clr.pixel; // and now I'm consistent!
1245 
1246  iRval = pUserData->lOldP != pUserData->lPixel ||
1247  pUserData->iOldR != pUserData->iRed ||
1248  pUserData->iOldG != pUserData->iGreen ||
1249  pUserData->iOldB != pUserData->iBlue ||
1250  pUserData->iOldC != pUserData->iChroma ||
1251  pUserData->iOldL != pUserData->iLuma ||
1252  pUserData->iOldS != pUserData->iSaturation;
1253 
1254  // fix all of the 'old' values to match
1255  pUserData->iOldR = pUserData->iRed;
1256  pUserData->iOldG = pUserData->iGreen;
1257  pUserData->iOldB = pUserData->iBlue;
1258 
1259  pUserData->iOldC = pUserData->iChroma;
1260  pUserData->iOldL = pUserData->iLuma;
1261  pUserData->iOldS = pUserData->iSaturation;
1262 
1263  pUserData->lOldP = pUserData->lPixel;
1264 
1265  return iRval;
1266 }
1267 
1268 static int ColorDialogHSVFromRGB(struct _COLOR_DIALOG_ *pUserData)
1269 {
1270 XColor clr;
1271 int iRval;
1272 
1273  PXM_RGBToHSV(pUserData->iRed, pUserData->iGreen, pUserData->iBlue,
1274  &pUserData->iChroma,
1275  &pUserData->iSaturation,
1276  &pUserData->iLuma);
1277 
1278  RGB255_TO_XCOLOR(pUserData->iRed, pUserData->iGreen, pUserData->iBlue, clr);
1279  PXM_RGBToPixel(&(pUserData->stdColorMap), &clr); // make sure the pixel is correct
1280 
1281  pUserData->lPixel = clr.pixel; // and now I'm consistent!
1282 
1283  iRval = pUserData->lOldP != pUserData->lPixel ||
1284  pUserData->iOldR != pUserData->iRed ||
1285  pUserData->iOldG != pUserData->iGreen ||
1286  pUserData->iOldB != pUserData->iBlue ||
1287  pUserData->iOldC != pUserData->iChroma ||
1288  pUserData->iOldL != pUserData->iLuma ||
1289  pUserData->iOldS != pUserData->iSaturation;
1290 
1291  // fix all of the 'old' values to match
1292  pUserData->iOldR = pUserData->iRed;
1293  pUserData->iOldG = pUserData->iGreen;
1294  pUserData->iOldB = pUserData->iBlue;
1295 
1296  pUserData->iOldC = pUserData->iChroma;
1297  pUserData->iOldL = pUserData->iLuma;
1298  pUserData->iOldS = pUserData->iSaturation;
1299 
1300  pUserData->lOldP = pUserData->lPixel;
1301 
1302  return iRval;
1303 }
1304 
1305 static void ColorDialogAssignColorboxPixmap(Display *pDisplay, WBDialogControl *pCtrl, unsigned long lPixel)
1306 {
1307 WBGC gc;
1308 Pixmap pxTemp;
1309 XGCValues xgcv;
1310 int iW = COLORBOX_PIXMAP_WIDTH;
1311 int iH = COLORBOX_PIXMAP_HEIGHT;
1312 //WB_GEOM geom;
1313 
1314 
1315 // // TEMPORARY - to make sure I fill the thing...
1316 // WBGetWindowGeom(pCtrl->wID, &geom);
1317 //
1318 // if((geom.width - 4) > iW || (geom.height - 4) > iH)
1319 // {
1320 // WB_ERROR_PRINT("TEMPORARY: %s - re-assign width/height from %d,%d to %d,%d\n",
1321 // __FUNCTION__, iW, iH, geom.width - 4, geom.height - 4);
1322 //
1323 // iW = geom.width - 4;
1324 // iH = geom.height - 4;
1325 // }
1326 
1327  // step 1: a simple graphics context to fill the rectangle with
1328 
1329  bzero(&xgcv, sizeof(xgcv));
1330  xgcv.foreground = lPixel;
1331  xgcv.background = lPixel;
1332  xgcv.line_width = 1;
1333  xgcv.function = GXcopy; // copy
1334  xgcv.cap_style = CapProjecting;
1335 
1336  gc = WBCreateGC(pDisplay, pCtrl->wID,
1337  (GCForeground | GCBackground | GCCapStyle | GCFunction | GCLineWidth),
1338  &xgcv);
1339 
1340  if(gc == None)
1341  {
1342  WB_ERROR_PRINT("ERROR: %s - unable to create gc for pixmap\n", __FUNCTION__);
1343  return;
1344  }
1345 
1346 // XSetForeground(pDisplay, gc, lPixel);
1347 // XSetBackground(pDisplay, gc, lPixel); // assign to the same color
1348 
1349  // step 2: create a pixmap that's the right size
1350 
1351  pxTemp = XCreatePixmap(pDisplay, pCtrl->wID, iW, iH,
1352  DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
1353 
1354  if(pxTemp == None)
1355  {
1356  WB_ERROR_PRINT("ERROR: %s - unable to create pixmap\n", __FUNCTION__);
1357  }
1358  else
1359  {
1360  WBFillRectangle(pDisplay, pxTemp, gc, 0, 0, iW, iH);
1361 
1362  // set pixmap for control now - control will own it.
1363 
1364  WBDialogControlSetPixmap(pCtrl, pxTemp); // and done!
1365  }
1366 
1367  WBDialogControlInvalidateGeom(pCtrl, NULL, 1); // paints immediately
1368 
1369  WBFreeGC(gc);
1370 }
1371 
1372 static void ColorDialogAssignLumaSatPixmap(Display *pDisplay, WBDialogControl *pCtrl, int iS, int iV)
1373 {
1374 }
1375 
1376 static void ColorDialogAssignChromaPixmap(Display *pDisplay, WBDialogControl *pCtrl, int iH)
1377 {
1378 }
1379 
1380 static unsigned long ColorDialogGetPixelValueFromControl(WBDialogControl *pCtrl)
1381 {
1382 const char *pTemp;
1383 const char *p3;
1384 unsigned long lPixel;
1385 
1386 
1387  lPixel = 0; // pre-assign to zero
1388 
1389  pTemp = WBDialogControlGetCaption(pCtrl);
1390 
1391  if(pTemp && *pTemp)
1392  {
1393  p3 = pTemp;
1394  while(*p3 && *p3 <= ' ') // skip leading white space
1395  {
1396  p3++;
1397  }
1398  if(*p3 == '#')
1399  {
1400  sscanf(p3 + 1, "%lX", &lPixel);
1401  }
1402  else if(!strncasecmp("0x", p3, 2))
1403  {
1404  sscanf(p3, "%lX", &lPixel);
1405  }
1406  else
1407  {
1408  sscanf(p3, "%ld", &lPixel);
1409  }
1410 
1411  lPixel &= 0xffffffff; // for now, limit to a 32-bit value (later, allow 64-bit colors?)
1412  }
1413 
1414  return lPixel;
1415 }
1416 
1417 
1418 static int ColorDialogCallback(Window wID, XEvent *pEvent)
1419 {
1420 Display *pDisplay = WBGetWindowDisplay(wID);
1422 struct _COLOR_DIALOG_ *pUserData = (struct _COLOR_DIALOG_ *)(pDlg ? pDlg->pUserData : NULL);
1423 //Display *pDisplay = WBGetWindowDisplay(wID);
1424 
1425 
1426  if(!pDlg || !pUserData)
1427  {
1428  return 0; // can't process any messages now
1429  }
1430 
1431  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
1432  {
1433  // initialize dialog box
1434 
1435  ColorDialogDataFromPixel(pUserData); // make everything in 'pUserData' consistent
1436 
1437  // now, assign correct values to the image coordinates representing color info
1438  if(pUserData->lPixel == 0) // black
1439  {
1440  pUserData->iXLumaSat = 0;
1441  pUserData->iYLumaSat = 0;
1442  }
1443  else
1444  {
1445  pUserData->iXLumaSat = (pUserData->iLuma + (COLOR_IMAGE_COLOR_FACTOR - 1))
1446  / COLOR_IMAGE_COLOR_FACTOR;
1447  pUserData->iYLumaSat = COLOR_IMAGE_SIZE
1448  - (pUserData->iSaturation + (COLOR_IMAGE_COLOR_FACTOR - 1))
1449  / COLOR_IMAGE_COLOR_FACTOR;
1450  }
1451 
1452  pUserData->iXChroma = (pUserData->iChroma + (COLOR_IMAGE_COLOR_FACTOR - 1))
1453  / COLOR_IMAGE_COLOR_FACTOR;
1454 
1455  pUserData->iOldXLS = pUserData->iOldYLS = pUserData->iOldXC = -1; // force re-initialization, just in case
1456 
1457  ColorDialogImagesFromData(pDisplay, WBGetDialogEntryControlStruct(pDlg, LUMA_SAT_PICKER),
1458  WBGetDialogEntryControlStruct(pDlg, CHROMA_PICKER), pUserData);
1459 
1461  pUserData->iLuma, NULL);
1463  pUserData->iChroma, NULL);
1465  pUserData->iSaturation, NULL);
1466 
1468  pUserData->iRed, NULL);
1470  pUserData->iGreen, NULL);
1472  pUserData->iBlue, NULL);
1473 
1475  pUserData->lPixel, "#%-08.8lX");
1476 
1477  ColorDialogAssignColorboxPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, COLORBOX_VALUE),
1478  pUserData->lPixel);
1479 
1480  ColorDialogAssignLumaSatPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, LUMA_SAT_PICKER),
1481  pUserData->iSaturation, pUserData->iLuma);
1482  ColorDialogAssignChromaPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, CHROMA_PICKER),
1483  pUserData->iChroma);
1484 
1485  return 1;
1486  }
1487 
1488  if(pEvent->type != ClientMessage)
1489  {
1490  return 0; // unhandled at this time
1491  }
1492 
1493  // EVERYTHING AT THIS POINT IS A CLIENT MESSAGE
1494 
1495  if(pEvent->xclient.message_type == aCONTROL_NOTIFY)
1496  {
1497  // l[0] == message
1498  // l[1] == control ID
1499  // l[2] == hashed pointer to control's structure
1500  // [the rest are event dependent]
1501 
1502  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
1503  {
1504  switch(pEvent->xclient.data.l[1])
1505  {
1506  case IDOK:
1507  case IDCANCEL:
1508  if(pEvent->xclient.data.l[1] == IDOK)
1509  {
1510  // do any data copying that's necessary on 'OK'
1511 
1512  pUserData->iRed = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, RED_BOX));
1513  pUserData->iGreen = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, GREEN_BOX));
1514  pUserData->iBlue = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, BLUE_BOX));
1515 
1516  if(pUserData->iRed != pUserData->iOldR ||
1517  pUserData->iGreen != pUserData->iOldG ||
1518  pUserData->iBlue != pUserData->iOldB)
1519  {
1520  ColorDialogHSVFromRGB(pUserData);
1521  }
1522  else
1523  {
1524  pUserData->lPixel = ColorDialogGetPixelValueFromControl(WBGetDialogEntryControlStruct(pDlg, COLORBOX_VALUE));
1525 
1526  if(pUserData->lPixel != pUserData->lOldP)
1527  {
1528  ColorDialogDataFromPixel(pUserData); // make everything in 'pUserData' consistent with 'lPixel'
1529  }
1530  else
1531  {
1532  pUserData->iLuma = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, LUMA_BOX));
1533  pUserData->iChroma = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, CHROMA_BOX));
1534  pUserData->iSaturation = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, SAT_BOX));
1535 
1536  if(pUserData->iLuma != pUserData->iOldL ||
1537  pUserData->iChroma != pUserData->iOldC ||
1538  pUserData->iSaturation != pUserData->iOldS)
1539  {
1540  ColorDialogRGBFromHSV(pUserData); // fix it
1541  }
1542  }
1543  }
1544 
1545  if(pUserData->pColor) // if I have an XColor, which I should, then set it up correctly
1546  {
1547  pUserData->pColor->pixel = pUserData->lPixel;
1548  PXM_PixelToRGB(&(pUserData->stdColorMap), pUserData->pColor);
1549  }
1550  else // the following code won't execute at this time, left for reference later
1551  {
1552  // TODO: send a notification event to the owner window??
1553  }
1554  }
1555 
1556  WBEndModal(wID, pEvent->xclient.data.l[1]); // all buttons close the dialog box
1557  return 1; // handled!
1558  }
1559  }
1560  else if((pEvent->xclient.data.l[0] == aMOUSE_CLICK ||
1561  pEvent->xclient.data.l[0] == aMOUSE_DBLCLICK ||
1562  pEvent->xclient.data.l[0] == aMOUSE_DRAG) &&
1563  WB_LIKELY(pEvent->xclient.data.l[1] == LUMA_SAT_PICKER ||
1564  pEvent->xclient.data.l[1] == CHROMA_PICKER))
1565  {
1566 #ifndef NO_DEBUG
1567  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
1568 
1569  WB_ERROR_PRINT("%s - TODO: control MOUSE notification message %ld (%s) %ld (%08lxH), %ld (%08lxH), %ld (%08lxH), %ld (%08lxH)\n",
1570  __FUNCTION__, pEvent->xclient.data.l[0], p1,
1571  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
1572  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2],
1573  pEvent->xclient.data.l[3], pEvent->xclient.data.l[3],
1574  pEvent->xclient.data.l[4], pEvent->xclient.data.l[4]);
1575 
1576  if(p1)
1577  {
1578  WBFree(p1);
1579  }
1580 #endif // NO_DEBUG
1581  }
1582  else
1583  {
1584 #ifndef NO_DEBUG
1585  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
1586 
1587  WB_WARN_PRINT("%s - TODO: control notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
1588  __FUNCTION__, pEvent->xclient.data.l[0], p1,
1589  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
1590  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
1591 
1592  if(p1)
1593  {
1594  WBFree(p1);
1595  }
1596 #endif // NO_DEBUG
1597  }
1598  }
1599  else if(pEvent->xclient.message_type == aLOSTFOCUS) // monitor these
1600  {
1601  switch(pEvent->xclient.data.l[0]) // the control identifier
1602  {
1603  case IDOK:
1604  case IDCANCEL:
1605  break; // don't bother here
1606 
1607  case COLORBOX_VALUE:
1608  pUserData->lPixel = ColorDialogGetPixelValueFromControl(WBGetDialogEntryControlStruct(pDlg, COLORBOX_VALUE));
1609 
1610  if(pUserData->lPixel != pUserData->lOldP) // value changed?
1611  {
1612  WB_ERROR_PRINT("TEMPORARY: %s - Color Value Box Changed from %ld to %ld\n", __FUNCTION__, pUserData->lOldP, pUserData->lPixel);
1613 
1614  ColorDialogDataFromPixel(pUserData); // make everything in 'pUserData' consistent with 'lPixel'
1615 
1616  goto fix_rgb_hsv_and_colors;
1617  }
1618 
1619  break; // no change so bust out now
1620 
1621  case LUMA_SAT_PICKER:
1622  case CHROMA_PICKER:
1623 
1624  // NOTE: click/drag on color boxen should automatically fix luma/chroma/sat
1625  // while clicking and dragging, so assume it's good now
1626  if(ColorDialogRGBFromHSV(pUserData)) // fixes everything
1627  {
1628 fix_rgb_hsv_and_colors:
1630  pUserData->iLuma, NULL);
1632  pUserData->iChroma, NULL);
1634  pUserData->iSaturation, NULL);
1635 
1637  pUserData->iRed, NULL);
1639  pUserData->iGreen, NULL);
1641  pUserData->iBlue, NULL);
1642 
1643  // ALWAYS do this one - it reformats the text in 'COLORBOX_VALUE' to standard color designator
1645  pUserData->lPixel, "#%-08.8lX");
1646 
1647  ColorDialogAssignColorboxPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, COLORBOX), pUserData->lPixel);
1648 
1649  if(pEvent->xclient.data.l[1] == COLORBOX_VALUE) // for color value, do the next part
1650  {
1651  ColorDialogAssignLumaSatPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, LUMA_SAT_PICKER),
1652  pUserData->iSaturation, pUserData->iLuma);
1653  ColorDialogAssignChromaPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, CHROMA_PICKER),
1654  pUserData->iChroma);
1655  }
1656  }
1657 
1658  break;
1659 
1660  case LUMA_BOX:
1661  pUserData->iLuma = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, LUMA_BOX)) & 0xff;
1662  if(pUserData->iLuma != pUserData->iOldL) // value changed?
1663  {
1664  WB_ERROR_PRINT("TEMPORARY: %s - Luma Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldL, pUserData->iLuma);
1665 fix_rgb_and_colors:
1666  ColorDialogRGBFromHSV(pUserData);
1667 
1669  pUserData->iRed, NULL);
1671  pUserData->iGreen, NULL);
1673  pUserData->iBlue, NULL);
1674 
1676  pUserData->lPixel, "#%-08.8lX");
1677 
1678  ColorDialogAssignColorboxPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, COLORBOX), pUserData->lPixel);
1679  ColorDialogAssignLumaSatPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, LUMA_SAT_PICKER),
1680  pUserData->iSaturation, pUserData->iLuma);
1681  ColorDialogAssignChromaPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, CHROMA_PICKER),
1682  pUserData->iChroma);
1683  }
1684 
1685  break;
1686 
1687  case CHROMA_BOX:
1688  pUserData->iChroma = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, CHROMA_BOX)) & 0xff;
1689  if(pUserData->iChroma != pUserData->iOldC) // value changed?
1690  {
1691  WB_ERROR_PRINT("TEMPORARY: %s - Chroma Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldC, pUserData->iChroma);
1692  goto fix_rgb_and_colors;
1693  }
1694 
1695  break;
1696 
1697  case SAT_BOX:
1698  pUserData->iSaturation = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, SAT_BOX)) & 0xff;
1699  if(pUserData->iSaturation != pUserData->iOldS) // value changed?
1700  {
1701  WB_ERROR_PRINT("TEMPORARY: %s - Sat Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldS, pUserData->iSaturation);
1702  goto fix_rgb_and_colors;
1703  }
1704 
1705  break;
1706 
1707 
1708  case RED_BOX:
1709  pUserData->iRed = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, RED_BOX)) & 0xff;
1710  if(pUserData->iRed != pUserData->iOldR) // value changed?
1711  {
1712  WB_ERROR_PRINT("TEMPORARY: %s - Red Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldR, pUserData->iRed);
1713 fix_hsv_and_colors:
1714  ColorDialogHSVFromRGB(pUserData);
1715 
1717  pUserData->iLuma, NULL);
1719  pUserData->iChroma, NULL);
1721  pUserData->iSaturation, NULL);
1722 
1724  pUserData->lPixel, "#%-08.8lX");
1725 
1726  ColorDialogAssignColorboxPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, COLORBOX), pUserData->lPixel);
1727  ColorDialogAssignLumaSatPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, LUMA_SAT_PICKER),
1728  pUserData->iSaturation, pUserData->iLuma);
1729  ColorDialogAssignChromaPixmap(pDisplay, WBGetDialogEntryControlStruct(pDlg, CHROMA_PICKER),
1730  pUserData->iChroma);
1731  }
1732 
1733  break;
1734 
1735  case GREEN_BOX:
1736  pUserData->iGreen = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, GREEN_BOX)) & 0xff;
1737  if(pUserData->iGreen != pUserData->iOldG) // value changed?
1738  {
1739  WB_ERROR_PRINT("TEMPORARY: %s - Green Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldG, pUserData->iGreen);
1740  goto fix_hsv_and_colors;
1741  }
1742 
1743  break;
1744 
1745  case BLUE_BOX:
1746  pUserData->iBlue = WBDialogControlGetCaptionInt(WBGetDialogEntryControlStruct(pDlg, BLUE_BOX)) & 0xff;
1747  if(pUserData->iBlue != pUserData->iOldB) // value changed?
1748  {
1749  WB_ERROR_PRINT("TEMPORARY: %s - Blue Box Changed from %d to %d\n", __FUNCTION__, pUserData->iOldB, pUserData->iBlue);
1750  goto fix_hsv_and_colors;
1751  }
1752 
1753  break;
1754  }
1755  return 0; // I want this to happen because it lets other things happen, too
1756  }
1757  else if(pEvent->xclient.message_type == aGOTFOCUS)
1758  {
1759 //#ifndef NO_DEBUG
1760 // {
1761 // char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
1762 //
1763 // WB_WARN_PRINT("TEMPORARY: %s - GOT FOCUS notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
1764 // __FUNCTION__, pEvent->xclient.data.l[0], p1,
1765 // pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
1766 // pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
1767 //
1768 // if(p1)
1769 // {
1770 // WBFree(p1);
1771 // }
1772 // }
1773 //#endif // NO_DEBUG
1774 
1775  // control ID is in pEvent->xclient.data.l[0]
1776 
1777  return 0; // for now
1778  }
1779  else
1780  {
1781 #ifndef NO_DEBUG
1782  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.message_type);
1783  char *p2 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
1784 
1785  WB_WARN_PRINT("%s - unhandled ClientMessage %d (%s) %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
1786  __FUNCTION__, (int)pEvent->xclient.message_type, (const char *)(p1 ? p1 : "(Null)"),
1787  pEvent->xclient.data.l[0], (const char *)(p2 ? p2 : "(Null)"),
1788  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
1789  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
1790 
1791  if(p1)
1792  {
1793  WBFree(p1);
1794  }
1795  if(p2)
1796  {
1797  WBFree(p2);
1798  }
1799 #endif // NO_DEBUG
1800  }
1801 
1802  return 0;
1803 }
1804 
1805 #define COLOR_DIALOG_WIDTH 560
1806 #define COLOR_DIALOG_HEIGHT 364
1807 
1808 int DLGColorDialog(Window wIDOwner, XStandardColormap *pColorMap, XColor *pColor)
1809 {
1810 static const char szColorDialogRes[]=
1811  "BEGIN_DIALOG FONT:Variable HEIGHT:182 WIDTH:280 TITLE:\"Color Chooser\"\n"
1812 
1813  // these controls are first in the tab order
1814  " CONTROL:Image ID:1009 X:150 Y:120 WIDTH:50 HEIGHT:14 VISIBLE\n"
1815  " CONTROL:Text TITLE:\"Value:\" X:200 Y:122 WIDTH:24 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1816  " CONTROL:Edit ID:1010 X:228 Y:122 WIDTH:40 HEIGHT:10 VISIBLE\n"
1817 
1818  // then the buttons
1819  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:60 Y:160 WIDTH:40 HEIGHT:18 VISIBLE\n"
1820  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:180 Y:160 WIDTH:40 HEIGHT:18 VISIBLE\n"
1821 
1822  // then the images
1823  " CONTROL:Image ID:1001 X:2 Y:2 HEIGHT:132 WIDTH:132 VISIBLE CLICKABLE\n" // 128x128 image, luma/saturation
1824  " CONTROL:Image ID:1002 X:2 Y:136 HEIGHT:16 WIDTH:132 VISIBLE CLICKABLE\n" // 128x12 image, chroma
1825 
1826  // then the rest
1827  " CONTROL:Text TITLE:\"Lum:\" X:140 Y:22 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1828  " CONTROL:Edit ID:1003 X:164 Y:22 WIDTH:28 HEIGHT:10 VISIBLE\n"
1829  " CONTROL:Text TITLE:\"Chr:\" X:140 Y:44 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1830  " CONTROL:Edit ID:1004 X:164 Y:44 WIDTH:28 HEIGHT:10 VISIBLE\n"
1831  " CONTROL:Text TITLE:\"Sat:\" X:140 Y:66 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1832  " CONTROL:Edit ID:1005 X:164 Y:66 WIDTH:28 HEIGHT:10 VISIBLE\n"
1833 
1834  " CONTROL:Text TITLE:\"Red:\" X:210 Y:22 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1835  " CONTROL:Edit ID:1006 X:234 Y:22 WIDTH:28 HEIGHT:10 VISIBLE\n"
1836  " CONTROL:Text TITLE:\"Grn:\" X:210 Y:44 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1837  " CONTROL:Edit ID:1007 X:234 Y:44 WIDTH:28 HEIGHT:10 VISIBLE\n"
1838  " CONTROL:Text TITLE:\"Blu:\" X:210 Y:66 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1839  " CONTROL:Edit ID:1008 X:234 Y:66 WIDTH:28 HEIGHT:10 VISIBLE\n"
1840 
1841  "END_DIALOG\n";
1842 WBDialogWindow *pDlg;
1843 Display *pDisplay;
1844 struct _COLOR_DIALOG_ data;
1845 int iX, iY, iRval = IDCANCEL; // default return is 'cancel'
1846 Window wIDDlg;
1847 WB_GEOM geomParent;
1848 
1849 
1850  if(!pColor)
1851  {
1852  return -1; // not valid
1853  }
1854 
1855  if(wIDOwner)
1856  {
1857  pDisplay = WBGetWindowDisplay(wIDOwner);
1858  }
1859  else
1860  {
1861  pDisplay = WBGetDefaultDisplay();
1862  }
1863 
1864  memset(&data, 0, sizeof(data));
1865 
1866  if(WB_LIKELY(pColorMap)) // should always be the case
1867  {
1868  memcpy(&(data.stdColorMap), pColorMap, sizeof(data.stdColorMap));
1869  }
1870  else
1871  {
1872  WBDefaultStandardColormap(pDisplay, &(data.stdColorMap));
1873  }
1874 
1875  bzero(&geomParent, sizeof(geomParent));
1876 
1877  if(wIDOwner != None)
1878  {
1879  WBGetWindowGeom0(wIDOwner, &geomParent); // parent geometry in absolute coordinates
1880 
1881  iX = geomParent.x + geomParent.border + MESSAGE_BOX_OFFSET;
1882  iY = geomParent.y + geomParent.border + MESSAGE_BOX_OFFSET;
1883  }
1884  else
1885  {
1886  // center in screen with slight random offset (so that every window won't always appear in exactly the same place)
1887  iY = (DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
1888  - MESSAGE_BOX_HEIGHT + MESSAGE_BOX_OFFSET - (int)(WBGetTimeIndex() % (2 * MESSAGE_BOX_OFFSET)))
1889  / 2;
1890 
1891  iX = (DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()))
1892  - MESSAGE_BOX_WIDTH + MESSAGE_BOX_OFFSET - (int)((~WBGetTimeIndex()) % (2 * MESSAGE_BOX_OFFSET)))
1893  / 2;
1894  }
1895 
1896  data.pColor = pColor; // pixel value will become initial color
1897  data.pimgLumaSat = NULL;
1898  data.pimgChroma = NULL;
1899  data.pixmapLumaSat = None;
1900  data.pixmapChroma = None;
1901 
1902  data.lPixel = pColor->pixel; // cache it - the rest will take care of itself
1903 
1904  // now that all of THAT is done, do the dialog box
1905 
1906  pDlg = DLGCreateDialogWindow(wIDOwner, "Color Chooser",szColorDialogRes,
1907  100,100,300,100,ColorDialogCallback,
1908  WBDialogWindow_VISIBLE,&data);
1909 
1910  if(pDlg)
1911  {
1912  wIDDlg = pDlg->wID;
1913 
1914  iRval = WBShowModal(pDlg->wID, 0);
1915 
1916  if(iRval == IDOK)
1917  {
1918  // check pColor assigned via data.pColor?
1919  }
1920  }
1921 
1922  // free up any resources here
1923 
1924 
1925  return iRval;
1926 }
1927 
1928 
1929 
1931 // FONT DIALOG
1933 
1934 
1935 WB_FONT DLGFontDialog(Display *pDisplay, Window wIDOwner, WB_FONTC pDefault)
1936 {
1937  return None;
1938 }
1939 
1940 
1941 
1942 
1944 // SPLASH SCREEN
1946 
1947 
1948 // construct a splash screen based on the size of the pixmap and position
1949 // the copyright text in the lower 1/3 of the splash screen, centered, then
1950 // pass a 'diagonal flash' across it, and close the screen after a total of
1951 // 5 seconds, returning back to the application.
1952 
1953 typedef struct _SPLASH_
1954 {
1955  Pixmap pixmap, pixmap2;
1956  char *szCopyright;
1957  int iW, iH; // width/height of bitmap
1958  int iDepth; // depth, needed to create compatible pixmaps
1959  int nIter; // total # of iterations thus far
1960  WB_FONT pFont;//Struct *pFont;
1961  int nGleam; // current gleam center position
1962  WB_GEOM geomBorder;
1963  XStandardColormap cmap;
1964  XImage *pImage;
1965  void *pImageData;
1966  unsigned long cbImageData;
1967  unsigned long clrText, clrBlack, clrWhite; // pixel colors
1968 } SPLASH;
1969 
1970 static int splash_callback(Window wID, XEvent *pEvent);
1971 static int SplashDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
1972  Window wID, struct _SPLASH_ *pData);
1973 
1974 #define SPLASH_FRAMERATE 30 /* make this configurable? */
1975 #define SPLASH_TIME 1500 /* milliseconds */
1976 
1977 void DLGSplashScreen(char *aXPM[], const char *szCopyright, unsigned long clrText)
1978 {
1979 Window wID;//, wIDTemp;
1980 XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */
1981 int iX, iY, iW, iH;
1982 XSizeHints xsh; /* Size hints for window manager */
1983 XWMHints xwmh;
1984 XPM_ATTRIBUTES xattr;
1985 SPLASH data;
1986 Atom a1;
1987 unsigned int ai1[3];
1988 
1989 
1990  bzero(&data, sizeof(data));
1991  bzero(&xattr, sizeof(xattr));
1992 
1994  aXPM, &(data.pixmap), &(data.pixmap2), &xattr))
1995  {
1996  WB_ERROR_PRINT("XPM_CREATE_PIXMAP_FROM_DATA ERROR\n");
1997  return;
1998  }
1999 
2000  iW = xattr.width + 4; // border width is 2
2001  iH = xattr.height + 4; // border width is 2
2002  data.iDepth = xattr.depth;
2003  if(!data.iDepth)
2004  {
2005  data.iDepth = DefaultDepth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2006  }
2007 
2008  if(!iW || !iH || data.pixmap == None)
2009  {
2010  WB_ERROR_PRINT("%s - iW=%d, iH=%d, data.pixmap=%d (%08xH)\n",
2011  __FUNCTION__, iW, iH, (int)data.pixmap, (int)data.pixmap);
2012  return;
2013  }
2014 
2015 // WB_ERROR_PRINT("TEMPORARY %s - iW=%d, iH=%d, data.pixmap=%d (%08xH)\n",
2016 // __FUNCTION__, iW, iH, (int)data.pixmap, (int)data.pixmap);
2017 
2018  // TODO: choose font, calculate bounds of text area
2019  // save font/bounds data and/or combine text into pixmap with transparent background
2020 
2021 
2022  iX = DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2023  iY = DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2024 
2025  iX = (iX - iW) / 2;
2026  iY = (iY - iH) / 2; // centered
2027 
2028  data.szCopyright = WBCopyString(szCopyright);
2029  data.clrText = clrText;
2030  data.clrBlack = BlackPixel(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2031  data.clrWhite = WhitePixel(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2032  data.iW = xattr.width;
2033  data.iH = xattr.height;
2034  data.pFont = NULL; // must do this
2035  data.nGleam = 0;
2036  data.pImage = NULL;
2037  data.pImageData = NULL;
2038  data.cbImageData = 0;
2039 
2040  bzero(&xswa, sizeof(xswa));
2041 
2042  xswa.border_pixel = data.clrBlack;
2043  xswa.background_pixel = data.clrWhite;
2044  xswa.colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2045  xswa.bit_gravity = CenterGravity;
2046 
2047  wID = WBCreateWindow(WBGetDefaultDisplay(), None,//DefaultRootWindow(WBGetDefaultDisplay()),
2048  splash_callback, "Splash",
2049  iX, iY, iW, iH, 0,
2050  InputOutput,
2051  CWBorderPixel | CWBackPixel | CWColormap | CWBitGravity | CWOverrideRedirect,
2052  &xswa);
2053 
2054  if(wID <= 0)
2055  {
2056  return;
2057  }
2058 
2059  WBSetWindowData(wID, 0, (void *)&data);
2060  WBCreateWindowDefaultGC(wID, clrText, xswa.background_pixel);
2061 
2062  bzero(&xsh, sizeof(xsh));
2063 
2064  xsh.flags = (USPosition | USSize | PBaseSize | PMinSize | PMaxSize | PWinGravity);
2065  xsh.x = iX;
2066  xsh.y = iY;
2067  xsh.width = xsh.base_width = xsh.min_width = xsh.max_width = iW;
2068  xsh.height = xsh.base_height = xsh.min_height = xsh.max_height = iH;
2069  xsh.win_gravity = NorthWestGravity; // StaticGravity
2070 
2071  bzero(&xwmh, sizeof(xwmh));
2072  xwmh.flags = InputHint;
2073  xwmh.input = 0; // never take focus
2074 
2075  // set title, size hints, and 'WM_HINTS' hints (so WM knows where to put the window and how to set focus)
2076  WBSetWMProperties(wID, "splashwindow", &xsh, &xwmh, NULL);
2077 
2078  // before mapping the window, set some properties
2079  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_WINDOW_TYPE", False);
2080  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_WINDOW_TYPE_SPLASH", False);
2081  XChangeProperty(WBGetDefaultDisplay(), wID, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 1);
2082 
2083 
2084  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
2085  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_MODAL", False);
2086  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
2087  ai1[2] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
2088  XChangeProperty(WBGetDefaultDisplay(), wID, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 3);
2089 
2090  // must EXPLICITLY allow PAINTING (and other stuff) i.e. ExposureMask
2091  XSelectInput(WBGetDefaultDisplay(), wID, WB_STANDARD_INPUT_MASK);
2092 
2094 
2095  if(CreateTimer(WBGetDefaultDisplay(), wID, 1000000 / SPLASH_FRAMERATE, 1, 1)) // periodic timer at 'frame rate'
2096  {
2097  WBDestroyWindow(wID);
2098  }
2099  else
2100  {
2101  WBMapWindow(WBGetDefaultDisplay(), wID); // make window visible
2102 
2103  WBShowModal(wID, -1); // timer will cause window to go away automatically
2104  }
2105 
2106  if(data.szCopyright)
2107  {
2108  WBFree((void *)data.szCopyright);
2109  }
2110 
2111  if(data.pImageData)
2112  {
2113  WBFree(data.pImageData);
2114  }
2115 
2117  if(data.pImage)
2118  {
2119  WBXDestroyImage(data.pImage);
2120  }
2121 
2122  if(data.pixmap != None)
2123  {
2124  XFreePixmap(WBGetDefaultDisplay(), data.pixmap);
2125  data.pixmap = None;
2126  }
2127 
2128  if(data.pixmap2 != None)
2129  {
2130  XFreePixmap(WBGetDefaultDisplay(), data.pixmap2);
2131  data.pixmap2 = None;
2132  }
2133 
2134  if(data.pFont)
2135  {
2136  WBFreeFont(WBGetDefaultDisplay(), data.pFont);
2137  }
2139 }
2140 
2141 static int splash_callback(Window wID, XEvent *pEvent)
2142 {
2143 Display *pDisplay = WBGetWindowDisplay(wID);
2144 struct _SPLASH_ *pData = (struct _SPLASH_ *)WBGetWindowData(wID, 0);
2145 
2146 
2147  if(pData && pEvent->type == Expose)
2148  {
2149  return SplashDoExposeEvent((XExposeEvent *)pEvent, pDisplay, wID, pData);
2150  }
2151 
2152  if(pEvent->type == ClientMessage &&
2153  pEvent->xclient.message_type == aWB_TIMER)
2154  {
2155  if(!pData)
2156  {
2157  DeleteTimer(WBGetDefaultDisplay(), wID, 1);
2159  WBDestroyWindow(wID);
2160  return 1;
2161  }
2162 
2163  pData->nIter ++;
2164 
2165  if(pData->nIter * 1000 >= SPLASH_FRAMERATE * (SPLASH_TIME + 1000))
2166  {
2167  DeleteTimer(WBGetDefaultDisplay(), wID, 1);
2168  WBSetWindowData(wID, 0, NULL);
2169  WBDestroyWindow(wID);
2170  }
2171  else
2172  {
2173  WBInvalidateGeom(wID, NULL, 1);
2174  }
2175 
2176  return 1;
2177  }
2178 
2179  // special handling for 'destroy'
2180  if(pEvent->type == DestroyNotify &&
2181  pEvent->xdestroywindow.window == wID)
2182  {
2183  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2184  "%s - DestroyNotify\n", __FUNCTION__);
2185 
2186  WBSetWindowData(wID, 0, NULL);
2187 
2188  return 1;
2189  }
2190 
2191  return 0; // not handled
2192 }
2193 
2194 static int SplashDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
2195  Window wID, struct _SPLASH_ *pData)
2196 {
2197 WB_FONT pFont;
2198 WBGC gc;
2199 Pixmap pxTemp;
2200 XGCValues xgcv;
2201 WB_GEOM geomText;
2202 int iX, iY, iTimeStart, iTimeEnd;
2203 
2204 
2205  if(!pDisplay)
2206  {
2207  pDisplay = WBGetDefaultDisplay();
2208  }
2209 
2210 // gc = WBBeginPaint(wID, pEvent, &geomPaint); // gnome b0rks this - window has absolute coordinates!
2211 
2212  if(pData->pFont == NULL && pData->szCopyright && *(pData->szCopyright))
2213  {
2215  pData->szCopyright, &geomText);
2216 
2217  if(!pFont)
2218  {
2219  pFont = WBCopyFont(pDisplay, WBGetDefaultFont()); // makes a copy of the default font
2220  }
2221 
2222  pData->pFont = pFont; // owned by the object now, so don't free it
2223  }
2224  else
2225  {
2226  pFont = pData->pFont; // cache it for later
2227  }
2228 
2229  bzero(&xgcv, sizeof(xgcv));
2230 // if(pFont)
2231 // {
2232 // xgcv.font = pData->pFont->fid;
2233 // xgcv.fill_style = FillSolid;
2234 // }
2235  xgcv.foreground = pData->clrText;
2236  xgcv.background = pData->clrWhite;
2237  xgcv.line_width = 1;
2238  xgcv.function = GXcopy; // copy
2239  xgcv.cap_style = CapProjecting;
2240 
2241  gc = WBCreateGC(pDisplay, wID,
2242  (/*(xgcv.font ? GCFont | GCFillStyle : 0) | */GCForeground | GCBackground | GCCapStyle | GCFunction | GCLineWidth),
2243  &xgcv);
2244 
2245  if(!gc)
2246  {
2247  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2248  return 0;
2249  }
2250 
2251  // now we get to create a window-compatible pixmap compatible with the window size
2252  // NOTE: XListDepths and XDefaultDepth may be needed to convert pixmaps to something that's compatible
2253 
2254  WBGetWindowGeom(wID, &(pData->geomBorder));
2255  pData->geomBorder.x = pData->geomBorder.y = 0; // force this (for now, gnome has absolute coordinates for splash window!)
2256 
2257 // not currently being used - later if I need it, uncomment - gcc in linux barphs on unused assigned vars
2258 // xrct.x = pData->geomBorder.x;
2259 // xrct.y = pData->geomBorder.y;
2260 // xrct.width = pData->geomBorder.width;
2261 // xrct.height = pData->geomBorder.height;
2262 
2263 
2264  if(pData->pixmap2 != None) // first part was already done
2265  {
2266  pxTemp = pData->pixmap2;
2267  }
2268  else
2269  {
2271  pxTemp = XCreatePixmap(pDisplay, wID, pData->iW + 4, pData->iH + 4,
2272  DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
2274 
2275  if(pxTemp == None)
2276  {
2277  WB_ERROR_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2278 
2279  WBFreeGC(gc);
2280  return 0;
2281  }
2282 
2283  if(pData->pixmap != None) // just in case
2284  {
2286  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc->gc,
2287  0, 0, pData->iW, pData->iH,
2288  pData->geomBorder.x + 2, pData->geomBorder.y + 2);
2290  }
2291  else
2292  {
2293  // TODO: erase the background of the drawable, WBEraseBackground maybe?
2294  }
2295 
2296  // this fixes the border areas properly
2297 
2298  xgcv.line_width = 3;
2299  xgcv.function = GXcopy; // copy
2300  xgcv.cap_style = CapProjecting;
2301 
2302  WBChangeGC(gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2303 
2304  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, 0,0, pData->iW + 3, 0);
2305  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, pData->iW + 3, 0, pData->iW + 3, pData->iH + 3);
2306  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, pData->iW + 3, pData->iH + 3, 0, pData->iH + 3);
2307  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, 0, pData->iH + 3, 0, 0);
2308 
2309  pData->pixmap2 = pxTemp; // temporarily cache it here (I'll juggle it after allocating 2nd pixmap)
2310 
2311  // next, I must create a *new* temporary pixmap as my 'working' pixmap. the previous one is the 'reference' pixmap
2312 
2314  pxTemp = XCreatePixmap(pDisplay, wID, pData->iW + 4, pData->iH + 4,
2315  DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
2317 
2318  if(pxTemp == None)
2319  {
2320  WB_ERROR_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2321 
2323  XFreePixmap(WBGetDefaultDisplay(), pData->pixmap2); // restartability
2325  pData->pixmap2 = None;
2326 
2327  WBFreeGC(gc);
2328  return 0;
2329  }
2330 
2331  if(pData->pixmap != None) // just in case, test for it
2332  {
2333  XFreePixmap(WBGetDefaultDisplay(), pData->pixmap);
2334  }
2335 
2336  pData->pixmap = pData->pixmap2; // NOW, ref pixmap (with image and border) goes into 'pixmap'
2337  pData->pixmap2 = pxTemp; // and the 'working' copy into 'pixmap2' (which is also 'pxTemp')
2338 
2339  // make an exact duplicate without any clipping regions
2341  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc->gc,
2342  0, 0, pData->iW + 4, pData->iH + 4, 0, 0); // make a good copy of it at least once
2344  }
2345 
2346  if(pData->nIter <= 1)
2347  {
2348 // TODO: verify this is still a problem
2349 // WBClearWindow(wID, gc); WBGC doesn't have a clip region yet, don't do this
2350 
2352  XClearWindow(pDisplay, wID); // erase background
2354  }
2355  else if(pData->nIter == SPLASH_FRAMERATE / 2) // after first half second
2356  {
2357  geomText.x = pData->geomBorder.x + 2;
2358  geomText.y = pData->geomBorder.y + 2;
2359  geomText.width = pData->geomBorder.width - 4;
2360  geomText.height = pData->geomBorder.height - 4;
2361 
2362  geomText.y += (geomText.height * 2) / 3;
2363  geomText.height -= (geomText.height * 2) / 3; // bottom 1/3
2364 
2365  // copyright string is 1 or 2 lines, for now use whatever font I end up with and draw lines separately
2366 
2367  if(pFont)
2368  {
2369  WB_RECT rctBounds;
2370  rctBounds.left = geomText.x;
2371  rctBounds.top = geomText.y;
2372  rctBounds.right = rctBounds.left + geomText.width;
2373  rctBounds.bottom = rctBounds.top + geomText.height;
2374 
2375  DTDrawMultiLineText(pFont, pData->szCopyright, pDisplay, gc, pData->pixmap,
2376  -8, 0, &rctBounds, DTAlignment_VCENTER | DTAlignment_HCENTER);
2377 #if 0
2378  p1 = pData->szCopyright;
2379  p2 = strchr(p1, '\n');
2380 
2381  if(p2)
2382  {
2383  *(p2++) = 0;
2384  }
2385 
2386  if(!p2 || !*p2)
2387  {
2388  iX = geomText.x + (geomText.width - XTextWidth(pFont, p1, strlen(p1))) / 2;
2389  iY = geomText.y + (geomText.height - WBFontAscent(pFont) + WBFontDescent(pFont) / 2
2390  + WBFontAscent(pFont); // bottom of text
2391 
2392  WBDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p1, strlen(p1));
2393  }
2394  else
2395  {
2396  iX = geomText.x + (geomText.width - XTextWidth(pFont, p1, strlen(p1))) / 2;
2397  iY = geomText.y + (geomText.height - 2 * WBFontHeight(pFont)) / 2
2398  + WBFontAscent(pFont); // bottom of text
2399 
2400  WBDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p1, strlen(p1));
2401 
2402  iX = geomText.x + (geomText.width - XTextWidth(pFont, p2, strlen(p2))) / 2;
2403  iY += WBFontHeight(pFont);
2404 
2405  WBDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p2, strlen(p2));
2406  }
2407 
2408  if(p2)
2409  {
2410  *(p2 - 1) = '\n'; // restore it for next time
2411  }
2412 #endif // 0
2413  }
2414  else
2415  {
2416  fprintf(stderr, "NO FONT, iter=%d\n", pData->nIter);
2417  }
2418 
2419  // make an exact duplicate without any clipping regions
2420 
2422  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc->gc,
2423  0, 0, pData->iW + 4, pData->iH + 4, 0, 0);
2425 
2426  // now, grab an XImage for it
2427 
2428  pData->pImage = WBXGetImage(pDisplay, pxTemp, 0, 0, pData->iW + 4, pData->iH + 4,
2429  0xffffffff, XYPixmap);
2430  }
2431 
2432  // TODO: consider creating clip regions to improve performance
2433 
2434  if(pData->nIter >= SPLASH_FRAMERATE / 2) // after first half second
2435  {
2436  iTimeStart = 1250 * SPLASH_FRAMERATE; // 1.5 seconds' worth in msecs, not seconds
2437  iTimeEnd = (SPLASH_TIME + 1000) * SPLASH_FRAMERATE
2438  - 500 * SPLASH_FRAMERATE; // 1/2 sec before end
2439 
2440  if(iTimeStart + 1000 * SPLASH_FRAMERATE / 2 > iTimeEnd)
2441  {
2442  iTimeStart = iTimeEnd - SPLASH_FRAMERATE / 2;
2443  }
2444 
2445  // drawing the 'gleam' diagonally from upper left to lower right
2446  // TODO: make this optional?
2447 
2448  if(pData->nIter * 1000 > iTimeEnd)
2449  {
2450  if(pData->pImage)
2451  {
2452  WBXPutImage(pDisplay, pData->pixmap2, gc, pData->pImage, 0, 0, 0, 0, pData->iW + 4, pData->iH + 4);
2453 
2454  WBXDestroyImage(pData->pImage); // destroy it now that I'm done with it
2455  pData->pImage = NULL; // no longer stored (already cleaned up)
2456  }
2457  }
2458  else if(pData->nIter * 1000 >= iTimeStart && pData->nIter * 1000 <= iTimeEnd)
2459  {
2460  int iDelta = iTimeEnd - iTimeStart + 1;
2461  int iTemp;
2462  XImage *pI; // the image I'll be manipulating
2463 
2464  iTemp = pData->nIter * 1000L - iTimeStart;
2465  iTemp = (int)(((long long)iTemp * (long long)iTemp) / (iTimeEnd - iTimeStart));
2466 
2467  // get the starting points and end points
2468  iX = 2 * (pData->iW * iTemp / iDelta + pData->iW / (2 * iDelta) / 1000); // x pos of top
2469  iY = 2 * (pData->iH * iTemp / iDelta + pData->iH / (2 * iDelta) / 1000); // y pos of left
2470 
2471  // will draw the line from 0,iY to iX,0
2472 
2473  if(!pData->pImage)
2474  {
2475  pData->pImage = WBXGetImage(pDisplay, pData->pixmap2, 0, 0, pData->iW + 4, pData->iH + 4,
2476  0xffffffff, // I've tried 0, 1, and THIS value - no apparent difference
2477  XYPixmap); // TODO: use ZPixmap instead?
2478  }
2479 
2480  pI = pData->pImage;
2481 
2482  if(pI && !pData->pImageData)
2483  {
2484  // this formula can be found in the xorg-server source:
2485  // length = ximage->bytes_per_line * ximage->height;
2486  // this is from 'xnestGetImage' in hw/xnest/GCOps.c
2487  // note that they don't include 'depth' in that. when I exclude 'depth', it doesn't work
2488  // TODO: do I need to pay attention to PADDING? docs and source suggest 'no'
2489 
2490 // WB_ERROR_PRINT("TEMPORARY: %s - bytes_per_line=%d, height=%d, depth=%d\n", __FUNCTION__,
2491 // pI->bytes_per_line, pI->height, pI->depth);
2492 
2493  pData->cbImageData = PXM_GetImageDataLength(pI);
2494  pData->pImageData = WBAlloc(pData->cbImageData + 4);
2495 
2496  if(pData->pImageData)
2497  {
2498  memcpy(pData->pImageData, PXM_GetImageDataPtr(pI), pData->cbImageData);
2499  }
2500  }
2501 
2502  if(!pI)
2503  {
2504  // don't do anything
2505  }
2506  else
2507  {
2508 #if defined(GLEAM_OLD)
2509 #define GLEAM_WIDTH 10
2510  static int aLuma[GLEAM_WIDTH + 1] = { 255, 249, 231, 202, 167, 128, 88, 53, 24, 6, 0 }; // 'luma' values for "the gleam" based on offset from center
2511 #elif defined(GLEAM_NARROW)
2512 #define GLEAM_WIDTH 17
2513  static int aLuma[GLEAM_WIDTH + 1] = { 255, 202, 161, 128, 101, 80, 64, 51, 40,
2514  32, 25, 20, 16, 13, 10, 8, 6, 5 }; // similar but 1/r^2 version (no cos)
2515 #else // WIDE gleam
2516 #define GLEAM_WIDTH 29
2517  static int aLuma[GLEAM_WIDTH + 1] = { 255,225,198,175,154,136,120,106,93,82,72,64,
2518  56,50,44,39,34,30,26,23,21,18,16,14,12,11,10,8,7,7 }; // a bit wider, more obvious
2519 #endif // GLEAM_OLD, GLEAM_NARROW
2520 
2521  int iX0, iY0, iX1, i1, i2, iW, iL, iMaxX, iMaxY;
2522 
2523  // NOW I get the fun of directly manipulating my image. W00T!
2524 
2525  // effectively I do this: WBDrawLine(pDisplay, pxTemp, gc, -2, iY, iX, -2) and it's 19 pixels wide
2526 
2527  // So the line has a width of '2*GLEAM_WIDTH + 1' pixels. The pixels represent a white reflection
2528  // centering at the coordinates I specified above, that is the line from -2, iY to iX, -2 . This
2529  // actually SHOULD be offset by 2 pixels so that it does not affect the border, but that's less iomportant
2530 
2531  // draw the line. 19 pixels wide is actually +/- 9. We start with a single pixel-width line, then
2532  // do a for loop from/to +/- GLEAM_WIDTH on the X axis, keeping Y constant. if Y did not change, skip it.
2533 
2534  iMaxX = pData->iW;
2535  iMaxY = pData->iH;
2536 
2537  for(iX0 = -GLEAM_WIDTH, iY0 = iY + GLEAM_WIDTH; iX0 < iMaxX + GLEAM_WIDTH && iY0 > -GLEAM_WIDTH; iX0++)
2538  {
2539  i1 = (int)(((iX - iX0) * (long long)iMaxY) / iMaxX); // a muldiv conversion (where I should be)
2540 
2541  if(iY0 > i1) // so I don't repeat what I've done
2542  {
2543  for(; iY0 > i1; iY0--) // remember, top < bottom so if I start at the bottom, must SUBTRACT
2544  {
2545  // +/- GLEAM_WIDTH pixels
2546  i2 = iX0 + GLEAM_WIDTH;
2547  for(iX1=iX0 - GLEAM_WIDTH, iW = -GLEAM_WIDTH; iX1 <= i2; iX1++, iW++)
2548  {
2549  // is my current iX1, iY0 inside the desired rectangle? If so, calculate the
2550  // new color and assign it to this point.
2551 
2552  if(iX1 > 2 && iX1 < iMaxX &&
2553  iY0 > 2 && iY0 < iMaxY)
2554  {
2555  XColor clrTemp, clrPixel;
2556  int iY, iU, iV, iR, iG, iB;
2557 
2558  clrPixel.pixel = XGetPixel(pI, iX1 + 2, iY0 + 2);
2559  PXM_PixelToRGB(&(pData->cmap), &clrPixel);
2560 
2561  PXM_RGBToYUV(clrPixel.red >> 8, clrPixel.green >> 8, clrPixel.blue >> 8,
2562  &iY, &iU, &iV);
2563 
2564  iL = aLuma[abs(iW)]; // the 'Luma' constant, 0-255 (with 255 = 'white')
2565 
2566  // new pixel luma will be: luma * (1 + iL / 128) (maxed at 255)
2567  // if new luma is > 255, reduce iU and iV (delta from 128) by the 'factor'
2568  // such that iU = 128 + (iU - 128) * factor [etc.]
2569  // and the 'factor' would be 255 / iU (the new value)
2570 
2571  iY = ((short)iY * ((short)256 + (short)iL)) / (short)256; // >> 6;/// (short)128;
2572 
2573  if(iY > 255)
2574  {
2575  iU = (short)128 + (((short)iU - (short)128) * (short)256) / (short)iY;
2576  iV = (short)128 + (((short)iV - (short)128) * (short)256) / (short)iY;
2577  iY = 255;
2578  }
2579 
2580  PXM_YUVToRGB(iY, iU, iV, &iR, &iG, &iB);
2581 
2582  clrTemp.red = iR << 8;
2583  clrTemp.green = iG << 8;
2584  clrTemp.blue = iB << 8;
2585  clrTemp.flags = DoRed | DoGreen | DoBlue;
2586 
2587  PXM_RGBToPixel(&(pData->cmap), &clrTemp);
2588 
2589  XPutPixel(pI, iX1 + 2, iY0 + 2, clrTemp.pixel);
2590  }
2591  }
2592  }
2593  }
2594  }
2595 
2596  // TODO: assign clipping region to gc
2597 
2598 // llTick -= WBGetTimeIndex();
2599 
2600  WBXPutImage(pDisplay, pData->pixmap2, gc, pI, 0, 0, 0, 0, pData->iW + 4, pData->iH + 4);
2601 
2603  XFlush(pDisplay); // make sure
2605 
2606 // llTick += WBGetTimeIndex();
2607 
2608  if(pData->pImageData)
2609  {
2610  // restore previous image data now that I'm done messing with it
2611  memcpy(PXM_GetImageDataPtr(pI), pData->pImageData, pData->cbImageData); // restore previous image data
2612  }
2613  else
2614  {
2615  WBXDestroyImage(pI);
2616  pData->pImage = NULL; // no longer stored (a fallback)
2617  }
2618 
2619 // WB_ERROR_PRINT("TEMPORARY: %s - pixel stuff takes %llu millis\n", __FUNCTION__, llTick);
2620  }
2621 
2622 #if 0
2623  // using some interesting raster ops, 'highlight' the pixels along the line of
2624  // (0,iY),(iX,0) or (iX,pData->iH-1),(pData->iW-1,iY)
2625 
2626  XSetForeground(pDisplay, gc, pData->clrWhite & 0x404040);
2627 
2628  xgcv.line_width = 19;
2629  xgcv.function = GXor; // a or b
2630  xgcv.cap_style = CapProjecting;
2631 
2632  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2633 
2634  if(!bInvert)
2635  {
2636  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2637  }
2638  else
2639  {
2640  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2641  }
2642 
2643  XSetForeground(pDisplay, gc, pData->clrWhite & 0x808080);
2644 
2645  xgcv.line_width = 11;
2646  xgcv.function = GXor; // a or b
2647  xgcv.cap_style = CapProjecting;
2648 
2649  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2650 
2651  if(!bInvert)
2652  {
2653  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2654  }
2655  else
2656  {
2657  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2658  }
2659 
2660  XSetForeground(pDisplay, gc, pData->clrWhite & 0xc0c0c0);
2661 
2662  xgcv.line_width = 5;
2663  xgcv.function = GXor; // a or b
2664  xgcv.cap_style = CapProjecting;
2665 
2666  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2667 
2668  if(!bInvert)
2669  {
2670  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2671  }
2672  else
2673  {
2674  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2675  }
2676 
2677  XSetForeground(pDisplay, gc, pData->clrWhite);
2678 
2679  xgcv.line_width = 1;
2680  xgcv.function = GXcopy; // copy
2681  xgcv.cap_style = CapProjecting;
2682 
2683  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2684 
2685  if(!bInvert)
2686  {
2687  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2688  }
2689  else
2690  {
2691  WBDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2692  }
2693 #endif // 0
2694  }
2695  }
2696 
2697  if(pxTemp) // using the 2nd pixmap to do the work, thus making the whole screen update at once
2698  {
2699  XCopyArea(pDisplay, pxTemp, wID, gc->gc, 0, 0, pData->iW + 4, pData->iH + 4, pData->geomBorder.x, pData->geomBorder.y);
2700  }
2701 
2702  WBFreeGC(gc);
2703 
2705  XSync(pDisplay, 0); // force update NOW
2707  WBValidateGeom(wID, NULL);
2708 // WBEndPaint(wID, gc);
2709 
2710  return 1; // processed
2711 }
2712 
2713 
GC gc
the associated 'GC'
Icon - multiple question marks in red triangle.
#define WB_LIKELY(x)
optimization for code branching when condition is 'likely'. use within conditionals
#define IDOK
Atom aLOSTFOCUS
CONTROL_NOTIFY ClientMessage for LOSTFOCUS event.
void WBSetWMProperties(Window wID, const char *szTitle, XSizeHints *pNormalHints, XWMHints *pWMHints, XClassHint *pClassHints)
assign standard WM (Window Manager) properties via XSetWMProperties
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.
int WBChangeGC(WBGC hGC, unsigned long valuemask, const XGCValues *values)
Change a WBGC, a wrapper for XChangeGC()
'window helper' main header file for the X11workbench Toolkit API
#define WB_LIST_SELCHANGE
static __inline__ const char * DLGGetControlProperty(WBDialogWindow *pDialog, int iControlID, Atom aPropName)
Convenience function to query a text property for a dialog control based on its control ID.
Atom aGOTFOCUS
CONTROL_NOTIFY ClientMessage for GOTFOCUS event.
int WBDrawLine(Display *display, Drawable d, WBGC gc, int x1, int y1, int x2, int y2)
Wrapper for XDrawLines()
static __inline__ unsigned long PXM_GetImageDataLength(XImage *pImage)
Returns the length of XImage data.
void WBFreeFont(Display *pDisplay, WB_FONT pFont)
free a WB_FONT that was created using one of the WBFont APIs
Definition: font_helper.c:250
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:364
void * WBGetWindowData(Window wID, int iIndex)
Gets the data associated with this window and the specified index.
int WBFontHeight(WB_FONTC pFont0)
Get the maximum character height from a WB_FONT.
Definition: font_helper.c:546
int WBFontAscent(WB_FONTC pFont0)
Get the maximum character ascent from a WB_FONT.
Definition: font_helper.c:495
void WBDefaultStandardColormap(Display *pDisplay, XStandardColormap *pMap)
returns a default XStandardColormap structure for the default screen of the specified display
Utilities for copying and drawing text, determining text extents, and so on.
Icon - black question mark in yellow triangle.
int WBUnmapWindow(Display *pDisplay, Window wID)
wrapper for XUnmapWindow, makes window invisible without destroying it
Icon - white skull and crossbones on black square.
static __inline__ void DLGNotifyDlg(WBDialogWindow *pDLG, Atom aNotify, long lData0, long lData1, long lData2, long lData3, long lData4)
Notify dialog window by calling the window's own callback function directly with an event.
Icon - white question mark in green triangle.
Atom aMOUSE_DBLCLICK
CONTROL_NOTIFY ClientMessage for MOUSE_DBLCLICK event.
void WBCreateWindowDefaultGC(Window wID, unsigned long clrFG, unsigned long clrBG)
creates a default WBGC for a window
static __inline__ WBDialogControl * DLGGetDialogControlStructFromID(WBDialogWindow *pDialog, int iControlID)
Returns a pointer to the WBDialogControl structure for a dialog control with validation....
Button Bits - Cancel button.
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.
Atom aLIST_NOTIFY
CONTROL_NOTIFY ClientMessage for LIST_NOTIFY event.
WB_FONT WBCopyFont(Display *pDisplay, WB_FONTC pOldFont)
make a copy of an existing font (best when assigning to a window)
Definition: font_helper.c:168
int WBShowModal(Window wID, int bMenuSplashFlag)
Shows a 'modal' window by processing events until the window closes.
int DLGColorDialog(Window wIDOwner, XStandardColormap *pColorMap, XColor *pColor)
Display a modal Color Dialog window, returning the selected color in the XColor structure pointed to ...
Definition: dialog_impl.c:1808
void WBGetWindowGeom0(Window wID, WB_GEOM *pGeom)
Returns the ABSOLUTE window geometry relative to the screen.
char * DLGInputBox(Window wIDOwner, const char *szTitle, const char *szPrompt, const char *szDefault, int iWidth, int iMaxChar)
Displays a special purpose dialog window that retrieves a character string as input.
Definition: dialog_impl.c:541
unsigned int border
Icon - white asterisk on blue circle.
unsigned int width
Compatibility structure for use with MyLoadPixmapFromData() whenever libXpm is not in use.
Atom aDLGC_PATH
dialog control PATH property, for file and directory controls
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.
Icon - yellow triangle (nothing else)
WB_FONT DTCalcIdealFont(Display *pDisplay, WB_FONTC pRefFont, const char *szText, WB_GEOM *geomBounds)
Calculate the ideal font based on the text and rectangle.
Definition: draw_text.c:277
Button Bits - No button.
horizontally centered text. tabs are treated as white space
Definition: draw_text.h:78
void * pUserData
user data that's assignable via API
Button Bits - OK button.
mask for button bits
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
internal wrapper struct for X11 'geometry' definition
'configuration helper' main header file for the X11 Work Bench Toolkit API
void PXM_RGBToPixel(XStandardColormap *pMap, XColor *pColor)
Icon Registration for application 'large' and 'small' icons.
#define RGB255_TO_XCOLOR(R, G, B, X)
Simple RGB assignment to pixel, 0-255 RGB.
Definition: pixmap_helper.h:94
int width
The width of the returned pixmaps.
static __inline__ void DLGSetControlCaption(WBDialogWindow *pDialog, int iControlID, const char *szCaption)
Convenience function to assign a dialog control's caption based on its control ID.
Button Bits - Yes button.
void PXM_PixelToRGB(XStandardColormap *pMap, XColor *pColor)
Convert the pixel menber of an XColor to RGB.
Atom aDIALOG_INIT
DIALOG_INIT ClientMessage, sent to dialog window callback on frame create.
int WBDrawString(Display *display, Drawable d, WBGC gc, int x, int y, const char *string, int length)
wrapper for XDrawString()
Icon - white fright mask on black circle.
Icon - green circle.
WBDialogWindow * DLGCreateDialogWindow(Window wIDOwner, const char *szTitle, const char *szDialogResource, int iX, int iY, int iWidth, int iHeight, WBWinEvent pUserCallback, int iFlags, void *pUserData)
create a dialog window using a text resource
Atom aMOUSE_CLICK
CONTROL_NOTIFY ClientMessage for MOUSE_CLICK event.
Structure identifying a dialog (frame) window.
static __inline__ int DLGSetControlProperty(WBDialogWindow *pDialog, int iControlID, Atom aPropName, const char *szPropVal)
Convenience function to assign a text property for a dialog control based on its control ID.
Icon - red stop sign.
Icon - white thumb up on green square.
mask for icon bits
void DeleteTimer(Display *pDisplay, Window wID, long lID)
Deletes an existing timer's resources.
WB_UINT64 WBGetTimeIndex(void)
Returns the current 'time index' (in microseconds)
#define RGB255_FROM_XCOLOR(X, R, G, B)
Simple RGB assignment from pixel, 0-255 RGB.
void WBInvalidateGeom(Window wID, const WB_GEOM *pGeom, int bPaintNow)
'Paint' helper, invalidates a geometry for asynchronous Expose event generation
#define DIALOG_WINDOW_TAG
Icon - white 'middle finger' on red triangle.
void WBDialogControlSetIconPixmap(WBDialogControl *pCtrl, Pixmap pixmap, Pixmap pixmap2)
Assign the ICON (image) property for a control, which consists of 2 pixmaps.
static __inline__ void WBDialogControlInvalidateGeom(WBDialogControl *pDialogControl, const WB_GEOM *pGeom, int bPaintFlag)
Convenience function, invalidates a Geom for a dialog box control.
static __inline__ void DLGNotifyDlgAsync(WBDialogWindow *pDLG, Atom aNotify, long lData0, long lData1, long lData2, long lData3, long lData4)
Notify dialog window by posting an event that will ASYNCHRONOUSLY be sent to the dialog window's call...
center using entire text height (ascent + descent for single line)
Definition: draw_text.h:86
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)
Window DLGGetDialogControl(WBDialogWindow *pDialog, int iControlID)
returns the Window ID of a member control of the dialog window using the 'control ID'
static __inline__ void * PXM_GetImageDataPtr(XImage *pImage)
Returns pointer to XImage data.
void WBValidateGeom(Window wID, const WB_GEOM *pGeom)
'Paint' helper, validates a geometry for asynchronous Expose event generation
void DLGSplashScreen(char *aXPM[], const char *szCopyright, unsigned long clrText)
Display a splash screen for 5 seconds (with animation and copyright string), and then return.
Definition: dialog_impl.c:1977
#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 WBIsDirectory(const char *szFileName)
Return whether a file is a directory or a symlink to a directory.
Definition: file_help.c:776
void WBFree(void *pBuf)
High performance memory sub-allocator 'free'.
Window wID
Window ID of the dialog control window.
#define IDCANCEL
void WBDestroyWindow(Window wID)
Destroy a window.
Button Bits - Retry button.
WBGC WBCreateGC(Display *pDisplay, Drawable dw, unsigned long valuemask, const XGCValues *values)
Creates a WBGC, wrapper for XCreateGC()
Icon - brown and tan teddy bear on grey circle.
static __inline__ int WBDialogControlGetCaptionInt(WBDialogControl *pCtrl)
Returns an integer from the text of the 'CAPTION' property of a dialog control.
void WBSetWindowIcon(Window wID, int idIcon)
assigns an icon resource (by ID) to a window
Window WBCreateWindow(Display *pDisplay, Window wIDParent, WBWinEvent pProc, const char *szClass, int iX, int iY, int iWidth, int iHeight, int iBorder, int iIO, WB_UINT64 iFlags, XSetWindowAttributes *pXSWA)
Create a window.
#define WB_STANDARD_INPUT_MASK
'Standard' input mask, bit flag for window creation
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 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.
static __inline__ const char * DLGGetControlCaption(WBDialogWindow *pDialog, int iControlID)
Convenience function to query a dialog control's caption based on its control ID.
int WBXDestroyImage(XImage *pImage)
Destroy an XImage - call this instead of XDestroyImage()
Atom aMOUSE_DRAG
CONTROL_NOTIFY ClientMessage for MOUSE_DRAG event.
unsigned int height
const char * WBDialogControlGetCaption(WBDialogControl *pCtrl)
Obtain a pointer to the assigned text for the 'CAPTION' property of a dialog control.
internal wrapper struct for 'rectangle' definition
Icon - purple T-Rex head on white circle (more like mozilla)
int WBFontDescent(WB_FONTC pFont0)
Get the maximum character descent from a WB_FONT.
Definition: font_helper.c:443
#define WB_LIST_DBLCLICK
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
Atom aCONTROL_NOTIFY
dialog control and child window notification messages
void WBFreeGC(WBGC hGC)
Free resources for a WBGC, wrapper for XFreeGC()
Button Bits - Ignore button.
static __inline__ WBDialogWindow * DLGGetDialogWindowStruct(Window wID)
Returns a pointer to the dialog window's WBDialogWindow structure.
WB_FONT DLGFontDialog(Display *pDisplay, Window wIDOwner, WB_FONTC pDefault)
Display a modal Font Dialog window, returning the selected font in the XColor structure pointed to by...
Definition: dialog_impl.c:1935
void WBSetWindowData(Window wID, int iIndex, void *pData)
assign 'data pointer' for a window and specified index value
static __inline__ void WBDialogControlSetCaptionLong(WBDialogControl *pCtrl, long lValue, const char *szFormat)
Assign a long integer as text to the 'CAPTION' property of a dialog control.
int depth
depth of the returned 'image' pixmap. The mask pixmap always has a depth of '1'.
char * WBGetCanonicalPath(const char *szFileName)
Return the canonical path for a file name (similar to POSIX 'realpath()' funtion)
Definition: file_help.c:803
#define BEGIN_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro precedes the call(s)
#define WB_UNUSED
marks a variable as likely to be 'unused'. warning abatement. Place macro directly after the variable...
int WBFillRectangle(Display *display, Drawable d, WBGC gc, int x, int y, unsigned int width, unsigned int height)
Wrapper for XFillRectangle()
Icon - application icon (from icon_app.xpm)
void WBGetWindowGeom(Window wID, WB_GEOM *pGeom)
Returns the RAW geometry of the window as reported by the window manager.
char * WBGetAtomName(Display *pDisplay, Atom aAtom)
Lookup and/or allocate an internal Atom for a named string.
Atom aBUTTON_PRESS
CONTROL_NOTIFY ClientMessage for BUTTON_PRESS event.
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
Icon - exclamation point on yellow triangle.
Atom aWB_TIMER
timer notifications generated by API
void DTDrawMultiLineText(WB_FONTC pFont, const char *szText, Display *pDisplay, WBGC gc, Drawable dw, int iTabWidth, int iTabOrigin, const WB_RECT *prcBounds, int iAlignment)
draw multi-line text
Definition: draw_text.c:1538
Visibility flag.
An allocated structure containing XFontStruct, XFontInfo, and XftFont [as applicable] for a specified...
Definition: font_helper.h:152
char * DLGFileDialog(int iType, Window wIDOwner, const char *szDefPath, const char *szDefName, const char *szExtAndDescList)
Display a modal File Dialog window, returning a WBAlloc'd pointer to a null-byte terminated string co...
Definition: dialog_impl.c:957
int CreateTimer(Display *pDisplay, Window wID, unsigned long lInterval, long lID, int iPeriodic)
Creates a one-shot or periodic timer.
void WBEndModal(Window wID, int iRval)
End a modal window with a specific return value.
char * WBCopyString(const char *pSrc)
A simple utility that returns a WBAlloc() copy of a 0-byte terminated string.
#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
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.
Icon - white thumb down on red square.
int WBMapWindow(Display *pDisplay, Window wID)
Wrapper for XMapWindow, makes window visible.
Window wID
window ID of the dialog (frame) window
Button Bits - Abort button.
void WBDialogControlSetPixmap(WBDialogControl *pCtrl, Pixmap pixmap)
Assign the PIXMAP (image) property for a control.
static __inline__ WBDialogControl * WBGetDialogEntryControlStruct(WBDialogWindow *pDialog, int iControlID)
Returns a pointer to the WBDialogControl structure for a dialog control based on its ID and containin...
const char * DLGGetControlListText(WBDialogControl *pCtrl, int iIndex)
Retrieve the text poiner for a single list entry (listbox, combo, and tree controls only)
static __inline__ void WBDialogControlSetCaptionInt(WBDialogControl *pCtrl, int iValue, const char *szFormat)
Assign an integer as text to the 'CAPTION' property of a dialog control.
int height
height of the returned pixmaps
#define WB_WARN_PRINT(...)
Preferred method of implementing a 'warning level' debug message for all subsystems.
Definition: debug_helper.h:467
static __inline__ WBDialogControl * DLGGetDialogControlStruct(Window wID)
Returns a pointer to the WBDialogControl structure for a dialog control with validation....
Structure identifying the properties of a dialog box control.
Icon - yellow circle with white exclamation point.
int DLGMessageBox(int iType, Window wIDOwner, const char *szTitle, const char *szMessage)
Display a modal 'message box' dialog window with a specific title, message, and button combination.
Definition: dialog_impl.c:231
void WBCatString(char **ppDest, const char *pSrc)
A simple utility that concatenates a string onto the end of a 0-byte terminated WBAlloc() string.
WB_FONTC WBGetDefaultFont(void)
Returns a pointer to the default font WB_FONT for the default display. This is a shared resource; do ...