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-2018 by Bob Frazier (aka 'Big Bad Bombastic Bob')
17  all rights reserved
18 
19  DISCLAIMER: The X11workbench application and toolkit software are supplied
20  'as-is', with no warranties, either implied or explicit.
21  Any claims to alleged functionality or features should be
22  considered 'preliminary', and might not function as advertised.
23 
24  BSD-like license:
25 
26  There is no restriction as to what you can do with this software, so long
27  as you include the above copyright notice and DISCLAIMER for any distributed
28  work that is equal to or derived from this one, along with this paragraph
29  that explains the terms of the license if the source is also being made
30  available. A "derived work" describes a work that uses a significant portion
31  of the source files or algorithms that are included with this one.
32  Specifically excluded from this are files that were generated by the software,
33  or anything that is included with the software that is part of another package
34  (such as files that were created or added during the 'configure' process).
35  Specifically included is the use of part or all of any of the X11 workbench
36  toolkit source or header files in your distributed application. If you do not
37  ship the source, the above copyright statement is still required to be placed
38  in a reasonably prominent place, such as documentation, splash screens, and/or
39  'about the application' dialog boxes.
40 
41  Use and distribution are in accordance with GPL, LGPL, and/or the above
42  BSD-like license. See COPYING and README files for more information.
43 
44 
45  Additional information at http://sourceforge.net/projects/X11workbench
46 
47 ******************************************************************************/
48 
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 // WB_ERROR_PRINT("TEMPORARY: %s - calling DLGCreateDialogWindow\n", __FUNCTION__);
418 
419  pDlg = DLGCreateDialogWindow(szTitle,pRes, iX, iY,
420  MESSAGE_BOX_WIDTH,
421  MESSAGE_BOX_HEIGHT, // TODO: derive from ???
422  MessageBoxCallback,
423  WBDialogWindow_VISIBLE, &mbox);
424 
425  if(pDlg) // TODO: manage this stuff as part of 'DLGCreateDialogWindow' instead
426  {
427  wIDDlg = pDlg->wID;
428 
429  if(wIDOwner != None)
430  {
431  Atom a1;
432  unsigned int ai1[3];
433 
434  DLGAssignOwner(pDlg, wIDOwner);
435 
436  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
437  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
438  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
439 
440  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 2);
441 
442  a1 = XInternAtom(WBGetWindowDisplay(wIDDlg), "WM_TRANSIENT_FOR", False);
443  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wIDOwner, 1);
444  }
445 
446  WBSetWindowIcon(wIDDlg, GetMessageBoxIconPixmapID(iType & MessageBox_ICON_MASK));
447 
448 // WB_ERROR_PRINT("TEMPORARY: %s - calling WBShowModal\n", __FUNCTION__);
449 
450  iRval = WBShowModal(wIDDlg, 0);
451 
452  return iRval;
453  }
454 
455  return -1; // by default return -1 on error
456 }
457 
458 
460 // INPUT BOX
462 
463 struct _INPUT_BOX_
464 {
465  const char *szTitle;
466  const char *szMessage;
467  char *szRval;
468 };
469 
470 
471 static int InputBoxCallback(Window wID, XEvent *pEvent)
472 {
474 struct _INPUT_BOX_ *pUserData = (struct _INPUT_BOX_ *)(pDlg ? pDlg->pUserData : NULL);
475 
476 
477  if(!pDlg)
478  return 0; // can't process any messages now
479 
480  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
481  {
482  // assigning the correct icon
483  {
484  WBDialogControl *pCtrl = DLGGetDialogControlStructFromID(pDlg, 1000); // ID 1000 for icon
485 
486  if(pCtrl)
487  {
488  Pixmap pixmap2 = None;
489  Pixmap pixmap = PXM_GetIconPixmap(ID_ICON_WHAT, NULL, &pixmap2);
490 
491  if(pixmap != None)
492  {
493  WBDialogControlSetIconPixmap(pCtrl, pixmap, pixmap2);
494  }
495  }
496  }
497 
498  // assign the caption text to the caption window (which varies and must be assigned at run time)
499 
500  DLGSetControlCaption((WBDialogWindow *)pDlg, 1001, pUserData->szMessage);
501 
502  if(pUserData->szRval)
503  {
504  DLGSetControlCaption(pDlg, 1002, pUserData->szRval);
505  }
506 
507  return 1;
508  }
509 
510  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aCONTROL_NOTIFY)
511  {
512  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
513  "%s - MessageBox ClientMessage CONTROL_NOTIFY\n", __FUNCTION__);
514 
515  switch(pEvent->xclient.data.l[1]) // control ID
516  {
517  case IDOK:
518  case IDCANCEL:
519  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
520  {
521  const char *pText = DLGGetControlCaption(pDlg, 1002);
522 
523  if(pUserData->szRval)
524  {
525  WBFree(pUserData->szRval);
526  }
527  if(pText)
528  {
529  pUserData->szRval = WBCopyString(pText);
530  }
531  else
532  {
533  WB_ERROR_PRINT("TEMPORARY: %s - NULL 'pText' for edit control\n", __FUNCTION__);
534  pUserData->szRval = NULL; // empty string
535  }
536 
537  WBEndModal(wID, pEvent->xclient.data.l[1]);
538  }
539  break;
540 
541  case 1002:
542  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
543  "%s - INPUT BOX 'EDIT' NOTIFICATION %ld\n",
544  __FUNCTION__, pEvent->xclient.data.l[0]);
545 
546  // TODO: update window text
547  break;
548 
549  default:
550  WB_WARN_PRINT("%s - MessageBox ClientMessage CONTROL_NOTIFY client id=%lx\n",
551  __FUNCTION__, pEvent->xclient.data.l[0]);
552  }
553  }
554 
555  return 0;
556 }
557 
558 char *DLGInputBox(Window wIDOwner, const char *szTitle, const char *szPrompt, const char *szDefault,
559  int iWidth, int iMaxChar)
560 {
561 static const char szInputDialogRes[]=
562  "BEGIN_DIALOG FONT:Variable HEIGHT:60 WIDTH:200 TITLE:\"User Input\"\n"
563  " CONTROL:Icon ID:1000 X:2 Y:2 HEIGHT:20 WIDTH:20 VISIBLE\n"
564  " CONTROL:Text ID:1001 X:24 Y:2 HEIGHT:20 WIDTH:172 VISIBLE HALIGN_TEXT_CENTER\n"
565  " CONTROL:Edit ID:1002 X:2 Y:22 WIDTH:196 HEIGHT:16 VISIBLE\n"
566  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:40 Y:40 WIDTH:40 HEIGHT:18 VISIBLE\n"
567  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:120 Y:40 WIDTH:40 HEIGHT:18 VISIBLE\n"
568  "END_DIALOG\n";
569 WBDialogWindow *pDlg;
570 struct _INPUT_BOX_ sRval;
571 int iRval;
572 Window wIDDlg;
573 
574 
575  sRval.szTitle = szTitle;
576  sRval.szMessage = szPrompt;
577  if(szDefault && *szDefault)
578  {
579  sRval.szRval = WBCopyString(szDefault); // a copy of the default value
580  }
581  else
582  {
583  sRval.szRval = NULL;
584  }
585 
586  pDlg = DLGCreateDialogWindow(szTitle,szInputDialogRes,
587  100,100,300,60,InputBoxCallback,
588  WBDialogWindow_VISIBLE,&sRval);
589 
590  if(pDlg) // TODO: manage this stuff as part of 'DLGCreateDialogWindow' instead
591  {
592  wIDDlg = pDlg->wID;
593 
594  if(wIDOwner != None)
595  {
596  Atom a1;
597  unsigned int ai1[3];
598 
599  DLGAssignOwner(pDlg, wIDOwner);
600 
601  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
602  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
603  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
604 
605  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 2);
606 
607  a1 = XInternAtom(WBGetWindowDisplay(wIDDlg), "WM_TRANSIENT_FOR", False);
608  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wIDOwner, 1);
609  }
610 
611  iRval = WBShowModal(pDlg->wID, 0);
612 
613  if(iRval == IDOK)
614  {
615  return sRval.szRval;
616  }
617  else if(iRval != IDCANCEL)
618  {
619  WB_ERROR_PRINT("TEMPORARY - %s - iRval is %d\n", __FUNCTION__, iRval);
620  }
621  }
622 
623  // it ends up here on 'cancel', etc. - so if a buffer was allocated, free it
624 
625  if(sRval.szRval)
626  {
627  WBFree(sRval.szRval);
628  }
629 
630  return NULL;
631 }
632 
633 
634 
636 // FILE DIALOG
638 
639 struct _FILE_DIALOG_
640 {
641  const char *szDefPath;
642  const char *szDefName;
643  const char *szExtAndDescList;
644  char *szPathName; // WBAlloc'd
645 };
646 
647 
648 #define FILE_DIALOG_PATH_TREE_CONTROL 1000
649 #define FILE_DIALOG_FILE_LIST_CONTROL 1001
650 #define FILE_DIALOG_FILE_NAME_CONTROL 1002
651 
652 static int FileDialogCallback(Window wID, XEvent *pEvent)
653 {
655 struct _FILE_DIALOG_ *pUserData = (struct _FILE_DIALOG_ *)(pDlg ? pDlg->pUserData : NULL);
656 //Display *pDisplay = WBGetWindowDisplay(wID);
657 char *p1, *p2;
658 
659 
660  if(!pDlg)
661  return 0; // can't process any messages now
662 
663  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
664  {
665  if(!pUserData->szPathName || !*(pUserData->szPathName) ||
666  (!strchr(pUserData->szPathName, '/') && !WBIsDirectory(pUserData->szPathName)))
667  {
668  if(!pUserData->szDefPath || !*(pUserData->szDefPath))
669  {
670  // set the 'DLGC_PATH' property for appropriate controls
671  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
672  aDLGC_PATH, "."); // set path to '.' if not specified already
673  }
674  else
675  {
676  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
677  aDLGC_PATH, pUserData->szDefPath);
678  }
679  }
680  else
681  {
682  p1 = WBCopyString(pUserData->szDefPath);
683  if(!p1)
684  {
685  WB_ERROR_PRINT("%s - no memory to copy path string (a)\n", __FUNCTION__);
686  }
687  else
688  {
689  p2 = strrchr(p1, '/');
690  if(p2)
691  {
692  p2[1] = 0; // keep the '/'
693  }
694 
695  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
696  aDLGC_PATH, p1);
697 
698  WBFree(p1);
699  }
700  }
701 
702  return 1;
703  }
704 
705  if(pEvent->type != ClientMessage)
706  {
707  return 0; // unhandled at this time
708  }
709 
710  // EVERYTHING AT THIS POINT IS A CLIENT MESSAGE
711 
712  if(pEvent->xclient.message_type == aCONTROL_NOTIFY)
713  {
714  // l[0] == message
715  // l[1] == control ID
716  // l[2] ==
717  switch(pEvent->xclient.data.l[1])
718  {
719  case IDOK:
720  case IDCANCEL:
721  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
722  {
723  if(pEvent->xclient.data.l[1] == IDOK)
724  {
725  const char *pPath = DLGGetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL);
726  const char *pDir = DLGGetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL, aDLGC_PATH);
727 
728  if(pUserData->szPathName)
729  {
730  WBFree(pUserData->szPathName);
731  }
732 
733  if(pPath && pPath[0] == '/')
734  {
735  pUserData->szPathName = WBCopyString(pPath); // absolute path assignment
736  }
737  else
738  {
739  if(pDir && *pDir)
740  {
741  pUserData->szPathName = WBCopyString(pDir);
742 
743  if(pUserData->szPathName && *pUserData->szPathName &&
744  pUserData->szPathName[strlen(pUserData->szPathName) - 1] != '/')
745  {
746  WBCatString(&(pUserData->szPathName), "/");
747  }
748  }
749  else
750  {
751  pUserData->szPathName = WBCopyString("./");
752  }
753 
754 // WB_ERROR_PRINT("TEMPORARY %s ---> dir=\"%s\" path=\"%s\" \n", __FUNCTION__, pUserData->szPathName, pPath);
755 
756  if(pUserData->szPathName && pPath)
757  {
758  WBCatString(&(pUserData->szPathName), pPath);
759  }
760 
761  // check for '/../' within path - if present, canonicalize it
762  if(pUserData->szPathName &&
763  (strstr(pUserData->szPathName, "/../") ||
764  (strlen(pUserData->szPathName) > 3 &&
765  (!memcmp(pUserData->szPathName, "../", 3) ||
766  !memcmp(pUserData->szPathName + strlen(pUserData->szPathName) - 3, "/..", 3)))))
767  {
768  p1 = WBGetCanonicalPath(pUserData->szPathName);
769  if(p1)
770  {
771  WBFree(pUserData->szPathName);
772  pUserData->szPathName = p1;
773  }
774  else
775  {
776  WB_ERROR_PRINT("ERROR - %s - Unable to get canonical path for \"%s\"\n", __FUNCTION__, pUserData->szPathName);
777  }
778  }
779  }
780 
781  if(pUserData->szPathName && *pUserData->szPathName &&
782  (pUserData->szPathName[strlen(pUserData->szPathName) - 1] == '/' || WBIsDirectory(pUserData->szPathName)))
783  {
784  // if it ends in a '/' it's supposed to be a DIRECTORY and I must change to it
785  p1 = WBCopyString(pUserData->szPathName);
786  if(p1 && (!*p1 || p1[strlen(p1) - 1] != '/'))
787  {
788  WBCatString(&p1, "/"); // make sure it ends in '/'
789  }
790 
791  if(!p1)
792  {
793  WB_ERROR_PRINT("%s - no memory to copy path string (b)\n", __FUNCTION__);
794  }
795  else
796  {
797  // TODO: do I do a chdir() ?
798 
799  DLGSetControlProperty(pDlg, FILE_DIALOG_FILE_LIST_CONTROL,
800  aDLGC_PATH, p1);
801 
802 // WB_ERROR_PRINT("TEMPORARY %s ---> new path=\"%s\"\n", __FUNCTION__, p1);
803 
804  // also I want to make sure that the file name control contains the new path
805  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, p1);
806 
807  WBFree(p1);
808  }
809 
810  return 1; // handled (do not close the dialog box)
811  }
812  }
813 
814  WBEndModal(wID, pEvent->xclient.data.l[1]);
815  return 1; // handled!
816  }
817  break;
818 
819  case FILE_DIALOG_FILE_LIST_CONTROL:
820  if(pEvent->xclient.data.l[0] == aLIST_NOTIFY) // list control notifications
821  {
822  if(pEvent->xclient.data.l[2] == WB_LIST_SELCHANGE)
823  {
824  // assign the textbox value to the selected text
825  if(pEvent->xclient.data.l[3] >= 0)
826  {
827  WBDialogControl *pCtrl = DLGGetDialogControlStructFromID(pDlg, pEvent->xclient.data.l[1]);
828  if(pCtrl)
829  {
830  const char *pText = DLGGetControlListText(pCtrl, pEvent->xclient.data.l[3]);
831 
832  if(pText)
833  {
834 // WB_WARN_PRINT("%s - assigning control text \"%s\"\n", __FUNCTION__, pText);
835  if(*pText == '@')
836  {
837  char *p1 = WBCopyString(pText + 1);
838 
839  if(p1)
840  {
841  WBCatString(&p1, "/");
842  if(p1)
843  {
844  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, p1);
845  WBFree(p1);
846  }
847  }
848  }
849  else // assume '~'
850  {
851  DLGSetControlCaption(pDlg, FILE_DIALOG_FILE_NAME_CONTROL, pText + 1);
852  }
853  }
854  }
855  }
856 
857  return 1; // handled
858  }
859  else if(pEvent->xclient.data.l[2] == WB_LIST_DBLCLICK)
860  {
861  // NOTE: pEvent->xclient.data.l[3] contains the selection index
862 
863  // Rather than allowing the default handler to deal with it, post an 'OK' button notification
864  // so that the same code deals with THIS as with the OK button
865 
866 // XClientMessageEvent evt = {
867 // .type=ClientMessage,
868 // .serial=0,
869 // .send_event=0,
870 // .display=pDisplay,
871 // .window=wID,
872 // .message_type=aCONTROL_NOTIFY,
873 // .format=32
874 // };
875 // evt.data.l[0] = aBUTTON_PRESS;
876 // evt.data.l[1] = IDOK;
877 // evt.data.l[2] = 0;
878 // evt.data.l[3] = 0;
879 // evt.data.l[4] = 0;
880 //
881 // WBPostPriorityEvent(wID, (XEvent *)&evt);
882 
883  // build a 'click' notification event to make sure I capture the correct name
884  DLGNotifyDlg(pDlg, aCONTROL_NOTIFY, aLIST_NOTIFY, FILE_DIALOG_FILE_LIST_CONTROL,
885  WB_LIST_SELCHANGE, pEvent->xclient.data.l[3], 0); // duplicates a 'SEL CHANGE" event
886 
887  {
888 #ifndef NO_DEBUG
889  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
890  WB_WARN_PRINT("%s - LIST_NOTIFY WB_LIST_DBLCLICK control notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
891  __FUNCTION__, pEvent->xclient.data.l[0], p1,
892  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
893  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
894  if(p1)
895  {
896  WBFree(p1);
897  }
898 #endif // NO_DEBUG
899  }
900 
901  DLGNotifyDlgAsync(pDlg, aCONTROL_NOTIFY, aBUTTON_PRESS, IDOK, 0, 0, 0); // post a button press event
902 
903  return 1;
904  }
905 
906  return 0; // not handled
907  }
908  break;
909 
910  default:
911  {
912 #ifndef NO_DEBUG
913  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
914 
915  WB_WARN_PRINT("%s - TODO: control notification message %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
916  __FUNCTION__, pEvent->xclient.data.l[0], p1,
917  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
918  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
919 
920  if(p1)
921  {
922  WBFree(p1);
923  }
924 #endif // NO_DEBUG
925  }
926  }
927  }
928  else if(pEvent->xclient.message_type == aGOTFOCUS)
929  {
930  // control ID is in pEvent->xclient.data.l[0]
931  return 0; // for now
932  }
933  else if(pEvent->xclient.message_type == aLOSTFOCUS)
934  {
935  // control ID is in pEvent->xclient.data.l[0]
936  return 0; // for now
937  }
938  else
939  {
940 #ifndef NO_DEBUG
941  char *p1 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.message_type);
942  char *p2 = WBGetAtomName(WBGetWindowDisplay(wID), (Atom)pEvent->xclient.data.l[0]);
943 
944  WB_WARN_PRINT("%s - unhandled notification %s %ld (%s) %ld (%08lxH), %ld (%08lxH)\n",
945  __FUNCTION__, p1,
946  pEvent->xclient.data.l[0], p2,
947  pEvent->xclient.data.l[1], pEvent->xclient.data.l[1],
948  pEvent->xclient.data.l[2], pEvent->xclient.data.l[2]);
949 
950  if(p1)
951  {
952  WBFree(p1);
953  }
954  if(p2)
955  {
956  WBFree(p2);
957  }
958 #endif // NO_DEBUG
959  }
960 
961  return 0;
962 }
963 
964 char *DLGFileDialog(int iType, Window wIDOwner, const char *szDefPath, const char *szDefName,
965  const char *szExtAndDescList)
966 {
967 static const char szFileDialogRes[]=
968  "BEGIN_DIALOG FONT:Variable HEIGHT:250 WIDTH:260 TITLE:\"File Dialog\"\n"
969  " CONTROL:PathTree ID:1000 X:2 Y:2 HEIGHT:200 WIDTH:116 VISIBLE\n"
970  " CONTROL:FileList ID:1001 X:122 Y:2 HEIGHT:200 WIDTH:136 VISIBLE\n"
971  " CONTROL:Edit ID:1002 X:2 Y:206 WIDTH:296 HEIGHT:16 VISIBLE\n"
972  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:40 Y:230 WIDTH:40 HEIGHT:18 VISIBLE\n"
973  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:180 Y:230 WIDTH:40 HEIGHT:18 VISIBLE\n"
974  "END_DIALOG\n";
975 WBDialogWindow *pDlg;
976 struct _FILE_DIALOG_ data;
977 int iRval;
978 Window wIDDlg;
979 
980 
981  data.szDefPath = szDefPath;
982  data.szDefName = szDefName;
983  data.szExtAndDescList = szExtAndDescList;
984  data.szPathName = NULL;
985 
986  pDlg = DLGCreateDialogWindow("File Select",szFileDialogRes,
987  100,100,300,100,FileDialogCallback,
988  WBDialogWindow_VISIBLE,&data);
989 
990  if(pDlg) // TODO: manage this stuff as part of 'DLGCreateDialogWindow' instead
991  {
992  wIDDlg = pDlg->wID;
993 
994  if(wIDOwner != None)
995  {
996  Atom a1;
997  unsigned int ai1[3];
998 
999  DLGAssignOwner(pDlg, wIDOwner);
1000 
1001  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
1002  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
1003  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
1004 
1005  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 2);
1006 
1007  a1 = XInternAtom(WBGetWindowDisplay(wIDDlg), "WM_TRANSIENT_FOR", False);
1008  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wIDOwner, 1);
1009  }
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 = XGetImage(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 = XGetImage(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 GC 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 = XCreateGC(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  XFillRectangle(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  XFreeGC(pDisplay, 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, CHROMA_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 int DLGColorDialog(Window wIDOwner, XStandardColormap *pColorMap, XColor *pColor)
1806 {
1807 static const char szColorDialogRes[]=
1808  "BEGIN_DIALOG FONT:Variable HEIGHT:182 WIDTH:280 TITLE:\"Color Chooser\"\n"
1809 
1810  // these controls are first in the tab order
1811  " CONTROL:Image ID:1009 X:150 Y:120 WIDTH:50 HEIGHT:14 VISIBLE\n"
1812  " CONTROL:Text TITLE:\"Value:\" X:200 Y:122 WIDTH:24 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1813  " CONTROL:Edit ID:1010 X:228 Y:122 WIDTH:40 HEIGHT:10 VISIBLE\n"
1814 
1815  // then the buttons
1816  " CONTROL:DefPushButton ID:IDOK TITLE:OK X:60 Y:160 WIDTH:40 HEIGHT:18 VISIBLE\n"
1817  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:180 Y:160 WIDTH:40 HEIGHT:18 VISIBLE\n"
1818 
1819  // then the images
1820  " CONTROL:Image ID:1001 X:2 Y:2 HEIGHT:132 WIDTH:132 VISIBLE CLICKABLE\n" // 128x128 image, luma/saturation
1821  " CONTROL:Image ID:1002 X:2 Y:136 HEIGHT:16 WIDTH:132 VISIBLE CLICKABLE\n" // 128x12 image, chroma
1822 
1823  // then the rest
1824  " CONTROL:Text TITLE:\"Lum:\" X:140 Y:22 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1825  " CONTROL:Edit ID:1003 X:164 Y:22 WIDTH:28 HEIGHT:10 VISIBLE\n"
1826  " CONTROL:Text TITLE:\"Chr:\" X:140 Y:44 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1827  " CONTROL:Edit ID:1004 X:164 Y:44 WIDTH:28 HEIGHT:10 VISIBLE\n"
1828  " CONTROL:Text TITLE:\"Sat:\" X:140 Y:66 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1829  " CONTROL:Edit ID:1005 X:164 Y:66 WIDTH:28 HEIGHT:10 VISIBLE\n"
1830 
1831  " CONTROL:Text TITLE:\"Red:\" X:210 Y:22 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1832  " CONTROL:Edit ID:1006 X:234 Y:22 WIDTH:28 HEIGHT:10 VISIBLE\n"
1833  " CONTROL:Text TITLE:\"Grn:\" X:210 Y:44 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1834  " CONTROL:Edit ID:1007 X:234 Y:44 WIDTH:28 HEIGHT:10 VISIBLE\n"
1835  " CONTROL:Text TITLE:\"Blu:\" X:210 Y:66 WIDTH:22 HEIGHT:10 NOBORDER VISIBLE VALIGN_TEXT_CENTER HALIGN_TEXT_RIGHT\n"
1836  " CONTROL:Edit ID:1008 X:234 Y:66 WIDTH:28 HEIGHT:10 VISIBLE\n"
1837 
1838  "END_DIALOG\n";
1839 WBDialogWindow *pDlg;
1840 Display *pDisplay;
1841 struct _COLOR_DIALOG_ data;
1842 int iRval = IDCANCEL; // default return is 'cancel'
1843 Window wIDDlg;
1844 
1845 
1846  if(!pColor)
1847  {
1848  return -1; // not valid
1849  }
1850 
1851  if(wIDOwner)
1852  {
1853  pDisplay = WBGetWindowDisplay(wIDOwner);
1854  }
1855  else
1856  {
1857  pDisplay = WBGetDefaultDisplay();
1858  }
1859 
1860  memset(&data, 0, sizeof(data));
1861 
1862  if(WB_LIKELY(pColorMap)) // should always be the case
1863  {
1864  memcpy(&(data.stdColorMap), pColorMap, sizeof(data.stdColorMap));
1865  }
1866  else
1867  {
1868  WBDefaultStandardColormap(pDisplay, &(data.stdColorMap));
1869  }
1870 
1871  data.pColor = pColor; // pixel value will become initial color
1872  data.pimgLumaSat = NULL;
1873  data.pimgChroma = NULL;
1874  data.pixmapLumaSat = None;
1875  data.pixmapChroma = None;
1876 
1877  data.lPixel = pColor->pixel; // cache it - the rest will take care of itself
1878 
1879  // now that all of THAT is done, do the dialog box
1880 
1881  pDlg = DLGCreateDialogWindow("Color Chooser",szColorDialogRes,
1882  100,100,300,100,ColorDialogCallback,
1883  WBDialogWindow_VISIBLE,&data);
1884 
1885  if(pDlg) // TODO: manage this stuff as part of 'DLGCreateDialogWindow' instead
1886  {
1887  wIDDlg = pDlg->wID;
1888 
1889  if(wIDOwner != None)
1890  {
1891  Atom a1;
1892  unsigned int ai1[3];
1893 
1894  DLGAssignOwner(pDlg, wIDOwner);
1895 
1896  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
1897  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
1898  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
1899 
1900  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 2);
1901 
1902  a1 = XInternAtom(WBGetWindowDisplay(wIDDlg), "WM_TRANSIENT_FOR", False);
1903  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wIDOwner, 1);
1904  }
1905 
1906  iRval = WBShowModal(pDlg->wID, 0);
1907 
1908  if(iRval == IDOK)
1909  {
1910  // check pColor assigned via data.pColor?
1911  }
1912  }
1913 
1914  // free up any resources here
1915 
1916 
1917  return iRval;
1918 }
1919 
1920 
1921 
1923 // FONT DIALOG
1925 
1926 
1927 XFontSet DLGFontDialog(Display *pDisplay, Window wIDOwner, XFontSet fsDefault)
1928 {
1929  return None;
1930 }
1931 
1932 
1933 
1934 
1936 // SPLASH SCREEN
1938 
1939 
1940 // construct a splash screen based on the size of the pixmap and position
1941 // the copyright text in the lower 1/3 of the splash screen, centered, then
1942 // pass a 'diagonal flash' across it, and close the screen after a total of
1943 // 5 seconds, returning back to the application.
1944 
1945 typedef struct _SPLASH_
1946 {
1947  Pixmap pixmap, pixmap2;
1948  char *szCopyright;
1949  int iW, iH; // width/height of bitmap
1950  int iDepth; // depth, needed to create compatible pixmaps
1951  int nIter; // total # of iterations thus far
1952  XFontSet fontSet;//Struct *pFont;
1953  int nGleam; // current gleam center position
1954  WB_GEOM geomBorder;
1955  XStandardColormap cmap;
1956  XImage *pImage;
1957  void *pImageData;
1958  unsigned long cbImageData;
1959  unsigned long clrText, clrBlack, clrWhite; // pixel colors
1960 } SPLASH;
1961 
1962 static int splash_callback(Window wID, XEvent *pEvent);
1963 static int SplashDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
1964  Window wID, struct _SPLASH_ *pData);
1965 
1966 #define SPLASH_FRAMERATE 30 /* make this configurable? */
1967 #define SPLASH_TIME 1500 /* milliseconds */
1968 
1969 void DLGSplashScreen(char *aXPM[], const char *szCopyright, unsigned long clrText)
1970 {
1971 Window wID;//, wIDTemp;
1972 XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */
1973 int iX, iY, iW, iH;
1974 XSizeHints xsh; /* Size hints for window manager */
1975 XWMHints xwmh;
1976 XPM_ATTRIBUTES xattr;
1977 SPLASH data;
1978 Atom a1;
1979 unsigned int ai1[3];
1980 
1981 
1982  bzero(&data, sizeof(data));
1983  bzero(&xattr, sizeof(xattr));
1984 
1986  aXPM, &(data.pixmap), &(data.pixmap2), &xattr))
1987  {
1988  WB_ERROR_PRINT("XPM_CREATE_PIXMAP_FROM_DATA ERROR\n");
1989  return;
1990  }
1991 
1992  iW = xattr.width + 4; // border width is 2
1993  iH = xattr.height + 4; // border width is 2
1994  data.iDepth = xattr.depth;
1995  if(!data.iDepth)
1996  {
1997  data.iDepth = DefaultDepth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
1998  }
1999 
2000  if(!iW || !iH || data.pixmap == None)
2001  {
2002  WB_ERROR_PRINT("%s - iW=%d, iH=%d, data.pixmap=%d (%08xH)\n",
2003  __FUNCTION__, iW, iH, (int)data.pixmap, (int)data.pixmap);
2004  return;
2005  }
2006 
2007 // WB_ERROR_PRINT("TEMPORARY %s - iW=%d, iH=%d, data.pixmap=%d (%08xH)\n",
2008 // __FUNCTION__, iW, iH, (int)data.pixmap, (int)data.pixmap);
2009 
2010  // TODO: choose font, calculate bounds of text area
2011  // save font/bounds data and/or combine text into pixmap with transparent background
2012 
2013 
2014  iX = DisplayWidth(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2015  iY = DisplayHeight(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2016 
2017  iX = (iX - iW) / 2;
2018  iY = (iY - iH) / 2; // centered
2019 
2020  data.szCopyright = WBCopyString(szCopyright);
2021  data.clrText = clrText;
2022  data.clrBlack = BlackPixel(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2023  data.clrWhite = WhitePixel(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2024  data.iW = xattr.width;
2025  data.iH = xattr.height;
2026  data.fontSet = None; // must do this
2027  data.nGleam = 0;
2028  data.pImage = NULL;
2029  data.pImageData = NULL;
2030  data.cbImageData = 0;
2031 
2032  bzero(&xswa, sizeof(xswa));
2033 
2034  xswa.border_pixel = data.clrBlack;
2035  xswa.background_pixel = data.clrWhite;
2036  xswa.colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
2037  xswa.bit_gravity = CenterGravity;
2038 
2039  wID = WBCreateWindow(WBGetDefaultDisplay(), None,//DefaultRootWindow(WBGetDefaultDisplay()),
2040  splash_callback, "Splash",
2041  iX, iY, iW, iH, 0,
2042  InputOutput,
2043  CWBorderPixel | CWBackPixel | CWColormap | CWBitGravity | CWOverrideRedirect,
2044  &xswa);
2045 
2046  if(wID <= 0)
2047  {
2048  return;
2049  }
2050 
2051  WBSetWindowData(wID, 0, (void *)&data);
2052  WBCreateWindowDefaultGC(wID, clrText, xswa.background_pixel);
2053 
2054  bzero(&xsh, sizeof(xsh));
2055 
2056  xsh.flags = (USPosition | USSize | PBaseSize | PMinSize | PMaxSize | PWinGravity);
2057  xsh.x = iX;
2058  xsh.y = iY;
2059  xsh.width = xsh.base_width = xsh.min_width = xsh.max_width = iW;
2060  xsh.height = xsh.base_height = xsh.min_height = xsh.max_height = iH;
2061  xsh.win_gravity = NorthWestGravity; // StaticGravity
2062 
2063  bzero(&xwmh, sizeof(xwmh));
2064  xwmh.flags = InputHint;
2065  xwmh.input = 0; // never take focus
2066 
2067  // set title, size hints, and 'WM_HINTS' hints (so WM knows where to put the window and how to set focus)
2068  WBSetWMProperties(wID, "splashwindow", &xsh, &xwmh, NULL);
2069 
2070  // before mapping the window, set some properties
2071  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_WINDOW_TYPE", False);
2072  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_WINDOW_TYPE_SPLASH", False);
2073  XChangeProperty(WBGetDefaultDisplay(), wID, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 1);
2074 
2075 
2076  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
2077  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_MODAL", False);
2078  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
2079  ai1[2] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
2080  XChangeProperty(WBGetDefaultDisplay(), wID, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 3);
2081 
2082  // must EXPLICITLY allow PAINTING (and other stuff) i.e. ExposureMask
2083  XSelectInput(WBGetDefaultDisplay(), wID, WB_STANDARD_INPUT_MASK);
2084 
2086 
2087  if(CreateTimer(WBGetDefaultDisplay(), wID, 1000000 / SPLASH_FRAMERATE, 1, 1)) // periodic timer at 'frame rate'
2088  {
2089  WBDestroyWindow(wID);
2090  }
2091  else
2092  {
2093  WBMapWindow(WBGetDefaultDisplay(), wID); // make window visible
2094 
2095  WBShowModal(wID, -1); // timer will cause window to go away automatically
2096  }
2097 
2098  if(data.szCopyright)
2099  {
2100  WBFree((void *)data.szCopyright);
2101  }
2102 
2103  if(data.pImageData)
2104  {
2105  WBFree(data.pImageData);
2106  }
2107 
2109  if(data.pImage)
2110  {
2111  XDestroyImage(data.pImage);
2112  }
2113 
2114  if(data.pixmap != None)
2115  {
2116  XFreePixmap(WBGetDefaultDisplay(), data.pixmap);
2117  data.pixmap = None;
2118  }
2119 
2120  if(data.pixmap2 != None)
2121  {
2122  XFreePixmap(WBGetDefaultDisplay(), data.pixmap2);
2123  data.pixmap2 = None;
2124  }
2125 
2126  if(data.fontSet)
2127  {
2128  XFreeFontSet(WBGetDefaultDisplay(), data.fontSet);
2129  }
2131 }
2132 
2133 static int splash_callback(Window wID, XEvent *pEvent)
2134 {
2135 Display *pDisplay = WBGetWindowDisplay(wID);
2136 struct _SPLASH_ *pData = (struct _SPLASH_ *)WBGetWindowData(wID, 0);
2137 
2138 
2139  if(pData && pEvent->type == Expose)
2140  {
2141  return SplashDoExposeEvent((XExposeEvent *)pEvent, pDisplay, wID, pData);
2142  }
2143 
2144  if(pEvent->type == ClientMessage &&
2145  pEvent->xclient.message_type == aWB_TIMER)
2146  {
2147  if(!pData)
2148  {
2149  DeleteTimer(WBGetDefaultDisplay(), wID, 1);
2151  WBDestroyWindow(wID);
2152  return 1;
2153  }
2154 
2155  pData->nIter ++;
2156 
2157  if(pData->nIter * 1000 >= SPLASH_FRAMERATE * (SPLASH_TIME + 1000))
2158  {
2159  DeleteTimer(WBGetDefaultDisplay(), wID, 1);
2160  WBSetWindowData(wID, 0, NULL);
2161  WBDestroyWindow(wID);
2162  }
2163  else
2164  {
2165  WBInvalidateGeom(wID, NULL, 1);
2166  }
2167 
2168  return 1;
2169  }
2170 
2171  // special handling for 'destroy'
2172  if(pEvent->type == DestroyNotify &&
2173  pEvent->xdestroywindow.window == wID)
2174  {
2175  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2176  "%s - DestroyNotify\n", __FUNCTION__);
2177 
2178  WBSetWindowData(wID, 0, NULL);
2179 
2180  return 1;
2181  }
2182 
2183  return 0; // not handled
2184 }
2185 
2186 static int SplashDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
2187  Window wID, struct _SPLASH_ *pData)
2188 {
2189 XFontSet fontSet;
2190 GC gc;
2191 Pixmap pxTemp;
2192 XGCValues xgcv;
2193 WB_GEOM geomText;
2194 int iX, iY, iTimeStart, iTimeEnd;
2195 
2196 
2197  if(!pDisplay)
2198  {
2199  pDisplay = WBGetDefaultDisplay();
2200  }
2201 
2202 // gc = WBBeginPaint(wID, pEvent, &geomPaint); // gnome b0rks this - window has absolute coordinates!
2203 
2204  if(pData->fontSet == None && pData->szCopyright && *(pData->szCopyright))
2205  {
2207  pData->szCopyright, &geomText);
2208 
2209  if(fontSet == None)
2210  {
2211  fontSet = WBFontSetFromFont(WBGetDefaultDisplay(), WBGetDefaultFont()); // makes a copy of the font set, basically
2212  }
2213 
2214  pData->fontSet = fontSet;
2215  }
2216 
2217  fontSet = pData->fontSet; // cache it for later
2218 
2219 
2220  bzero(&xgcv, sizeof(xgcv));
2221 // if(pFont)
2222 // {
2223 // xgcv.font = pData->pFont->fid;
2224 // xgcv.fill_style = FillSolid;
2225 // }
2226  xgcv.foreground = pData->clrText;
2227  xgcv.background = pData->clrWhite;
2228  xgcv.line_width = 1;
2229  xgcv.function = GXcopy; // copy
2230  xgcv.cap_style = CapProjecting;
2231 
2232  gc = XCreateGC(pDisplay, wID,
2233  (/*(xgcv.font ? GCFont | GCFillStyle : 0) | */GCForeground | GCBackground | GCCapStyle | GCFunction | GCLineWidth),
2234  &xgcv);
2235 
2236  if(!gc)
2237  {
2238  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2239  return 0;
2240  }
2241 
2242  // now we get to create a window-compatible pixmap compatible with the window size
2243  // NOTE: XListDepths and XDefaultDepth may be needed to convert pixmaps to something that's compatible
2244 
2245  WBGetWindowGeom(wID, &(pData->geomBorder));
2246  pData->geomBorder.x = pData->geomBorder.y = 0; // force this (for now, gnome has absolute coordinates for splash window!)
2247 
2248 // not currently being used - later if I need it, uncomment - gcc in linux barphs on unused assigned vars
2249 // xrct.x = pData->geomBorder.x;
2250 // xrct.y = pData->geomBorder.y;
2251 // xrct.width = pData->geomBorder.width;
2252 // xrct.height = pData->geomBorder.height;
2253 
2254 
2255  if(pData->pixmap2 != None) // first part was already done
2256  {
2257  pxTemp = pData->pixmap2;
2258  }
2259  else
2260  {
2261  pxTemp = XCreatePixmap(pDisplay, wID, pData->iW + 4, pData->iH + 4,
2262  DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
2263 
2264  if(pxTemp == None)
2265  {
2266  WB_ERROR_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2267  XFreeGC(pDisplay, gc);
2268  return 0;
2269  }
2270 
2271  if(pData->pixmap != None) // just in case
2272  {
2273  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc,
2274  0, 0, pData->iW, pData->iH,
2275  pData->geomBorder.x + 2, pData->geomBorder.y + 2);
2276  }
2277  else
2278  {
2279  // TODO: erase the background of the drawable, WBEraseBackground maybe?
2280  }
2281 
2282  // this fixes the border areas properly
2283 
2284  xgcv.line_width = 3;
2285  xgcv.function = GXcopy; // copy
2286  xgcv.cap_style = CapProjecting;
2287 
2288  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2289 
2290  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, 0,0, pData->iW + 3, 0);
2291  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, pData->iW + 3, 0, pData->iW + 3, pData->iH + 3);
2292  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, pData->iW + 3, pData->iH + 3, 0, pData->iH + 3);
2293  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, 0, pData->iH + 3, 0, 0);
2294 
2295  pData->pixmap2 = pxTemp; // temporarily cache it here (I'll juggle it after allocating 2nd pixmap)
2296 
2297  // next, I must create a *new* temporary pixmap as my 'working' pixmap. the previous one is the 'reference' pixmap
2298 
2299  pxTemp = XCreatePixmap(pDisplay, wID, pData->iW + 4, pData->iH + 4,
2300  DefaultDepth(pDisplay, DefaultScreen(pDisplay)));
2301 
2302  if(pxTemp == None)
2303  {
2304  WB_ERROR_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
2305 
2306  XFreePixmap(WBGetDefaultDisplay(), pData->pixmap2); // restartability
2307  pData->pixmap2 = None;
2308 
2309  XFreeGC(pDisplay, gc);
2310  return 0;
2311  }
2312 
2313  if(pData->pixmap != None) // just in case, test for it
2314  {
2315  XFreePixmap(WBGetDefaultDisplay(), pData->pixmap);
2316  }
2317 
2318  pData->pixmap = pData->pixmap2; // NOW, ref pixmap (with image and border) goes into 'pixmap'
2319  pData->pixmap2 = pxTemp; // and the 'working' copy into 'pixmap2' (which is also 'pxTemp')
2320 
2321  // make an exact duplicate without any clipping regions
2322  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc,
2323  0, 0, pData->iW + 4, pData->iH + 4, 0, 0); // make a good copy of it at least once
2324  }
2325 
2326  if(pData->nIter <= 1)
2327  {
2328 // WBClearWindow(wID, gc); GC doesn't have a clip region yet, don't do this
2329  XClearWindow(pDisplay, wID); // erase background
2330  }
2331  else if(pData->nIter == SPLASH_FRAMERATE / 2) // after first half second
2332  {
2333  geomText.x = pData->geomBorder.x + 2;
2334  geomText.y = pData->geomBorder.y + 2;
2335  geomText.width = pData->geomBorder.width - 4;
2336  geomText.height = pData->geomBorder.height - 4;
2337 
2338  geomText.y += (geomText.height * 2) / 3;
2339  geomText.height -= (geomText.height * 2) / 3; // bottom 1/3
2340 
2341  // copyright string is 1 or 2 lines, for now use whatever font I end up with and draw lines separately
2342 
2343  if(fontSet != None)
2344  {
2345  WB_RECT rctBounds;
2346  rctBounds.left = geomText.x;
2347  rctBounds.top = geomText.y;
2348  rctBounds.right = rctBounds.left + geomText.width;
2349  rctBounds.bottom = rctBounds.top + geomText.height;
2350 
2351  DTDrawMultiLineText(fontSet, pData->szCopyright, pDisplay, gc, pData->pixmap,
2352  -8, 0, &rctBounds, DTAlignment_VCENTER | DTAlignment_HCENTER);
2353 #if 0
2354  p1 = pData->szCopyright;
2355  p2 = strchr(p1, '\n');
2356 
2357  if(p2)
2358  {
2359  *(p2++) = 0;
2360  }
2361 
2362  if(!p2 || !*p2)
2363  {
2364  iX = geomText.x + (geomText.width - XTextWidth(pFont, p1, strlen(p1))) / 2;
2365  iY = geomText.y + (geomText.height - pFont->max_bounds.ascent + pFont->max_bounds.descent) / 2
2366  + pFont->max_bounds.ascent; // bottom of text
2367 
2368  XDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p1, strlen(p1));
2369  }
2370  else
2371  {
2372  iX = geomText.x + (geomText.width - XTextWidth(pFont, p1, strlen(p1))) / 2;
2373  iY = geomText.y + (geomText.height - 2 * (pFont->max_bounds.ascent + pFont->max_bounds.descent)) / 2
2374  + pFont->max_bounds.ascent; // bottom of text
2375 
2376  XDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p1, strlen(p1));
2377 
2378  iX = geomText.x + (geomText.width - XTextWidth(pFont, p2, strlen(p2))) / 2;
2379  iY += pFont->max_bounds.ascent + pFont->max_bounds.descent;
2380 
2381  XDrawString(pDisplay, pxTemp ? pxTemp : wID, gc, iX, iY, p2, strlen(p2));
2382  }
2383 
2384  if(p2)
2385  {
2386  *(p2 - 1) = '\n'; // restore it for next time
2387  }
2388 #endif // 0
2389  }
2390  else
2391  {
2392  fprintf(stderr, "NO FONT, iter=%d\n", pData->nIter);
2393  }
2394 
2395  // make an exact duplicate without any clipping regions
2396 
2397  XCopyArea(pDisplay, pData->pixmap, pxTemp, gc,
2398  0, 0, pData->iW + 4, pData->iH + 4, 0, 0);
2399 
2400  // now, grab an XImage for it
2401 
2402  pData->pImage = XGetImage(pDisplay, pxTemp, 0, 0, pData->iW + 4, pData->iH + 4,
2403  0xffffffff, XYPixmap);
2404  }
2405 
2406  // TODO: consider creating clip regions to improve performance
2407 
2408  if(pData->nIter >= SPLASH_FRAMERATE / 2) // after first half second
2409  {
2410  iTimeStart = 1250 * SPLASH_FRAMERATE; // 1.5 seconds' worth in msecs, not seconds
2411  iTimeEnd = (SPLASH_TIME + 1000) * SPLASH_FRAMERATE
2412  - 500 * SPLASH_FRAMERATE; // 1/2 sec before end
2413 
2414  if(iTimeStart + 1000 * SPLASH_FRAMERATE / 2 > iTimeEnd)
2415  {
2416  iTimeStart = iTimeEnd - SPLASH_FRAMERATE / 2;
2417  }
2418 
2419  // drawing the 'gleam' diagonally from upper left to lower right
2420  // TODO: make this optional?
2421 
2422  if(pData->nIter * 1000 > iTimeEnd)
2423  {
2424  if(pData->pImage)
2425  {
2426  XPutImage(pDisplay, pData->pixmap2, gc, pData->pImage, 0, 0, 0, 0, pData->iW + 4, pData->iH + 4);
2427 
2428  XDestroyImage(pData->pImage); // destroy it now that I'm done with it
2429  pData->pImage = NULL; // no longer stored (already cleaned up)
2430  }
2431  }
2432  else if(pData->nIter * 1000 >= iTimeStart && pData->nIter * 1000 <= iTimeEnd)
2433  {
2434  int iDelta = iTimeEnd - iTimeStart + 1;
2435  int iTemp;
2436  XImage *pI; // the image I'll be manipulating
2437 
2438  iTemp = pData->nIter * 1000L - iTimeStart;
2439  iTemp = (int)(((long long)iTemp * (long long)iTemp) / (iTimeEnd - iTimeStart));
2440 
2441  // get the starting points and end points
2442  iX = 2 * (pData->iW * iTemp / iDelta + pData->iW / (2 * iDelta) / 1000); // x pos of top
2443  iY = 2 * (pData->iH * iTemp / iDelta + pData->iH / (2 * iDelta) / 1000); // y pos of left
2444 
2445  // will draw the line from 0,iY to iX,0
2446 
2447  if(!pData->pImage)
2448  {
2449  pData->pImage = XGetImage(pDisplay, pData->pixmap2, 0, 0, pData->iW + 4, pData->iH + 4,
2450  0xffffffff, // I've tried 0, 1, and THIS value - no apparent difference
2451  XYPixmap); // TODO: use ZPixmap instead?
2452  }
2453 
2454  pI = pData->pImage;
2455 
2456  if(pI && !pData->pImageData)
2457  {
2458  // this formula can be found in the xorg-server source:
2459  // length = ximage->bytes_per_line * ximage->height;
2460  // this is from 'xnestGetImage' in hw/xnest/GCOps.c
2461  // note that they don't include 'depth' in that. when I exclude 'depth', it doesn't work
2462  // TODO: do I need to pay attention to PADDING? docs and source suggest 'no'
2463 
2464 // WB_ERROR_PRINT("TEMPORARY: %s - bytes_per_line=%d, height=%d, depth=%d\n", __FUNCTION__,
2465 // pI->bytes_per_line, pI->height, pI->depth);
2466 
2467  pData->cbImageData = PXM_GetImageDataLength(pI);
2468  pData->pImageData = WBAlloc(pData->cbImageData + 4);
2469 
2470  if(pData->pImageData)
2471  {
2472  memcpy(pData->pImageData, PXM_GetImageDataPtr(pI), pData->cbImageData);
2473  }
2474  }
2475 
2476  if(!pI)
2477  {
2478  // don't do anything
2479  }
2480  else
2481  {
2482 #if defined(GLEAM_OLD)
2483 #define GLEAM_WIDTH 10
2484  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
2485 #elif defined(GLEAM_NARROW)
2486 #define GLEAM_WIDTH 17
2487  static int aLuma[GLEAM_WIDTH + 1] = { 255, 202, 161, 128, 101, 80, 64, 51, 40,
2488  32, 25, 20, 16, 13, 10, 8, 6, 5 }; // similar but 1/r^2 version (no cos)
2489 #else // WIDE gleam
2490 #define GLEAM_WIDTH 29
2491  static int aLuma[GLEAM_WIDTH + 1] = { 255,225,198,175,154,136,120,106,93,82,72,64,
2492  56,50,44,39,34,30,26,23,21,18,16,14,12,11,10,8,7,7 }; // a bit wider, more obvious
2493 #endif // GLEAM_OLD, GLEAM_NARROW
2494 
2495  int iX0, iY0, iX1, i1, i2, iW, iL, iMaxX, iMaxY;
2496 
2497  // NOW I get the fun of directly manipulating my image. W00T!
2498 
2499  // effectively I do this: XDrawLine(pDisplay, pxTemp, gc, -2, iY, iX, -2) and it's 19 pixels wide
2500 
2501  // So the line has a width of '2*GLEAM_WIDTH + 1' pixels. The pixels represent a white reflection
2502  // centering at the coordinates I specified above, that is the line from -2, iY to iX, -2 . This
2503  // actually SHOULD be offset by 2 pixels so that it does not affect the border, but that's less iomportant
2504 
2505  // draw the line. 19 pixels wide is actually +/- 9. We start with a single pixel-width line, then
2506  // do a for loop from/to +/- GLEAM_WIDTH on the X axis, keeping Y constant. if Y did not change, skip it.
2507 
2508  iMaxX = pData->iW;
2509  iMaxY = pData->iH;
2510 
2511  for(iX0 = -GLEAM_WIDTH, iY0 = iY + GLEAM_WIDTH; iX0 < iMaxX + GLEAM_WIDTH && iY0 > -GLEAM_WIDTH; iX0++)
2512  {
2513  i1 = (int)(((iX - iX0) * (long long)iMaxY) / iMaxX); // a muldiv conversion (where I should be)
2514 
2515  if(iY0 > i1) // so I don't repeat what I've done
2516  {
2517  for(; iY0 > i1; iY0--) // remember, top < bottom so if I start at the bottom, must SUBTRACT
2518  {
2519  // +/- GLEAM_WIDTH pixels
2520  i2 = iX0 + GLEAM_WIDTH;
2521  for(iX1=iX0 - GLEAM_WIDTH, iW = -GLEAM_WIDTH; iX1 <= i2; iX1++, iW++)
2522  {
2523  // is my current iX1, iY0 inside the desired rectangle? If so, calculate the
2524  // new color and assign it to this point.
2525 
2526  if(iX1 > 2 && iX1 < iMaxX &&
2527  iY0 > 2 && iY0 < iMaxY)
2528  {
2529  XColor clrTemp, clrPixel;
2530  int iY, iU, iV, iR, iG, iB;
2531 
2532  clrPixel.pixel = XGetPixel(pI, iX1 + 2, iY0 + 2);
2533  PXM_PixelToRGB(&(pData->cmap), &clrPixel);
2534 
2535  PXM_RGBToYUV(clrPixel.red >> 8, clrPixel.green >> 8, clrPixel.blue >> 8,
2536  &iY, &iU, &iV);
2537 
2538  iL = aLuma[abs(iW)]; // the 'Luma' constant, 0-255 (with 255 = 'white')
2539 
2540  // new pixel luma will be: luma * (1 + iL / 128) (maxed at 255)
2541  // if new luma is > 255, reduce iU and iV (delta from 128) by the 'factor'
2542  // such that iU = 128 + (iU - 128) * factor [etc.]
2543  // and the 'factor' would be 255 / iU (the new value)
2544 
2545  iY = ((short)iY * ((short)256 + (short)iL)) / (short)256; // >> 6;/// (short)128;
2546 
2547  if(iY > 255)
2548  {
2549  iU = (short)128 + (((short)iU - (short)128) * (short)256) / (short)iY;
2550  iV = (short)128 + (((short)iV - (short)128) * (short)256) / (short)iY;
2551  iY = 255;
2552  }
2553 
2554  PXM_YUVToRGB(iY, iU, iV, &iR, &iG, &iB);
2555 
2556  clrTemp.red = iR << 8;
2557  clrTemp.green = iG << 8;
2558  clrTemp.blue = iB << 8;
2559  clrTemp.flags = DoRed | DoGreen | DoBlue;
2560 
2561  PXM_RGBToPixel(&(pData->cmap), &clrTemp);
2562 
2563  XPutPixel(pI, iX1 + 2, iY0 + 2, clrTemp.pixel);
2564  }
2565  }
2566  }
2567  }
2568  }
2569 
2570  // TODO: assign clipping region to gc
2571 
2572 // llTick -= WBGetTimeIndex();
2573 
2574  XPutImage(pDisplay, pData->pixmap2, gc, pI, 0, 0, 0, 0, pData->iW + 4, pData->iH + 4);
2575  XFlush(pDisplay); // make sure
2576 
2577 // llTick += WBGetTimeIndex();
2578 
2579  if(pData->pImageData)
2580  {
2581  // restore previous image data now that I'm done messing with it
2582  memcpy(PXM_GetImageDataPtr(pI), pData->pImageData, pData->cbImageData); // restore previous image data
2583  }
2584  else
2585  {
2586  XDestroyImage(pI);
2587  pData->pImage = NULL; // no longer stored (a fallback)
2588  }
2589 
2590 // WB_ERROR_PRINT("TEMPORARY: %s - pixel stuff takes %llu millis\n", __FUNCTION__, llTick);
2591  }
2592 
2593 #if 0
2594  // using some interesting raster ops, 'highlight' the pixels along the line of
2595  // (0,iY),(iX,0) or (iX,pData->iH-1),(pData->iW-1,iY)
2596 
2597  XSetForeground(pDisplay, gc, pData->clrWhite & 0x404040);
2598 
2599  xgcv.line_width = 19;
2600  xgcv.function = GXor; // a or b
2601  xgcv.cap_style = CapProjecting;
2602 
2603  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2604 
2605  if(!bInvert)
2606  {
2607  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2608  }
2609  else
2610  {
2611  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2612  }
2613 
2614  XSetForeground(pDisplay, gc, pData->clrWhite & 0x808080);
2615 
2616  xgcv.line_width = 11;
2617  xgcv.function = GXor; // a or b
2618  xgcv.cap_style = CapProjecting;
2619 
2620  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2621 
2622  if(!bInvert)
2623  {
2624  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2625  }
2626  else
2627  {
2628  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2629  }
2630 
2631  XSetForeground(pDisplay, gc, pData->clrWhite & 0xc0c0c0);
2632 
2633  xgcv.line_width = 5;
2634  xgcv.function = GXor; // a or b
2635  xgcv.cap_style = CapProjecting;
2636 
2637  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2638 
2639  if(!bInvert)
2640  {
2641  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2642  }
2643  else
2644  {
2645  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2646  }
2647 
2648  XSetForeground(pDisplay, gc, pData->clrWhite);
2649 
2650  xgcv.line_width = 1;
2651  xgcv.function = GXcopy; // copy
2652  xgcv.cap_style = CapProjecting;
2653 
2654  XChangeGC(pDisplay, gc, GCCapStyle | GCFunction | GCLineWidth, &xgcv);
2655 
2656  if(!bInvert)
2657  {
2658  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, -2, iY, iX, -2);
2659  }
2660  else
2661  {
2662  XDrawLine(pDisplay, pxTemp ? pxTemp : wID, gc, iX, pData->iH + 4, pData->iW + 4, iY);
2663  }
2664 #endif // 0
2665  }
2666  }
2667 
2668  if(pxTemp) // using the 2nd pixmap to do the work, thus making the whole screen update at once
2669  {
2670  XCopyArea(pDisplay, pxTemp, wID, gc, 0, 0, pData->iW + 4, pData->iH + 4, pData->geomBorder.x, pData->geomBorder.y);
2671  }
2672 
2673  XFreeGC(pDisplay, gc);
2674  XSync(pDisplay, 0); // force update NOW
2675  WBValidateGeom(wID, NULL);
2676 // WBEndPaint(wID, gc);
2677 
2678  return 1; // processed
2679 }
2680 
2681 
Icon - multiple question marks in red triangle.
#define WB_LIKELY(x)
optimization for code branching when condition is &#39;likely&#39;. use within conditionals ...
#define IDOK
Atom aLOSTFOCUS
CONTROL_NOTIFY ClientMessage for LOSTFOCUS event.
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.
&#39;window helper&#39; main header file for the X11workbench Toolkit API
#define WB_LIST_SELCHANGE
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
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.
static __inline__ unsigned long PXM_GetImageDataLength(XImage *pImage)
Returns the length of XImage data.
void WBGetWindowGeom(Window wID, WB_GEOM *pGeom)
Returns the RAW geometry of the window as reported by the window manager.
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:299
void * WBGetWindowData(Window wID, int iIndex)
Gets the data associated with this window and the specified index.
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.
XFontSet DLGFontDialog(Display *pDisplay, Window wIDOwner, XFontSet fsDefault)
Display a modal Font Dialog window, returning the selected font in the XColor structure pointed to by...
Definition: dialog_impl.c:1927
WBDialogWindow * DLGCreateDialogWindow(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
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&#39;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.
static __inline__ WBDialogControl * DLGGetDialogControlStructFromID(WBDialogWindow *pDialog, int iControlID)
Returns a pointer to the WBDialogControl structure for a dialog control with validation. May return NULL.
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.
XFontSet DTCalcIdealFontSet(Display *pDisplay, XFontSet fontSet, const char *szText, WB_GEOM *geomBounds)
Calculate the ideal font based on the text and rectangle.
Definition: draw_text.c:278
Atom aLIST_NOTIFY
CONTROL_NOTIFY ClientMessage for LIST_NOTIFY event.
int WBShowModal(Window wID, int bMenuSplashFlag)
Shows a &#39;modal&#39; 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:1805
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:558
Window WBGetHiddenHelperWindow(void)
Returns a special &#39;hidden&#39; window used for information purposes.
Icon - white asterisk on blue circle.
XFontSet WBFontSetFromFont(Display *pDisplay, const XFontStruct *pFont)
Creates an &#39;XFontSet&#39; from an XFontStruct for a given display.
Definition: font_helper.c:1750
Atom aDLGC_PATH
dialog control PATH property, for file and directory controls
Icon - yellow triangle (nothing else)
unsigned int border
Button Bits - No button.
horizontally centered text. tabs are treated as white space
Definition: draw_text.h:78
Button Bits - OK button.
mask for button bits
&#39;configuration helper&#39; main header file for the X11 Work Bench Toolkit API
void PXM_RGBToPixel(XStandardColormap *pMap, XColor *pColor)
Icon Registration for application &#39;large&#39; and &#39;small&#39; icons.
#define RGB255_TO_XCOLOR(R, G, B, X)
Simple RGB assignment to pixel, 0-255 RGB.
Definition: pixmap_helper.h:95
static __inline__ void DLGSetControlCaption(WBDialogWindow *pDialog, int iControlID, const char *szCaption)
Convenience function to assign a dialog control&#39;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.
Icon - white fright mask on black circle.
Icon - green circle.
#define WB_STANDARD_INPUT_MASK
&#39;Standard&#39; input mask, bit flag for window creation
Atom aMOUSE_CLICK
CONTROL_NOTIFY ClientMessage for MOUSE_CLICK event.
int depth
depth of the returned &#39;image&#39; pixmap. The mask pixmap always has a depth of &#39;1&#39;.
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&#39;s resources.
WB_UINT64 WBGetTimeIndex(void)
Returns the current &#39;time index&#39; (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)
&#39;Paint&#39; helper, invalidates a geometry for asynchronous Expose event generation
#define DIALOG_WINDOW_TAG
Icon - white &#39;middle finger&#39; on red triangle.
void WBDialogControlSetIconPixmap(WBDialogControl *pCtrl, Pixmap pixmap, Pixmap pixmap2)
Assign the ICON (image) property for a control, which consists of 2 pixmaps.
Window wID
Window ID of the dialog control window.
static __inline__ void WBDialogControlInvalidateGeom(WBDialogControl *pDialogControl, const WB_GEOM *pGeom, int bPaintFlag)
Convenience function, invalidates a Geom for a dialog box control.
void WBCreateWindowDefaultGC(Window wID, unsigned long clrFG, unsigned long clrBG)
creates a default GC for a window
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&#39;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 &#39;allocate&#39;.
unsigned int width
#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 &#39;control ID&#39; ...
static __inline__ void * PXM_GetImageDataPtr(XImage *pImage)
Returns pointer to XImage data.
void WBValidateGeom(Window wID, const WB_GEOM *pGeom)
&#39;Paint&#39; helper, validates a geometry for asynchronous Expose event generation
unsigned int height
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:1969
#define WB_ERROR_PRINT(...)
Preferred method of implementing an &#39;error level&#39; debug message for all subsystems.
Definition: debug_helper.h:356
Window wID
window ID of the dialog (frame) window
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 &#39;free&#39;.
#define IDCANCEL
void WBDestroyWindow(Window wID)
Destroy a window.
Button Bits - Retry button.
Icon - brown and tan teddy bear on grey circle.
void DTDrawMultiLineText(XFontSet fSet, const char *szText, Display *pDisplay, GC gc, Drawable dw, int iTabWidth, int iTabOrigin, const WB_RECT *prcBounds, int iAlignment)
draw multi-line text
Definition: draw_text.c:1589
static __inline__ int WBDialogControlGetCaptionInt(WBDialogControl *pCtrl)
Returns an integer from the text of the &#39;CAPTION&#39; property of a dialog control.
void WBSetWindowIcon(Window wID, int idIcon)
assigns an icon resource (by ID) to a window
void * pUserData
user data that&#39;s assignable via API
internal wrapper struct for &#39;rectangle&#39; definition
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.
Definition: x.c:237
Structure identifying the properties of a dialog box control.
static __inline__ const char * DLGGetControlCaption(WBDialogWindow *pDialog, int iControlID)
Convenience function to query a dialog control&#39;s caption based on its control ID. ...
Atom aMOUSE_DRAG
CONTROL_NOTIFY ClientMessage for MOUSE_DRAG event.
void DLGAssignOwner(WBDialogWindow *pDlg, Window wIDOwner)
Assign owning window to dialog.
const char * WBDialogControlGetCaption(WBDialogControl *pCtrl)
Obtain a pointer to the assigned text for the &#39;CAPTION&#39; property of a dialog control.
Icon - purple T-Rex head on white circle (more like mozilla)
XFontStruct * WBGetDefaultFont(void)
Returns a pointer to the default font&#39;s XFontStruct.
#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
Button Bits - Ignore button.
static __inline__ WBDialogWindow * DLGGetDialogWindowStruct(Window wID)
Returns a pointer to the dialog window&#39;s WBDialogWindow structure.
void WBSetWindowData(Window wID, int iIndex, void *pData)
assign &#39;data pointer&#39; 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 &#39;CAPTION&#39; property of a dialog control.
char * WBGetCanonicalPath(const char *szFileName)
Return the canonical path for a file name (similar to POSIX &#39;realpath()&#39; 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)
int height
height of the returned pixmaps
Structure identifying a dialog (frame) window.
#define WB_UNUSED
marks a variable as likely to be &#39;unused&#39;. warning abatement. Place macro directly after the variable...
Icon - application icon (from icon_app.xpm)
Window WBCreateWindow(Display *pDisplay, Window wIDParent, WBWinEvent pProc, const char *szClass, int iX, int iY, int iWidth, int iHeight, int iBorder, int iIO, int iFlags, XSetWindowAttributes *pXSWA)
Create a window.
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.
int width
The width of the returned pixmaps.
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
Visibility flag.
char * DLGFileDialog(int iType, Window wIDOwner, const char *szDefPath, const char *szDefName, const char *szExtAndDescList)
Display a modal File Dialog window, returning a WBAlloc&#39;d pointer to a null-byte terminated string co...
Definition: dialog_impl.c:964
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.
void WBSetWMProperties(Window wID, const char *szTitle, XSizeHints *pNormalHints, XWMHints *pWMHints, XClassHint *pClassHints)
assign standard WM (Window Manager) properties via XSetWMProperties
#define XPM_CREATE_PIXMAP_FROM_DATA(A, B, C, D, E, F)
Platform helper macro to create a pixmap from data.
Compatibility structure for use with MyLoadPixmapFromData() whenever libXpm is not in use...
void WBGetWindowGeom0(Window wID, WB_GEOM *pGeom)
Returns the ABSOLUTE window geometry relative the screen.
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.
Definition: x.c:125
Icon - white thumb down on red square.
int WBMapWindow(Display *pDisplay, Window wID)
Wrapper for XMapWindow, makes window visible.
Button Bits - Abort button.
void WBDialogControlSetPixmap(WBDialogControl *pCtrl, Pixmap pixmap)
Assign the PIXMAP (image) property for a control.
internal wrapper struct for X11 &#39;geometry&#39; definition
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 &#39;CAPTION&#39; property of a dialog control.
#define WB_WARN_PRINT(...)
Preferred method of implementing a &#39;warning level&#39; debug message for all subsystems.
Definition: debug_helper.h:349
static __inline__ WBDialogControl * DLGGetDialogControlStruct(Window wID)
Returns a pointer to the WBDialogControl structure for a dialog control with validation. May return NULL.
Icon - yellow circle with white exclamation point.
XFontSet WBGetDefaultFontSet(Display *pDisplay)
Returns an XFontSet for the default font.
int DLGMessageBox(int iType, Window wIDOwner, const char *szTitle, const char *szMessage)
Display a modal &#39;message box&#39; 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...