X11workbench Toolkit  1.0
dialog_controls.c
Go to the documentation of this file.
1 // //
3 // _ _ _ _ _ //
4 // __| |(_) __ _ | | ___ __ _ ___ ___ _ __ | |_ _ __ ___ | | ___ ___ //
5 // / _` || | / _` || | / _ \ / _` | / __|/ _ \ | '_ \ | __|| '__|/ _ \ | |/ __| / __| //
6 // | (_| || || (_| || || (_) || (_| | | (__| (_) || | | || |_ | | | (_) || |\__ \ _| (__ //
7 // \__,_||_| \__,_||_| \___/ \__, |_____\___|\___/ |_| |_| \__||_| \___/ |_||___/(_)\___| //
8 // |___/|_____| //
9 // //
10 // dialog control support //
11 // construction, destruction, message handling, and expose handlers for dialog controls //
12 // //
14 
15 /*****************************************************************************
16 
17  X11workbench - X11 programmer's 'work bench' application and toolkit
18  Copyright (c) 2010-2018 by Bob Frazier (aka 'Big Bad Bombastic Bob')
19  all rights reserved
20 
21  DISCLAIMER: The X11workbench application and toolkit software are supplied
22  'as-is', with no warranties, either implied or explicit.
23  Any claims to alleged functionality or features should be
24  considered 'preliminary', and might not function as advertised.
25 
26  BSD-like license:
27 
28  There is no restriction as to what you can do with this software, so long
29  as you include the above copyright notice and DISCLAIMER for any distributed
30  work that is equal to or derived from this one, along with this paragraph
31  that explains the terms of the license if the source is also being made
32  available. A "derived work" describes a work that uses a significant portion
33  of the source files or algorithms that are included with this one.
34  Specifically excluded from this are files that were generated by the software,
35  or anything that is included with the software that is part of another package
36  (such as files that were created or added during the 'configure' process).
37  Specifically included is the use of part or all of any of the X11 workbench
38  toolkit source or header files in your distributed application. If you do not
39  ship the source, the above copyright statement is still required to be placed
40  in a reasonably prominent place, such as documentation, splash screens, and/or
41  'about the application' dialog boxes.
42 
43  Use and distribution are in accordance with GPL, LGPL, and/or the above
44  BSD-like license. See COPYING and README files for more information.
45 
46 
47  Additional information at http://sourceforge.net/projects/X11workbench
48 
49 ******************************************************************************/
50 
51 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <memory.h>
56 #include <string.h>
57 #include <strings.h>
58 #include <signal.h>
59 #include <time.h>
60 #include <sys/stat.h>
61 
62 #ifndef XK_Delete /* moslty for interix */
63 #define XK_MISCELLANY /* mostly for interix */
64 #include <X11/keysymdef.h> // some platforms don't automatically include this with X headers
65 #endif // XK_Delete
66 
67 #include <X11/cursorfont.h> /* for special cursors */
68 
69 #include "window_helper.h"
70 #include "pixmap_helper.h" // pixmap helpers, including pre-defined icons
71 #include "dialog_window.h"
72 #include "dialog_controls.h"
73 #include "dialog_support.h" // internal stuff
74 #include "conf_help.h"
75 #include "text_object.h"
76 #include "file_help.h"
77 #include "draw_text.h"
78 #include "window_dressing.h"
79 
82 #define THIS_SUBSYSTEM DebugSubSystem_DialogCtrl
83 
84 #define KEYSYM_DEBUG_FLAG DebugLevel_Excessive/*DebugLevel_ERROR*/
85 
86 #define DEFAULT_STATIC_TAB_WIDTH 4 /* for drawing static text */
87 #define DEFAULT_BUTTON_TAB_WIDTH 4 /* for drawing button text */
88 
89 
90 static void FileListControlDisplayProc(WBDialogControl *pList, void *pData, int iSelected, GC gc, WB_GEOM *pGeom, XFontSet fontSet);
91 
92 
93 
94 #define DEFINE_CREATE_CONTROL(X) \
95  static WBDialogControl * do_create_##X(WBDialogControl *pDialogControl, \
96  int iX, int iY, int iWidth, int iHeight, \
97  const char *szClassName, const char *szTitle);
98 
99 #define IMPLEMENT_CREATE_CONTROL(X) \
100  static WBDialogControl * do_create_##X(WBDialogControl *pDialogControl, \
101  int iX, int iY, int iWidth, int iHeight, \
102  const char *szClassName, const char *szTitle)
103 
104 #define BEGIN_CREATE_CONTROL(X) Atom aThis WB_UNUSED = a##X;
105 
106 DEFINE_CREATE_CONTROL(FRAME_CONTROL)
107 DEFINE_CREATE_CONTROL(TEXT_CONTROL)
108 DEFINE_CREATE_CONTROL(ICON_CONTROL)
109 DEFINE_CREATE_CONTROL(IMAGE_CONTROL)
110 DEFINE_CREATE_CONTROL(EDIT_CONTROL)
111 DEFINE_CREATE_CONTROL(PUSHBUTTON_CONTROL)
112 DEFINE_CREATE_CONTROL(DEFPUSHBUTTON_CONTROL)
113 DEFINE_CREATE_CONTROL(CANCELBUTTON_CONTROL)
114 DEFINE_CREATE_CONTROL(RADIOBUTTON_CONTROL)
115 DEFINE_CREATE_CONTROL(FIRSTRADIOBUTTON_CONTROL)
116 DEFINE_CREATE_CONTROL(CHECKBUTTON_CONTROL)
117 DEFINE_CREATE_CONTROL(TRISTATEBUTTON_CONTROL)
118 DEFINE_CREATE_CONTROL(HSCROLL_CONTROL)
119 DEFINE_CREATE_CONTROL(VSCROLL_CONTROL)
120 DEFINE_CREATE_CONTROL(SLIDER_CONTROL)
121 DEFINE_CREATE_CONTROL(KNOB_CONTROL)
122 DEFINE_CREATE_CONTROL(LIST_CONTROL)
123 DEFINE_CREATE_CONTROL(COMBO_CONTROL)
124 DEFINE_CREATE_CONTROL(TREE_CONTROL)
125 DEFINE_CREATE_CONTROL(COMBOTREE_CONTROL)
126 DEFINE_CREATE_CONTROL(FILE_LIST_CONTROL)
127 DEFINE_CREATE_CONTROL(FILE_COMBO_CONTROL)
128 DEFINE_CREATE_CONTROL(PATH_TREE_CONTROL)
129 DEFINE_CREATE_CONTROL(TAB_CONTROL)
130 
131 
132 static int GetWBDialogControlStructSize(Atom aClass)
133 {
134  if(aClass == aICON_CONTROL ||
135  aClass == aIMAGE_CONTROL)
136  {
137  return sizeof(struct _WB_IMAGE_CONTROL_);
138  }
139 
140  if(aClass == aPUSHBUTTON_CONTROL ||
141  aClass == aDEFPUSHBUTTON_CONTROL ||
142  aClass == aCANCELBUTTON_CONTROL)
143  {
144  return sizeof(struct _WB_PUSHBUTTON_CONTROL_);
145  }
146 
147  if(aClass == aEDIT_CONTROL)
148  {
149  return sizeof(struct _WB_EDIT_CONTROL_);
150  }
151 
152  if(aClass == aCOMBO_CONTROL)
153  {
154  return sizeof(struct _WB_COMBO_CONTROL_);
155  }
156 
157  if(aClass == aLIST_CONTROL ||
158  aClass == aFILE_LIST_CONTROL)
159  {
160  return sizeof(struct _WB_LIST_CONTROL_);
161  }
162 
163  if(aClass == aTREE_CONTROL ||
164  aClass == aPATH_TREE_CONTROL)
165  {
166  return sizeof(struct _WB_TREE_CONTROL_);
167  }
168 
169  return sizeof(WBDialogControl);
170 }
171 
172 int DLGControlDefaultCallback(Window wID, XEvent *pEvent)
173 {
174 #ifndef NO_DEBUG
175  Display *pDisplay = WBGetWindowDisplay(wID);
176 #endif // NO_DEBUG
177  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
178  int iRval;
179 
180  if(!pDialogControl)
181  {
182  WB_ERROR_PRINT("%s - no dialog control struct for window %d (%08xH)\n",
183  __FUNCTION__, (int)wID, (int)wID);
184  return 0;
185  }
186 
187  // TODO: message re-direction to children BEFORE 'pDLGCallback'
188 
189  switch(pEvent->type)
190  {
191  case ButtonPress:
192  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Mouse | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
193  "BUTTON PRESS - dialog control\n");
194 
195  // if this window does NOT have the focus, then I must switch focus
196  // also make sure parent window is 'moved forward' so I can view it
197 
198  // TODO: in cases where button presses need to be generically overridden
199  // I can do that here
200 
201  break;
202 
203  case ButtonRelease:
204  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Mouse | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
205  "BUTTON RELEASE - dialog control\n");
206 
207  // TODO: in cases where button presses need to be generically overridden
208  // I can do that here
209 
210  break;
211 
212  case MotionNotify:
213  WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_Mouse | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
214  "MOTION NOTIFY - dialog control\n");
215 
216  // TODO: in cases where mouse drags need to be generically overridden
217  // I can do that here
218 
219  break;
220 
221  case KeyPress:
222  case KeyRelease:
223 
224  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Keyboard | DebugSubSystem_DialogCtrl,
225  "%s KEY PRESS/RELEASE - dialog control - check for hotkeys\n", __FUNCTION__);
226 
227  // TODO: in cases where key presses need to be generically overridden
228  // I can do that here
229 
230  iRval = DLGProcessHotKey(pDialogControl->pOwner, pEvent);
231 
232  if(iRval)
233  {
234  return iRval;
235  }
236 
237  break;
238 
239  case FocusIn:
240 
241 // WB_ERROR_PRINT("TEMPORARY: %s - FocusIn for dialog control ID %d window %d (%08xH)\n", __FUNCTION__,
242 // (int)(pDialogControl->pDlgControlEntry ? pDialogControl->pDlgControlEntry->iID : -1),
243 // (int)wID, (int)wID);
244 
245  WB_DEBUG_PRINT(DebugLevel_Excessive | DebugSubSystem_Mouse | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
246  "FocusIn - dialog control\n");
247 
248  DLGNotifyOwner(pDialogControl, aGOTFOCUS,
249  (long)(pDialogControl->pDlgControlEntry ? pDialogControl->pDlgControlEntry->iID : pDialogControl->wID),
250  WBCreatePointerHash(pDialogControl->pDlgControlEntry), 0, 0, 0);
251 
252  // now update myself
253  WBInvalidateGeom(wID, NULL, 1);
254 
255  break;
256 
257  case FocusOut:
258 
259  WB_DEBUG_PRINT(DebugLevel_Excessive | DebugSubSystem_Mouse | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
260  "FocusOut - dialog control\n");
261 
262  DLGNotifyOwner(pDialogControl, aLOSTFOCUS,
263  (long)(pDialogControl->pDlgControlEntry ? pDialogControl->pDlgControlEntry->iID : pDialogControl->wID),
264  WBCreatePointerHash(pDialogControl->pDlgControlEntry), 0, 0, 0);
265 
266  // now update myself
267  WBInvalidateGeom(wID, NULL, 1);
268 
269  break;
270 
271  }
272 
273 
274  if(pDialogControl->pDLGControlCallback)
275  {
276  // for most messages, if I handle it here, I don't do further processing
277 
278  int iRval = pDialogControl->pDLGControlCallback(wID, pEvent);
279 
280  if(iRval)
281  {
282  // check message types that I do *NOT* want to 'bail out' for
283 
284  switch(pEvent->type)
285  {
286  case DestroyNotify:
287  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
288  "%s - DestroyNotify and user callback returned %d\n", __FUNCTION__, iRval);
289 
290  break;;
291 
292  case Expose:
293  return iRval; // 'expose' event already handled
294 
295  default:
296  return iRval;
297  }
298  }
299  }
300 
301  // un-handled messages
302 
303  if(pEvent->type == ClientMessage &&
304  pEvent->xclient.window == wID)
305  {
306  if(pEvent->xclient.message_type == aWM_PROTOCOLS && pEvent->xclient.window == wID)
307  {
308  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
309  "CLIENT MESSAGE - dialog control - WM_PROTOCOLS\n");
310 
311  return 0; // "not handled"
312  }
313 // else if(pEvent->xclient.message_type == aCONTROL_NOTIFY) // 'control notification' messages
314 // {
315 // }
316 // else if(pEvent->xclient.message_type == aDLG_FOCUS) // dialog focus change message
317 // {
318 // }
319 
320 #ifndef NO_DEBUG
321  {
322  char *p1 = WBGetAtomName(pDisplay, pEvent->xclient.message_type);
323  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
324  "CLIENT MESSAGE - dialog control (NOT HANDLED) - %s\n", p1);
325  if(p1)
326  {
327  WBFree(p1);
328  }
329  }
330 #endif // NO_DEBUG
331  return 1;
332  }
333 
334 // // special handling for 'destroy'
335 // if(pEvent->type == DestroyNotify &&
336 // pEvent->xdestroywindow.window == wID)
337 // {
338 // WBUnregisterWindowCallback(wID); // force this to happen, regardless
339 
349 // return 1;
350 // }
351 
352  return 0;
353 }
354 
355 void DLGRegisterControlCallback(WBDialogControl *pDialogControl, const char *szClassName, WBWinEvent pCallback)
356 {
357  pDialogControl->pDLGControlCallback = pCallback;
358  WBRegisterWindowCallback(pDialogControl->wID, DLGControlDefaultCallback);
359  WBSetWindowClassName(pDialogControl->wID, szClassName);
360 }
361 
362 
364  WBDialogEntry *pDialogEntry, // pointer to the dialog entry I'll be using
365  int iX, int iY, int iWidth, int iHeight,
366  const char *szTitle, const char *szPropertyList)
367 {
368 WBDialogControl *pRval;
369 int i1;
370 
371 #define DO_CREATE_CONTROL(X) if(aClass == a##X) \
372  { return do_create_##X(pRval, iX, iY, iWidth, iHeight, #X, szTitle); }
373 
374  if(aClass == None)
375  {
376  WB_ERROR_PRINT("%s - 'aClass' is None (invalid type name?)\n", __FUNCTION__);
377  return NULL;
378  }
379 
380  pRval = WBAlloc(i1 = GetWBDialogControlStructSize(aClass));
381  if(!pRval)
382  {
383  return NULL;
384  }
385 
386  memset(pRval, 0, i1);
387 
388  iX = DLGPixelWidth(pOwner, iX);
389  iY = DLGPixelHeight(pOwner, iY);
390  iWidth = DLGPixelWidth(pOwner, iWidth);
391  iHeight = DLGPixelHeight(pOwner, iHeight);
392 
393  pRval->ulTag = DIALOG_CONTROL_TAG;
394  pRval->wID = -1; // initial value
395  pRval->aClass = aClass;
396  pRval->pOwner = pOwner;
397  pRval->pDlgControlEntry = pDialogEntry;
398  pRval->ulFlags = 0;
399  pRval->pPropList = NULL; // initial value
400  pRval->cbStructSize = i1; // keep track of how large the structure _REALLY_ is
401 
402  if(WBDialogControlSetPropList(pRval, szPropertyList))
403  {
404  WB_ERROR_PRINT("%s - Error return from WBDialogSetPropList\n", __FUNCTION__);
405  WBFree(pRval);
406  return NULL;
407  }
408 
409  DO_CREATE_CONTROL(FRAME_CONTROL); // NOTE: if requested type matches FRAME_CONTROL it returns
410  DO_CREATE_CONTROL(TEXT_CONTROL);
411  DO_CREATE_CONTROL(ICON_CONTROL);
412  DO_CREATE_CONTROL(IMAGE_CONTROL);
413  DO_CREATE_CONTROL(EDIT_CONTROL);
414  DO_CREATE_CONTROL(PUSHBUTTON_CONTROL);
415  DO_CREATE_CONTROL(DEFPUSHBUTTON_CONTROL);
416  DO_CREATE_CONTROL(CANCELBUTTON_CONTROL);
417  DO_CREATE_CONTROL(RADIOBUTTON_CONTROL);
418  DO_CREATE_CONTROL(FIRSTRADIOBUTTON_CONTROL);
419  DO_CREATE_CONTROL(CHECKBUTTON_CONTROL);
420  DO_CREATE_CONTROL(TRISTATEBUTTON_CONTROL);
421  DO_CREATE_CONTROL(HSCROLL_CONTROL);
422  DO_CREATE_CONTROL(VSCROLL_CONTROL);
423  DO_CREATE_CONTROL(SLIDER_CONTROL);
424  DO_CREATE_CONTROL(KNOB_CONTROL);
425  DO_CREATE_CONTROL(LIST_CONTROL);
426  DO_CREATE_CONTROL(COMBO_CONTROL);
427  DO_CREATE_CONTROL(TREE_CONTROL);
428  DO_CREATE_CONTROL(COMBOTREE_CONTROL);
429  DO_CREATE_CONTROL(FILE_LIST_CONTROL);
430  DO_CREATE_CONTROL(FILE_COMBO_CONTROL);
431  DO_CREATE_CONTROL(PATH_TREE_CONTROL);
432  DO_CREATE_CONTROL(TAB_CONTROL);
433 
434 
435  // TODO: user-registered controls
436 
437 
438  // if I get here the control was unrecognized (would have returned if any of the above matched)
439 
440  {
441  char *pAtomName = WBGetAtomName(WBGetDefaultDisplay(), aClass);
442 
443  if(pAtomName)
444  {
445  WB_ERROR_PRINT("%s - Unrecognized control '%s' in WBDialogControlCreate\n", __FUNCTION__, pAtomName);
446 
447  WBFree(pAtomName);
448  }
449  else
450  {
451  WB_ERROR_PRINT("%s - Unrecognized control {NULL} in WBDialogControlCreate\n", __FUNCTION__);
452  }
453  }
454 
455  // unrecognized control
456  if(pRval->pPropList)
457  {
459  pRval->pPropList = NULL; // as a matter of course
460  }
461 
463  WBFree(pRval);
464 
465  return NULL;
466 }
467 
468 
469 #define LOAD_COLOR0(X,Y) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) > 0) { }
470 #define LOAD_COLOR(X,Y,Z) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) <= 0){ WB_WARN_PRINT("%s - WARNING: can't find color %s, using default value %s\n", __FUNCTION__, X, Z); strcpy(Y,Z); }
471 
472 static void alloc_control_colors(WBDialogControl *pDialogControl,
473  const char *szFGName, const char *szBGName,
474  const char *szHFGName, const char *szHBGName,
475  const char *szAFGName, const char *szABGName,
476  const char *szBDName, int bUseStaticColors)
477 {
478 // static const char *szBorder2="#FFFFFF", *szBorder3="#9C9A94"; // for 3D borders
479  static const char *szHFGDef="#E0E0E0", *szHBGDef="#0000A0"; // highlight FG/BG
480  static const char *szAFGDef="#000000", *szABGDef="white"; // active FG/BG
481  char szFG[18], szBG[18], szBD[18], szHFG[18], szHBG[18], szAFG[18], szABG[18];
482  Colormap colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
483  int iY, iU, iV, iR, iG, iB;
484 
485 
486  // TODO: add some sanity to this, maybe an API for loading colors? *MOST* of this is now obsolete
487  // and XSETTINGS uses completely different naming.
488 
489  LOAD_COLOR0(szFGName,szFG) else LOAD_COLOR0("*Dialog.foreground",szFG) else LOAD_COLOR0("*Form.foreground", szFG)
490  else LOAD_COLOR0("*WmDialogShell.foreground",szFG) else LOAD_COLOR0("*WmForm.foreground", szFG)
491  else LOAD_COLOR("*foreground", szFG, "#000000");
492  if(bUseStaticColors)
493  {
494  LOAD_COLOR0(szBGName,szBG) else LOAD_COLOR0("*Dialog.background",szBG) else LOAD_COLOR0("*Form.background", szBG)
495  else LOAD_COLOR0("*WmDialogShell.background",szBG)
496  else LOAD_COLOR("*WmForm.background", szBG, "#dcdad5"); // default for gnome is dcdad5
497  }
498  else
499  {
500  LOAD_COLOR0(szBGName,szBG) else LOAD_COLOR0("*Window.background",szBG)
501  else LOAD_COLOR("*background", szBG, "white");
502  }
503  LOAD_COLOR(szHFGName,szHFG,szHFGDef);
504  LOAD_COLOR(szHBGName,szHBG,szHBGDef);
505  if(bUseStaticColors)
506  {
507  LOAD_COLOR(szAFGName,szAFG,szAFGDef);
508  LOAD_COLOR(szABGName,szABG,szABGDef);
509  }
510  else
511  {
512  LOAD_COLOR(szAFGName,szAFG,szFG);
513  LOAD_COLOR(szABGName,szABG,szBG);
514  }
515  LOAD_COLOR0(szBDName,szBD) else LOAD_COLOR0("*Dialog.border",szBD) else LOAD_COLOR0("*Form.border", szBD)
516  else LOAD_COLOR0("*WmDialogShell.border",szBD) else LOAD_COLOR0("*WmForm.border", szBD)
517  else LOAD_COLOR0("*borderColor", szBD)
518  else LOAD_COLOR("*border", szBD, "black"); // default for gnome
519 
520 
521 // // TEMPORARILY DUMP COLOR MAPPING
522 // WB_ERROR_PRINT("TEMPORARY: %s - control colors:\n", __FUNCTION__);
523 // WB_ERROR_PRINT(" %s=%s default=%s\n", szFGName, szFG, "#000000");
524 // WB_ERROR_PRINT(" %s=%s default=%s\n", szBGName, szBG, "#dcdad5 or 'white'");
525 // WB_ERROR_PRINT(" %s=%s default=%s\n", szHFGName, szHFG, szHFGDef);
526 // WB_ERROR_PRINT(" %s=%s default=%s\n", szHBGName, szHBG, szHBGDef);
527 // WB_ERROR_PRINT(" %s=%s default=%s\n", szAFGName, szAFG, szAFGDef);
528 // WB_ERROR_PRINT(" %s=%s default=%s\n", szABGName, szABG, szABGDef);
529 // WB_ERROR_PRINT(" %s=%s default=%s\n", szBDName, szBD, "black");
530 
531 
532  XParseColor(WBGetDefaultDisplay(), colormap, szFG, &(pDialogControl->clrFG));
533  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrFG));
534  XParseColor(WBGetDefaultDisplay(), colormap, szBG, &(pDialogControl->clrBG));
535  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrBG));
536  XParseColor(WBGetDefaultDisplay(), colormap, szAFG, &(pDialogControl->clrAFG));
537  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrAFG));
538  XParseColor(WBGetDefaultDisplay(), colormap, szABG, &(pDialogControl->clrABG));
539  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrABG));
540  XParseColor(WBGetDefaultDisplay(), colormap, szHFG, &(pDialogControl->clrHFG));
541  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrHFG));
542  XParseColor(WBGetDefaultDisplay(), colormap, szHBG, &(pDialogControl->clrHBG));
543  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrHBG));
544  XParseColor(WBGetDefaultDisplay(), colormap, szBD, &(pDialogControl->clrBD));
545 
546  // ---------------------------------------------------------------------------------------
547  // 3D border colors - determine a decent set of border colors for clrBD2 and clrBD3 using
548  // the background color. highlight luminocity will average between black and background
549  // for the shaded color (clrBD3) and between white and background for highlight (clrBD2).
550  // ---------------------------------------------------------------------------------------
551 
552  if((pDialogControl->clrBG.flags & (DoRed | DoGreen | DoBlue)) != (DoRed | DoGreen | DoBlue))
553  {
555  &(pDialogControl->clrBG)); // make sure RGB is correctly assigned
556  }
557 
558  RGB255_FROM_XCOLOR(pDialogControl->clrBG, iR, iG, iB);
559 
560  PXM_RGBToYUV(iR, iG, iB, &iY, &iU, &iV);
561 
562  // the highlight color should be 1/4 of the way between the background color and white, using the same U and V
563 
564  PXM_YUVToRGB((3 * iY + 256) / 4, iU, iV, &iR, &iG, &iB);
565 
566  RGB255_TO_XCOLOR(iR, iG, iB, pDialogControl->clrBD2); // assign new RGB values to the XColor struct
568  &(pDialogControl->clrBD2)); // re-assign pixel element from RGB values
569 
570  // the shaded color should be 3/4 of the way between black and the background color, using the same U and V
571 
572  PXM_YUVToRGB((3 * iY) / 4, iU, iV, &iR, &iG, &iB);
573 
574  RGB255_TO_XCOLOR(iR, iG, iB, pDialogControl->clrBD3); // assign new RGB values to the XColor struct
576  &(pDialogControl->clrBD3)); // re-assign pixel element from RGB values
577 
578  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrBD2));
579  XAllocColor(WBGetDefaultDisplay(), colormap, &(pDialogControl->clrBD3));
580 }
581 
582 static Display *dialog_control_get_display(WBDialogControl *pDialogControl)
583 {
584 Display *pRval = NULL;
585 
586  if(pDialogControl && pDialogControl->pOwner)
587  {
588  pRval = WBGetWindowDisplay(pDialogControl->pOwner->wID);
589  }
590 
591  if(!pRval)
592  {
593  pRval = WBGetDefaultDisplay();
594  }
595 
596  return pRval;
597 }
598 
599 static Window standard_do_create_control(WBDialogControl *pDialogControl,
600  int iX, int iY, int iWidth, int iHeight, int iBorderWidth,
601  const char *szClassName, const char *szTitle, WBWinEvent pCallback)
602 {
603  XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */
604  Display *pDisplay = dialog_control_get_display(pDialogControl);
605 
606  bzero(&xswa, sizeof(xswa));
607 
608  xswa.border_pixel = pDialogControl->clrBD.pixel;
609  xswa.background_pixel = pDialogControl->clrBG.pixel;
610  xswa.colormap = DefaultColormap(pDisplay, DefaultScreen(pDisplay));
611  xswa.bit_gravity = CenterGravity;
612 
613  pDialogControl->wID = XCreateWindow(pDisplay, pDialogControl->pOwner ? pDialogControl->pOwner->wID : 0,
614  iX, iY, iWidth, iHeight,
615  iBorderWidth,
616  DefaultDepth(pDisplay, DefaultScreen(pDisplay)),
617  InputOutput,
618  DefaultVisual(pDisplay, DefaultScreen(pDisplay)),
619  CWBorderPixel | CWBackPixel | CWColormap | CWBitGravity,
620  &xswa);
621  if(pDialogControl->wID <= 0 /* == None */)
622  {
623  return None;
624  }
625 
626  // TODO: standardize this a little better using WBCreateWindow
627 
628  DLGRegisterControlCallback(pDialogControl, szClassName, pCallback); // adds it to the 'WB' window matrix
629  WBSetParentWindow(pDialogControl->wID, pDialogControl->pOwner ? pDialogControl->pOwner->wID : None);
630 
631  // immediately identify this window using window data
632  WBSetWindowData(pDialogControl->wID, 0, (void *)pDialogControl);
633 
634  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
635  "%s - TEMPORARY: creating %s control with caption \"%s\"\n",
636  __FUNCTION__, szClassName, szTitle);
637 
638  pDialogControl->pCaption = WBCopyString(szTitle);
639 // XSetStandardProperties(pDisplay, pDialogControl->wID, szTitle, szTitle, None,
640 // NULL, 0, NULL); // argv, argc, &xsh);
641  // this has been superseded by XSetWMProperties() and should not be used any more
642 
643  WBCreateWindowDefaultGC(pDialogControl->wID, pDialogControl->clrFG.pixel, pDialogControl->clrBG.pixel);
644 
645  return pDialogControl->wID;
646 }
647 
648 // IMPLEMENT_CREATE_CONTROL
649 // static WBDialogControl * do_create_##X(WBDialogControl *pDialogControl,
650 // int iX, int iY, int iWidth, int iHeight,
651 // const char *szClassName, const char *szTitle);
652 
653 static int static_callback(Window wID, XEvent *pEvent);
654 
655 IMPLEMENT_CREATE_CONTROL(FRAME_CONTROL)
656 {
657 BEGIN_CREATE_CONTROL(FRAME_CONTROL);
658 
659  Display *pDisplay = dialog_control_get_display(pDialogControl);
660  int iBorderWidth = 1;
661 
662  pDialogControl->ulFlags &= ~STATIC_TYPEMASK;
663  pDialogControl->ulFlags |= STATIC_Frame;
664 
665  // if 3D border
666  {
667  iBorderWidth = 0;
668  pDialogControl->ulFlags |= STATIC_3DBorder;
669  }
670 
671  // color information for border, foreground, background
672 
673  alloc_control_colors(pDialogControl, "*Dialog.foreground", "*Dialog.background",
674  "*Dialog.foreground", "*Dialog.background",
675  "*Dialog.foreground", "*Dialog.background",
676  "*Dialog.border", 1);
677 
678  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, iBorderWidth,
679  szClassName, szTitle, static_callback)
680  == None)
681  {
682  if(pDialogControl->pPropList)
683  {
684  DLGCDestroyProperties(pDialogControl->pPropList);
685  pDialogControl->pPropList = NULL; // as a matter of course
686  }
687 
688  WBDestroyPointerHashPtr(pDialogControl);
689  WBFree(pDialogControl);
690  return NULL;
691  }
692 
693  if(pDialogControl->pDlgControlEntry &&
695  {
696  // this type of static control can NOT have the focus.
697  pDialogControl->pDlgControlEntry->iFlags &= ~WBDialogEntry_CAN_HAVE_FOCUS; // turn it off
698  }
699 
700  // now allow certain kinds of input messages (I should be able to handle messages at this point)
701  XSelectInput(pDisplay, pDialogControl->wID, WB_STANDARD_INPUT_MASK);
702 
703 
704  if(pDialogControl->pDlgControlEntry &&
705  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
706  {
707  XMapWindow(pDisplay, pDialogControl->wID);
708  }
709 
710  return pDialogControl;
711 }
712 
713 
714 IMPLEMENT_CREATE_CONTROL(TEXT_CONTROL)
715 {
716 BEGIN_CREATE_CONTROL(TEXT_CONTROL);
717 
718  Display *pDisplay = dialog_control_get_display(pDialogControl);
719  int iBorderWidth = 1;
720 
721  pDialogControl->ulFlags &= ~STATIC_TYPEMASK;
722  pDialogControl->ulFlags |= STATIC_Text;
723 
724  // if 3D border
725  {
726  iBorderWidth = 0;
727  pDialogControl->ulFlags |= STATIC_3DBorder;
728  }
729 
730 // // focus
731 // pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_CAN_HAVE_FOCUS;
732 
733  // color information for border, foreground, background
734 
735  alloc_control_colors(pDialogControl, "*Label.foreground", "*Label.background",
736  "*Label.highlightColor", "*Label.highlightBackground",
737  "*Labelframe.highlightColor", "*Labelframe.background", // slightly different
738  "*Labelframe.foreground", 1);
739 
740  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, iBorderWidth,
741  szClassName, szTitle, static_callback)
742  == None)
743  {
744  if(pDialogControl->pPropList)
745  {
746  DLGCDestroyProperties(pDialogControl->pPropList);
747  pDialogControl->pPropList = NULL; // as a matter of course
748  }
749 
750  WBDestroyPointerHashPtr(pDialogControl);
751  WBFree(pDialogControl);
752  return NULL;
753  }
754 
755  if(pDialogControl->pDlgControlEntry &&
757  {
758  // this type of static control can NOT have the focus.
759  pDialogControl->pDlgControlEntry->iFlags &= ~WBDialogEntry_CAN_HAVE_FOCUS; // turn it off
760  }
761 
762  // now allow certain kinds of input messages (I should be able to handle messages at this point)
763  XSelectInput(pDisplay, pDialogControl->wID, WB_STANDARD_INPUT_MASK);
764 
765 
766  if(pDialogControl->pDlgControlEntry &&
767  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
768  {
769  XMapWindow(pDisplay, pDialogControl->wID);
770  }
771 
772  return pDialogControl;
773 }
774 
775 
776 IMPLEMENT_CREATE_CONTROL(ICON_CONTROL)
777 {
778 BEGIN_CREATE_CONTROL(ICON_CONTROL);
779 
780  Display *pDisplay = dialog_control_get_display(pDialogControl);
781  int iBorderWidth = 1;
782 
783  pDialogControl->ulFlags &= ~STATIC_TYPEMASK;
784  pDialogControl->ulFlags |= STATIC_Icon;
785 
786  // if 3D border
787  {
788  iBorderWidth = 0;
789  pDialogControl->ulFlags |= STATIC_3DBorder;
790  }
791 
792 
793  // color information for border, foreground, background
794 
795  alloc_control_colors(pDialogControl, "*Dialog.foreground", "*Dialog.background",
796  "*Dialog.foreground", "*Dialog.background",
797  "*Dialog.foreground", "*Dialog.background",
798  "*Dialog.border", 1);
799 
800  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, iBorderWidth,
801  szClassName, szTitle, static_callback)
802  == None)
803  {
804  if(pDialogControl->pPropList)
805  {
806  DLGCDestroyProperties(pDialogControl->pPropList);
807  pDialogControl->pPropList = NULL; // as a matter of course
808  }
809 
810  WBDestroyPointerHashPtr(pDialogControl);
811  WBFree(pDialogControl);
812  return NULL;
813  }
814 
815  // now allow certain kinds of input messages (I should be able to handle messages at this point)
816 
817  if(pDialogControl->pDlgControlEntry &&
819  {
820  // now allow certain kinds of input messages (I should be able to handle messages at this point)
821  XSelectInput(pDisplay, pDialogControl->wID,
823  }
824  else
825  {
826  XSelectInput(pDisplay, pDialogControl->wID, WB_STANDARD_INPUT_MASK);
827  }
828 
829  // TODO: scan properties for 'ICON' property, load icon, assign to
830  // ((struct _WB_IMAGE_CONTROL_ *)pDialogControl)->pixmap
831 
832  if(pDialogControl->pDlgControlEntry &&
833  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
834  {
835  XMapWindow(pDisplay, pDialogControl->wID);
836  }
837 
838  return pDialogControl;
839 }
840 
841 
842 IMPLEMENT_CREATE_CONTROL(IMAGE_CONTROL)
843 {
844 BEGIN_CREATE_CONTROL(IMAGE_CONTROL);
845 
846  Display *pDisplay = dialog_control_get_display(pDialogControl);
847  int iBorderWidth = 1;
848 
849  pDialogControl->ulFlags &= ~STATIC_TYPEMASK;
850  pDialogControl->ulFlags |= STATIC_Image;
851 
852  // if 3D border
853  {
854  iBorderWidth = 0;
855  pDialogControl->ulFlags |= STATIC_3DBorder;
856  }
857 
858 
859  // color information for border, foreground, background
860 
861  alloc_control_colors(pDialogControl, "*Dialog.foreground", "*Dialog.background",
862  "*Dialog.foreground", "*Dialog.background",
863  "*Dialog.foreground", "*Dialog.background",
864  "*Dialog.border", 1);
865 
866  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, iBorderWidth,
867  szClassName, szTitle, static_callback)
868  == None)
869  {
870  if(pDialogControl->pPropList)
871  {
872  DLGCDestroyProperties(pDialogControl->pPropList);
873  pDialogControl->pPropList = NULL; // as a matter of course
874  }
875 
876  WBDestroyPointerHashPtr(pDialogControl);
877  WBFree(pDialogControl);
878  return NULL;
879  }
880 
881  // now allow certain kinds of input messages (I should be able to handle messages at this point)
882  if(pDialogControl->pDlgControlEntry &&
884  {
885  // now allow certain kinds of input messages (I should be able to handle messages at this point)
886  XSelectInput(pDisplay, pDialogControl->wID,
888  }
889  else
890  {
891  XSelectInput(pDisplay, pDialogControl->wID, WB_STANDARD_INPUT_MASK);
892  }
893 
894  if(pDialogControl->pDlgControlEntry &&
895  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
896  {
897  XMapWindow(pDisplay, pDialogControl->wID);
898  }
899 
900  return pDialogControl;
901 }
902 
903 
904 static int edit_callback(Window wID, XEvent *pEvent);
905 
906 IMPLEMENT_CREATE_CONTROL(EDIT_CONTROL)
907 {
908 BEGIN_CREATE_CONTROL(EDIT_CONTROL);
909 
910  WBEditControl *pPrivate = (WBEditControl *)pDialogControl;
911  Display *pDisplay = dialog_control_get_display(pDialogControl);
912 
913 // pDialogControl->ulFlags &= ~EDIT_TYPEMASK;
914 // pDialogControl->ulFlags |= EDIT_Frame;
915 
916 
917  // focus
919 
920  // private member initialization
921 // pPrivate->pState = NULL; // nothing, yet (until text is assigned)
922  WBInitializeInPlaceTextObject(&(pPrivate->xTextObject), None);
923 
924  // NOTE: it's assumed that vtable will NOT be NULL after calling that...
925 
926 
927  // TODO: determine single/multi line behavior. for now, SINGLE only
928  pPrivate->xTextObject.vtable->set_linefeed(&(pPrivate->xTextObject), LineFeed_NONE); // single-line
929 
930 
931  // color information for border, foreground, background
932 
933  alloc_control_colors(pDialogControl, "*Text.foreground", "*Text.background",
934  "*Text.selectForeground", "*Text.selectBackground",
935  "*Text.activeForeground", "*Text.activeBackground",
936  "*Text.border", 0);
937 
938 // WB_ERROR_PRINT("TEMPORARY: EDIT colors FG=%lxH BG=%lxH HF=%lx HB=%lx AF=%lx AB=%lx\n",
939 // pDialogControl->clrFG.pixel,pDialogControl->clrBG.pixel,
940 // pDialogControl->clrHFG.pixel,pDialogControl->clrHBG.pixel,
941 // pDialogControl->clrAFG.pixel,pDialogControl->clrABG.pixel);
942 
943  // assign highlight colors to text object (other colors obtained from the GC)
944  pPrivate->xTextObject.vtable->highlight_colors(&(pPrivate->xTextObject), pDialogControl->clrHFG, pDialogControl->clrHBG);
945 
946  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 1, // border width is 1
947  szClassName, szTitle, edit_callback)
948  == None)
949  {
950  if(pDialogControl->pPropList)
951  {
952  DLGCDestroyProperties(pDialogControl->pPropList);
953  pDialogControl->pPropList = NULL; // as a matter of course
954  }
955 
956  // destroy any allocated 'text object' stuff thus far
958 
959  WBDestroyPointerHashPtr(pDialogControl);
960  WBFree(pDialogControl);
961  return NULL;
962  }
963 
964  pPrivate->xTextObject.wIDOwner = pDialogControl->wID; // TODO: make assigning this an API function?
965 
966  // this one needs a special cursor
967  WBSetWindowDefaultCursor(pDialogControl->wID, XC_xterm);//tcross);
968 
969  // assign colors to TEXT OBJECT
970 
971  // now allow certain kinds of input messages (I should be able to handle messages at this point)
972  XSelectInput(pDisplay, pDialogControl->wID,
974 
975  if(pDialogControl->pDlgControlEntry &&
976  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
977  {
978  XMapWindow(pDisplay, pDialogControl->wID);
979  }
980 
981  // create timer for cursor blink
982  CreateTimer(pDisplay, pDialogControl->wID, 333333, 1, 1); // TODO: use #define for timer ID
983 
984  return pDialogControl;
985 }
986 
987 
988 static int button_callback(Window wID, XEvent *pEvent);
989 
990 IMPLEMENT_CREATE_CONTROL(PUSHBUTTON_CONTROL)
991 {
992 BEGIN_CREATE_CONTROL(PUSHBUTTON_CONTROL);
993 
994 XFontSet fsBold;
995 
996 
997  Display *pDisplay = dialog_control_get_display(pDialogControl);
998 
999  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1000  pDialogControl->ulFlags |= BUTTON_PushButton;
1001 
1002 
1003  // focus
1005  | WBDialogEntry_PUSHBUTTON; // override 'default' when I have focus
1006 
1007  // color information for border, foreground, background
1008 
1009  alloc_control_colors(pDialogControl, "*Button.foreground", "*Button.background",
1010  "*Button.highlightForeground", "*Button.highlightBackground",
1011  "*Button.activeForeground", "*Button.activeBackground",
1012  "*Button.border", 1);
1013 
1014  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1015  szClassName, szTitle, button_callback)
1016  == None)
1017  {
1018  if(pDialogControl->pPropList)
1019  {
1020  DLGCDestroyProperties(pDialogControl->pPropList);
1021  pDialogControl->pPropList = NULL; // as a matter of course
1022  }
1023 
1024  WBDestroyPointerHashPtr(pDialogControl);
1025  WBFree(pDialogControl);
1026  return NULL;
1027  }
1028 
1029  // assign BOLD font to this one... (TODO: query owner dialog box? get fonts from that?)
1030 
1031  fsBold = WBCopyModifyFontSet(pDisplay, WBGetDefaultFontSet(pDisplay),
1032  0, WBFontFlag_WT_BOLD); // BOLD version
1033 
1034  if(fsBold != None)
1035  {
1036  WBSetWindowFontSet(pDialogControl->wID, fsBold);
1037  }
1038 
1039  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1040  XSelectInput(pDisplay, pDialogControl->wID,
1042 
1043 
1044  if(pDialogControl->pDlgControlEntry &&
1045  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1046  {
1047  XMapWindow(pDisplay, pDialogControl->wID);
1048  }
1049 
1050  return pDialogControl;
1051 }
1052 
1053 
1054 IMPLEMENT_CREATE_CONTROL(DEFPUSHBUTTON_CONTROL)
1055 {
1056 BEGIN_CREATE_CONTROL(DEFPUSHBUTTON_CONTROL);
1057 
1058 XFontSet fsBold;
1059 
1060 
1061  Display *pDisplay = dialog_control_get_display(pDialogControl);
1062 
1063  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1064  pDialogControl->ulFlags |= BUTTON_DefPushButton;
1065 
1066 
1067  // focus
1069  | WBDialogEntry_PUSHBUTTON // override 'default' when I have focus (trivial here)
1071 
1072  // color information for border, foreground, background
1073 
1074  alloc_control_colors(pDialogControl, "*Button.foreground", "*Button.background",
1075  "*Button.highlightForeground", "*Button.highlightBackground",
1076  "*Button.activeForeground", "*Button.activeBackground",
1077  "*Button.border", 1);
1078 
1079  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1080  szClassName, szTitle, button_callback)
1081  == None)
1082  {
1083  if(pDialogControl->pPropList)
1084  {
1085  DLGCDestroyProperties(pDialogControl->pPropList);
1086  pDialogControl->pPropList = NULL; // as a matter of course
1087  }
1088 
1089  WBDestroyPointerHashPtr(pDialogControl);
1090  WBFree(pDialogControl);
1091  return NULL;
1092  }
1093 
1094  // assign BOLD font to this one... (TODO: query owner dialog box? get fonts from that?)
1095 
1096  fsBold = WBCopyModifyFontSet(pDisplay, WBGetDefaultFontSet(pDisplay),
1097  0, WBFontFlag_WT_BOLD); // BOLD version
1098 
1099  if(fsBold != None)
1100  {
1101  WBSetWindowFontSet(pDialogControl->wID, fsBold);
1102  }
1103 
1104  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1105  XSelectInput(pDisplay, pDialogControl->wID,
1107 
1108 
1109  if(pDialogControl->pDlgControlEntry &&
1110  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1111  {
1112  XMapWindow(pDisplay, pDialogControl->wID);
1113  }
1114 
1115  return pDialogControl;
1116 }
1117 
1118 
1119 IMPLEMENT_CREATE_CONTROL(CANCELBUTTON_CONTROL)
1120 {
1121 BEGIN_CREATE_CONTROL(CANCELBUTTON_CONTROL);
1122 
1123 XFontSet fsBold;
1124 
1125 
1126  Display *pDisplay = dialog_control_get_display(pDialogControl);
1127 
1128  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1129  pDialogControl->ulFlags |= BUTTON_CancelButton;
1130 
1131 
1132  // focus
1134  | WBDialogEntry_PUSHBUTTON; // override 'default' when I have focus
1135 
1136  // color information for border, foreground, background
1137 
1138  alloc_control_colors(pDialogControl, "*Button.foreground", "*Button.background",
1139  "*Button.highlightForeground", "*Button.highlightBackground",
1140  "*Button.activeForeground", "*Button.activeBackground",
1141  "*Button.border", 1);
1142 
1143  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1144  szClassName, szTitle, button_callback)
1145  == None)
1146  {
1147  if(pDialogControl->pPropList)
1148  {
1149  DLGCDestroyProperties(pDialogControl->pPropList);
1150  pDialogControl->pPropList = NULL; // as a matter of course
1151  }
1152 
1153  WBDestroyPointerHashPtr(pDialogControl);
1154  WBFree(pDialogControl);
1155  return NULL;
1156  }
1157 
1158  // assign BOLD font to this one... (TODO: query owner dialog box? get fonts from that?)
1159 
1160  fsBold = WBCopyModifyFontSet(pDisplay, WBGetDefaultFontSet(pDisplay),
1161  0, WBFontFlag_WT_BOLD); // BOLD version
1162 
1163  if(fsBold != None)
1164  {
1165  WBSetWindowFontSet(pDialogControl->wID, fsBold);
1166  }
1167 
1168  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1169  XSelectInput(pDisplay, pDialogControl->wID,
1171 
1172 
1173  if(pDialogControl->pDlgControlEntry &&
1174  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1175  {
1176  XMapWindow(pDisplay, pDialogControl->wID);
1177  }
1178 
1179  return pDialogControl;
1180 }
1181 
1182 
1183 IMPLEMENT_CREATE_CONTROL(RADIOBUTTON_CONTROL)
1184 {
1185 BEGIN_CREATE_CONTROL(RADIOBUTTON_CONTROL);
1186 
1187  Display *pDisplay = dialog_control_get_display(pDialogControl);
1188 
1189  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1190  pDialogControl->ulFlags |= BUTTON_RadioButton;
1191 
1192 
1193  // focus
1195 
1196  // color information for border, foreground, background
1197 
1198  alloc_control_colors(pDialogControl, "*Radiobutton.foreground", "*Radiobutton.background",
1199  "*Radiobutton.highlightForeground", "*Radiobutton.highlightBackground",
1200  "*Radiobutton.activeForeground", "*RadioButton.activeBackground",
1201  "*Radiobutton.border", 1);
1202 
1203  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1204  szClassName, szTitle, button_callback)
1205  == None)
1206  {
1207  if(pDialogControl->pPropList)
1208  {
1209  DLGCDestroyProperties(pDialogControl->pPropList);
1210  pDialogControl->pPropList = NULL; // as a matter of course
1211  }
1212 
1213  WBDestroyPointerHashPtr(pDialogControl);
1214  WBFree(pDialogControl);
1215  return NULL;
1216  }
1217 
1218  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1219  XSelectInput(pDisplay, pDialogControl->wID,
1221 
1222 
1223  if(pDialogControl->pDlgControlEntry &&
1224  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1225  {
1226  XMapWindow(pDisplay, pDialogControl->wID);
1227  }
1228 
1229  return pDialogControl;
1230 }
1231 
1232 
1233 IMPLEMENT_CREATE_CONTROL(FIRSTRADIOBUTTON_CONTROL)
1234 {
1235 BEGIN_CREATE_CONTROL(FIRSTRADIOBUTTON_CONTROL);
1236 
1237  Display *pDisplay = dialog_control_get_display(pDialogControl);
1238 
1239  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1240  pDialogControl->ulFlags |= BUTTON_FirstRadioButton;
1241 
1242 
1243  // focus
1245 
1246  // color information for border, foreground, background
1247 
1248  alloc_control_colors(pDialogControl, "*Radiobutton.foreground", "*Radiobutton.background",
1249  "*Radiobutton.highlightForeground", "*Radiobutton.highlightBackground",
1250  "*Radiobutton.activeForeground", "*RadioButton.activeBackground",
1251  "*Radiobutton.border", 1);
1252 
1253  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1254  szClassName, szTitle, button_callback)
1255  == None)
1256  {
1257  if(pDialogControl->pPropList)
1258  {
1259  DLGCDestroyProperties(pDialogControl->pPropList);
1260  pDialogControl->pPropList = NULL; // as a matter of course
1261  }
1262 
1263  WBDestroyPointerHashPtr(pDialogControl);
1264  WBFree(pDialogControl);
1265  return NULL;
1266  }
1267 
1268  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1269  XSelectInput(pDisplay, pDialogControl->wID,
1271 
1272 
1273  if(pDialogControl->pDlgControlEntry &&
1274  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1275  {
1276  XMapWindow(pDisplay, pDialogControl->wID);
1277  }
1278 
1279  return pDialogControl;
1280 }
1281 
1282 
1283 IMPLEMENT_CREATE_CONTROL(CHECKBUTTON_CONTROL)
1284 {
1285 BEGIN_CREATE_CONTROL(CHECKBUTTON_CONTROL);
1286 
1287 
1288  Display *pDisplay = dialog_control_get_display(pDialogControl);
1289 
1290  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1291  pDialogControl->ulFlags |= BUTTON_CheckButton;
1292 
1293 
1294  // focus
1296 
1297  // color information for border, foreground, background
1298 
1299  alloc_control_colors(pDialogControl, "*Checkbutton.foreground", "*Checkbutton.background",
1300  "*Checkbutton.highlightForeground", "*Checkbutton.highlightBackground",
1301  "*Checkbutton.activeForeground", "*CheckButton.activeBackground",
1302  "*Checkbutton.border", 1);
1303 
1304  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1305  szClassName, szTitle, button_callback)
1306  == None)
1307  {
1308  if(pDialogControl->pPropList)
1309  {
1310  DLGCDestroyProperties(pDialogControl->pPropList);
1311  pDialogControl->pPropList = NULL; // as a matter of course
1312  }
1313 
1314  WBDestroyPointerHashPtr(pDialogControl);
1315  WBFree(pDialogControl);
1316  return NULL;
1317  }
1318 
1319  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1320  XSelectInput(pDisplay, pDialogControl->wID,
1322 
1323 
1324  if(pDialogControl->pDlgControlEntry &&
1325  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1326  {
1327  XMapWindow(pDisplay, pDialogControl->wID);
1328  }
1329 
1330  return pDialogControl;
1331 }
1332 
1333 
1334 IMPLEMENT_CREATE_CONTROL(TRISTATEBUTTON_CONTROL)
1335 {
1336 BEGIN_CREATE_CONTROL(TRISTATEBUTTON_CONTROL);
1337 
1338  Display *pDisplay = dialog_control_get_display(pDialogControl);
1339 
1340  pDialogControl->ulFlags &= ~BUTTON_TYPEMASK;
1341  pDialogControl->ulFlags |= BUTTON_TriStateButton;
1342 
1343 
1344  // focus
1346 
1347  // color information for border, foreground, background
1348 
1349  alloc_control_colors(pDialogControl, "*Checkbutton.foreground", "*Checkbutton.background",
1350  "*Checkbutton.highlightForeground", "*Checkbutton.highlightBackground",
1351  "*Checkbutton.activeForeground", "*CheckButton.activeBackground",
1352  "*Checkbutton.border", 1);
1353 
1354  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1355  szClassName, szTitle, button_callback)
1356  == None)
1357  {
1358  if(pDialogControl->pPropList)
1359  {
1360  DLGCDestroyProperties(pDialogControl->pPropList);
1361  pDialogControl->pPropList = NULL; // as a matter of course
1362  }
1363 
1364  WBDestroyPointerHashPtr(pDialogControl);
1365  WBFree(pDialogControl);
1366  return NULL;
1367  }
1368 
1369  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1370  XSelectInput(pDisplay, pDialogControl->wID,
1372 
1373 
1374  if(pDialogControl->pDlgControlEntry &&
1375  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1376  {
1377  XMapWindow(pDisplay, pDialogControl->wID);
1378  }
1379 
1380  return pDialogControl;
1381 }
1382 
1383 
1384 IMPLEMENT_CREATE_CONTROL(HSCROLL_CONTROL)
1385 {
1386 BEGIN_CREATE_CONTROL(HSCROLL_CONTROL);
1387 
1388 
1389 
1390  return NULL; // for now
1391 }
1392 
1393 
1394 IMPLEMENT_CREATE_CONTROL(VSCROLL_CONTROL)
1395 {
1396 BEGIN_CREATE_CONTROL(VSCROLL_CONTROL);
1397 
1398 
1399 
1400  return NULL; // for now
1401 }
1402 
1403 
1404 IMPLEMENT_CREATE_CONTROL(SLIDER_CONTROL)
1405 {
1406 BEGIN_CREATE_CONTROL(SLIDER_CONTROL);
1407 
1408 
1409 
1410  return NULL; // for now
1411 }
1412 
1413 
1414 IMPLEMENT_CREATE_CONTROL(KNOB_CONTROL)
1415 {
1416 BEGIN_CREATE_CONTROL(KNOB_CONTROL);
1417 
1418 
1419 
1420  return NULL; // for now
1421 }
1422 
1423 
1424 static int list_callback(Window wID, XEvent *pEvent);
1425 
1426 IMPLEMENT_CREATE_CONTROL(LIST_CONTROL)
1427 {
1428 BEGIN_CREATE_CONTROL(LIST_CONTROL);
1429 
1430  Display *pDisplay = dialog_control_get_display(pDialogControl);
1431 
1432  pDialogControl->ulFlags |= CONTROL_SupportListInfo;
1433 
1434  // focus
1435  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_CAN_HAVE_FOCUS; // override 'default' when I have focus
1436 
1437 
1438  // color information for border, foreground, background
1439 
1440  alloc_control_colors(pDialogControl, "*List.foreground", "*List.background",
1441  "*List.highlightForeground", "*List.highlightBackground",
1442  "*List.activeForeground", "*List.activeBackground",
1443  "*List.border", 0);
1444 
1445  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1446  szClassName, szTitle, list_callback)
1447  == None)
1448  {
1449  if(pDialogControl->pPropList)
1450  {
1451  DLGCDestroyProperties(pDialogControl->pPropList);
1452  pDialogControl->pPropList = NULL; // as a matter of course
1453  }
1454 
1455  WBDestroyPointerHashPtr(pDialogControl);
1456  WBFree(pDialogControl);
1457  return NULL;
1458  }
1459 
1460  // initialize list element with default settings if not already initialized on window create
1461  if(DLGInitControlListInfoDefault(pDialogControl))
1462 // DLGInitControlListInfo(pDialogControl, ListInfoFlags_SORTED, DLGCDefaultListInfoAllocator, WBFree, NULL, NULL))
1463  {
1464  WB_ERROR_PRINT("%s - Unable to initialize list entry for control\n", __FUNCTION__);
1465  if(pDialogControl->pPropList)
1466  {
1467  DLGCDestroyProperties(pDialogControl->pPropList);
1468  pDialogControl->pPropList = NULL; // as a matter of course
1469  }
1470 
1471  WBSetWindowData(pDialogControl->wID, 0, NULL);
1472  WBDestroyPointerHashPtr(pDialogControl);
1473  WBFree(pDialogControl);
1474  return NULL;
1475  }
1476 
1477  ((WBListControl *)pDialogControl)->fsBold = None; // make sure
1478 
1479 
1480  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1481  XSelectInput(pDisplay, pDialogControl->wID,
1483 
1484 
1485  if(pDialogControl->pDlgControlEntry &&
1486  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1487  {
1488  XMapWindow(pDisplay, pDialogControl->wID);
1489  }
1490 
1491  return pDialogControl;
1492 }
1493 
1494 
1495 static int combo_callback(Window wID, XEvent *pEvent)
1496 {
1497 // Display *pDisplay = WBGetWindowDisplay(wID);
1498  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
1499 
1500 
1501  // special handling for 'destroy'
1502  if(pEvent->type == DestroyNotify &&
1503  pEvent->xdestroywindow.window == wID)
1504  {
1505  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
1506  "%s - DestroyNotify\n", __FUNCTION__);
1507 
1508  WBSetWindowData(wID, 0, NULL);
1509 
1510  if(pDialogControl)
1511  {
1512  WBComboControl *pPrivate = (WBComboControl *)pDialogControl;
1513 
1514  if(pDialogControl->pCaption)
1515  {
1516  WBFree(pDialogControl->pCaption);
1517  }
1518 
1519  if(pDialogControl->pPropList)
1520  {
1521  DLGCDestroyProperties(pDialogControl->pPropList);
1522  pDialogControl->pPropList = NULL; // as a matter of course
1523  }
1524 
1525  // free up privately allocated stuff
1527 
1528  WBDestroyPointerHashPtr(pDialogControl);
1529  WBFree(pDialogControl);
1530  }
1531 
1532  return 1; // handled
1533  }
1534 
1535  return 0; // temporary
1536 }
1537 
1538 IMPLEMENT_CREATE_CONTROL(COMBO_CONTROL)
1539 {
1540 BEGIN_CREATE_CONTROL(COMBO_CONTROL);
1541 
1542  WBComboControl *pPrivate = (WBComboControl *)pDialogControl;
1543  Display *pDisplay = dialog_control_get_display(pDialogControl);
1544 
1545  pDialogControl->ulFlags |= CONTROL_SupportListInfo;
1546 
1547  // focus
1548  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_CAN_HAVE_FOCUS; // override 'default' when I have focus
1549 
1550  WBInitializeInPlaceTextObject(&(pPrivate->xTextObject), None);
1551 
1552  // TODO: determine single/multi line behavior. for now, SINGLE only
1553  pPrivate->xTextObject.vtable->set_linefeed(&(pPrivate->xTextObject), LineFeed_NONE); // single-line
1554 
1555 
1556  // color information for border, foreground, background
1557 
1558  alloc_control_colors(pDialogControl, "*Combo.foreground", "*Combo.background",
1559  "*Combo.highlightForeground", "*Combo.highlightBackground",
1560  "*Combo.activeForeground", "*Combo.activeBackground",
1561  "*Combo.border", 0);
1562 
1563  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1564  szClassName, szTitle, combo_callback)
1565  == None)
1566  {
1567  if(pDialogControl->pPropList)
1568  {
1569  DLGCDestroyProperties(pDialogControl->pPropList);
1570  pDialogControl->pPropList = NULL; // as a matter of course
1571  }
1572 
1573  // destroy any allocated stuff thus far
1574  WBDestroyInPlaceTextObject(&(pPrivate->xTextObject)); // by convention
1575 
1576  WBDestroyPointerHashPtr(pDialogControl);
1577  WBFree(pDialogControl);
1578  return NULL;
1579  }
1580 
1581  pPrivate->xTextObject.wIDOwner = pDialogControl->wID; // TODO: make assigning this an API function?
1582 
1583 
1584 // // initialize list element with default settings if not already initialized on window create
1585 // if(DLGInitControlListInfoDefault(pDialogControl))
1587 // {
1588 // WB_ERROR_PRINT("%s - Unable to initialize list entry for control\n", __FUNCTION__);
1589 // if(pDialogControl->pPropList)
1590 // DLGCDestroyProperties(pDialogControl->pPropList);
1591 //
1592 // WBSetWindowData(wID, 0, NULL);
1593 // WBDestroyPointerHashPtr(pDialogControl);
1594 // WBFree(pDialogControl);
1595 // return NULL;
1596 // }
1597 
1598  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1599  XSelectInput(pDisplay, pDialogControl->wID,
1601 
1602 
1603  if(pDialogControl->pDlgControlEntry &&
1604  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1605  {
1606  XMapWindow(pDisplay, pDialogControl->wID);
1607  }
1608 
1609  return pDialogControl;
1610 }
1611 
1612 
1613 static int tree_callback(Window wID, XEvent *pEvent);
1614 
1615 IMPLEMENT_CREATE_CONTROL(TREE_CONTROL)
1616 {
1617 BEGIN_CREATE_CONTROL(TREE_CONTROL);
1618 
1619  Display *pDisplay = dialog_control_get_display(pDialogControl);
1620 
1621  pDialogControl->ulFlags |= CONTROL_SupportListInfo;
1622 
1623  // focus
1624  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_CAN_HAVE_FOCUS; // override 'default' when I have focus
1625 
1626 
1627  // color information for border, foreground, background
1628 
1629  alloc_control_colors(pDialogControl, "*List.foreground", "*List.background",
1630  "*List.highlightForeground", "*List.highlightBackground",
1631  "*List.activeForeground", "*List.activeBackground",
1632  "*List.border", 0);
1633 
1634  if(standard_do_create_control(pDialogControl, iX, iY, iWidth, iHeight, 0, // border width is zero
1635  szClassName, szTitle, tree_callback)
1636  == None)
1637  {
1638  if(pDialogControl->pPropList)
1639  {
1640  DLGCDestroyProperties(pDialogControl->pPropList);
1641  pDialogControl->pPropList = NULL; // as a matter of course
1642  }
1643 
1644  WBDestroyPointerHashPtr(pDialogControl);
1645  WBFree(pDialogControl);
1646  return NULL;
1647  }
1648 
1649  // initialize list element with default settings if not already initialized on window create
1650  if(DLGInitControlListInfoDefault(pDialogControl))
1651 // DLGInitControlListInfo(pDialogControl, ListInfoFlags_SORTED, DLGCDefaultListInfoAllocator, WBFree, NULL, NULL))
1652  {
1653  if(pDialogControl->pPropList)
1654  {
1655  DLGCDestroyProperties(pDialogControl->pPropList);
1656  }
1657 
1658  WBSetWindowData(pDialogControl->wID, 0, NULL);
1659  WBDestroyPointerHashPtr(pDialogControl);
1660  WBFree(pDialogControl);
1661  return NULL;
1662  }
1663 
1664  ((WBTreeControl *)pDialogControl)->fsBold = None;
1665 
1666  // now allow certain kinds of input messages (I should be able to handle messages at this point)
1667  XSelectInput(pDisplay, pDialogControl->wID,
1669 
1670 
1671  if(pDialogControl->pDlgControlEntry &&
1672  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE))
1673  {
1674  XMapWindow(pDisplay, pDialogControl->wID);
1675  }
1676 
1677  return pDialogControl;
1678 }
1679 
1680 
1681 static int combo_tree_callback(Window wID, XEvent *pEvent)
1682 {
1683  return 0; // temporary
1684 }
1685 
1686 IMPLEMENT_CREATE_CONTROL(COMBOTREE_CONTROL)
1687 {
1688 BEGIN_CREATE_CONTROL(COMBOTREE_CONTROL);
1689 
1690  int (*x)(Window wID, XEvent *pEvent) WB_UNUSED = NULL;
1691 
1692  x = combo_tree_callback;
1693 
1694 
1695 
1696  return NULL; // for now
1697 }
1698 
1699 
1700 static int file_list_callback(Window wID, XEvent *pEvent);
1701 
1702 IMPLEMENT_CREATE_CONTROL(FILE_LIST_CONTROL)
1703 {
1704 BEGIN_CREATE_CONTROL(FILE_LIST_CONTROL);
1705 
1706 int iVisible = pDialogControl->pDlgControlEntry &&
1707  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE);
1708 
1709  if(iVisible)
1710  {
1711  pDialogControl->pDlgControlEntry->iFlags &= ~ WBDialogEntry_VISIBLE; // turn off visibility first
1712  }
1713 
1714  pDialogControl = do_create_LIST_CONTROL(pDialogControl, iX, iY, iWidth, iHeight, szClassName, szTitle);
1715  // these are very similar so use the LIST CONTROL create method. Initially, the 'list control'
1716  // callback is assigned. I must immediately assign the correct proc (and class name) after it returns.
1717 
1718  if(pDialogControl)
1719  {
1720  pDialogControl->aClass = aThis; // re-define the correct class
1721  DLGRegisterControlCallback(pDialogControl, szClassName, file_list_callback); // use this callback
1722 
1723  DLGModifyControlListInfo(pDialogControl, 0, 0, 0, 0, 0, 0,
1724  1, FileListControlDisplayProc, // only modify the display proc
1725  0, 0);
1726 
1727  if(iVisible)
1728  {
1729  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_VISIBLE; // turn visibility back on
1730  XMapWindow(WBGetWindowDisplay(pDialogControl->wID), pDialogControl->wID); // now show it
1731  }
1732  }
1733 
1734  return pDialogControl;
1735 }
1736 
1737 
1738 static int file_combo_callback(Window wID, XEvent *pEvent)
1739 {
1740 // return 0; // temporary
1741 
1742  // for all unhandled messages, call the 'combo_callback'
1743  // this takes care of things that are common to both FILE COMBO and the COMBO handler
1744 
1745  return combo_callback(wID, pEvent);
1746 }
1747 
1748 IMPLEMENT_CREATE_CONTROL(FILE_COMBO_CONTROL)
1749 {
1750 BEGIN_CREATE_CONTROL(FILE_COMBO_CONTROL);
1751 
1752 int iVisible = pDialogControl->pDlgControlEntry &&
1753  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE);
1754 
1755  if(iVisible)
1756  {
1757  pDialogControl->pDlgControlEntry->iFlags &= ~ WBDialogEntry_VISIBLE; // turn off visibility first
1758  }
1759 
1760  pDialogControl = do_create_COMBO_CONTROL(pDialogControl, iX, iY, iWidth, iHeight, szClassName, szTitle);
1761  // these are very similar so use the COMBO CONTROL create method. Initially, the 'combo control'
1762  // callback is assigned. I must immediately assign the correct proc (and class name) after it returns.
1763 
1764  if(pDialogControl)
1765  {
1766  pDialogControl->aClass = aThis; // re-define the correct class
1767  DLGRegisterControlCallback(pDialogControl, szClassName, file_combo_callback); // use this callback
1768 
1769  if(iVisible)
1770  {
1771  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_VISIBLE; // turn visibility back on
1772  XMapWindow(WBGetWindowDisplay(pDialogControl->wID), pDialogControl->wID); // now show it
1773  }
1774  }
1775 
1776  return pDialogControl;
1777 }
1778 
1779 
1780 static int path_tree_callback(Window wID, XEvent *pEvent);
1781 
1782 IMPLEMENT_CREATE_CONTROL(PATH_TREE_CONTROL)
1783 {
1784 BEGIN_CREATE_CONTROL(PATH_TREE_CONTROL);
1785 
1786 int iVisible = pDialogControl->pDlgControlEntry &&
1787  (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_VISIBLE);
1788 
1789  if(iVisible)
1790  {
1791  pDialogControl->pDlgControlEntry->iFlags &= ~ WBDialogEntry_VISIBLE; // turn off visibility first
1792  }
1793 
1794  pDialogControl = do_create_TREE_CONTROL(pDialogControl, iX, iY, iWidth, iHeight, szClassName, szTitle);
1795  // these are very similar so use the TREE CONTROL create method. Initially, the 'tree control'
1796  // callback is assigned. I must immediately assign the correct proc (and class name) after it returns.
1797 
1798  if(pDialogControl)
1799  {
1800  pDialogControl->aClass = aThis; // re-define the correct class
1801  DLGRegisterControlCallback(pDialogControl, szClassName, path_tree_callback); // use this callback
1802 
1803  if(iVisible)
1804  {
1805  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_VISIBLE; // turn visibility back on
1806  XMapWindow(WBGetWindowDisplay(pDialogControl->wID), pDialogControl->wID); // now show it
1807  }
1808  }
1809 
1810  return pDialogControl;
1811 }
1812 
1813 
1814 IMPLEMENT_CREATE_CONTROL(TAB_CONTROL)
1815 {
1816 BEGIN_CREATE_CONTROL(TAB_CONTROL);
1817 
1818 
1819 
1820  return NULL; // for now
1821 }
1822 
1823 
1824 
1825 // callbacks
1826 
1827 static int StaticDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
1828  Window wID, WBDialogControl *pSelf);
1829 
1830 static int static_callback(Window wID, XEvent *pEvent)
1831 {
1832  Display *pDisplay = WBGetWindowDisplay(wID);
1833  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
1834 
1835  if(pDialogControl && pEvent->type == Expose)
1836  {
1837  return StaticDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl);
1838  }
1839 
1840  // special handling for images with mouse click/drag
1841 
1842  if(pEvent->type == ButtonPress ||
1843  pEvent->type == ButtonRelease ||
1844  pEvent->type == MotionNotify)
1845  {
1846  return 0; // not handled (use WB_POINTER messages generated by toolkit)
1847  }
1848  else if(pEvent->type == KeyPress || pEvent->type == KeyRelease)
1849  {
1850  return 0; // NOT handled (use WB_CHAR messages instead)
1851  }
1852 
1853  if(pEvent->type == ClientMessage &&
1854  pEvent->xclient.type == aWB_POINTER &&
1855  pDialogControl != NULL)
1856  {
1857  if(pDialogControl->aClass == aIMAGE_CONTROL) // images are 'clickable' and 'draggable'
1858  {
1859  if(pEvent->xclient.data.l[0] == WB_POINTER_CLICK &&
1860  pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // only left-click
1861  pEvent->xclient.data.l[2] == 0) // no ctrl/alt/shift modifiers
1862  {
1864  pDialogControl->pDlgControlEntry->iID,
1865  WBCreatePointerHash(pDialogControl),
1866  pEvent->xclient.data.l[3] - 2, // X coordinate (offset by 2; see StaticDoExposeEvent)
1867  pEvent->xclient.data.l[4] - 2); // Y coordinate
1868 
1869  return 1; // handled
1870  }
1871  else if(pEvent->xclient.data.l[0] == WB_POINTER_DBLCLICK &&
1872  pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // only left-click
1873  pEvent->xclient.data.l[2] == 0) // no ctrl/alt/shift modifiers
1874  {
1876  pDialogControl->pDlgControlEntry->iID,
1877  WBCreatePointerHash(pDialogControl),
1878  pEvent->xclient.data.l[3] - 2, // X coordinate (offset by 2; see StaticDoExposeEvent)
1879  pEvent->xclient.data.l[4] - 2); // Y coordinate
1880 
1881  return 1; // handled
1882  }
1883  else if(pEvent->xclient.data.l[0] == WB_POINTER_MOVE &&
1884  pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // only left-click
1885  pEvent->xclient.data.l[2] == 0) // no ctrl/alt/shift modifiers
1886  {
1888  pDialogControl->pDlgControlEntry->iID,
1889  WBCreatePointerHash(pDialogControl),
1890  pEvent->xclient.data.l[3] - 2, // X coordinate (offset by 2; see StaticDoExposeEvent)
1891  pEvent->xclient.data.l[4] - 2); // Y coordinate
1892 
1893  return 1; // handled
1894  }
1895  else if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG &&
1896  pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // only left-click
1897  pEvent->xclient.data.l[2] == 0) // no ctrl/alt/shift modifiers
1898  {
1899  return (int)wID; // to support mouse-dragging
1900  }
1901 
1902  return 0; // not handled
1903  }
1904  }
1905 
1906 
1907  // special handling for 'destroy'
1908  if(pEvent->type == DestroyNotify &&
1909  pEvent->xdestroywindow.window == wID)
1910  {
1911  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
1912  "%s - DestroyNotify\n", __FUNCTION__);
1913 
1914  WBSetWindowData(wID, 0, NULL);
1915 
1916  if(pDialogControl)
1917  {
1918  if(pDialogControl->aClass == aICON_CONTROL ||
1919  pDialogControl->aClass == aIMAGE_CONTROL)
1920  {
1921 
1922  Pixmap pxOld = ((struct _WB_IMAGE_CONTROL_ *)pDialogControl)->pixmap;
1923  Pixmap pxOld2 = ((struct _WB_IMAGE_CONTROL_ *)pDialogControl)->pixmap2;
1924 
1925  ((struct _WB_IMAGE_CONTROL_ *)pDialogControl)->pixmap = None;
1926  ((struct _WB_IMAGE_CONTROL_ *)pDialogControl)->pixmap2 = None;
1927 
1928  if(pxOld != None)
1929  {
1931  if(!pDisplay)
1932  {
1933  XFreePixmap(WBGetDefaultDisplay(), pxOld);
1934  }
1935  else
1936  {
1937  XFreePixmap(pDisplay, pxOld);
1938  }
1940  }
1941 
1942  if(pxOld2 != None)
1943  {
1945  if(!pDisplay)
1946  {
1947  XFreePixmap(WBGetDefaultDisplay(), pxOld2);
1948  }
1949  else
1950  {
1951  XFreePixmap(pDisplay, pxOld2);
1952  }
1954  }
1955  }
1956 
1957  if(pDialogControl->pCaption)
1958  {
1959  WBFree(pDialogControl->pCaption);
1960  }
1961 
1962  if(pDialogControl->pPropList)
1963  {
1964  DLGCDestroyProperties(pDialogControl->pPropList);
1965  pDialogControl->pPropList = NULL; // as a matter of course
1966  }
1967 
1968  WBDestroyPointerHashPtr(pDialogControl);
1969  WBFree(pDialogControl);
1970  }
1971 
1972  return 1;
1973  }
1974 
1975  return 0; // not handled
1976 }
1977 
1978 
1979 static int EditDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
1980  Window wID, WBDialogControl *pSelf);
1981 static int EditDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
1982  Window wID, WBDialogControl *pSelf);
1983 static int EditDoPointerEvent(XClientMessageEvent *pEvent, Display *pDisplay,
1984  Window wID, WBDialogControl *pSelf);
1985 
1986 static int edit_callback(Window wID, XEvent *pEvent)
1987 {
1988  int iRval = 0;
1989  Atom aNotification = None;
1990  Display *pDisplay = WBGetWindowDisplay(wID);
1991  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
1992  WBEditControl *pPrivate = (WBEditControl *)pDialogControl;
1993 // char tbuf[32];
1994 // int nChar = sizeof(tbuf);
1995 
1996 
1997  if(pDialogControl && pEvent->type == Expose)
1998  {
1999  return EditDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl);
2000  }
2001 
2002  // special handling for 'destroy'
2003  if(pEvent->type == DestroyNotify &&
2004  pEvent->xdestroywindow.window == wID)
2005  {
2006  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2007  "%s - DestroyNotify\n", __FUNCTION__);
2008 
2009  WBSetWindowData(wID, 0, NULL);
2010 
2011  if(pDialogControl)
2012  {
2013  WBEditControl *pPrivate = (WBEditControl *)pDialogControl;
2014 
2015  if(pDialogControl->pCaption)
2016  {
2017  WBFree(pDialogControl->pCaption);
2018  }
2019 
2020  if(pDialogControl->pPropList)
2021  {
2022  DLGCDestroyProperties(pDialogControl->pPropList);
2023  pDialogControl->pPropList = NULL; // as a matter of course
2024  }
2025 
2026  DeleteTimer(pDisplay, wID, 1); // TODO: use #define for timer ID
2027 
2028  // free up privately allocated stuff
2029  WBDestroyInPlaceTextObject(&(pPrivate->xTextObject)); // destroy in-place text object
2030 
2031  WBDestroyPointerHashPtr(pDialogControl);
2032  WBFree(pDialogControl);
2033  }
2034 
2035  return 1; // handled
2036  }
2037 
2038  // MOUSE/KEYBOARD INPUT
2039  if(pEvent->type == ButtonPress ||
2040  pEvent->type == ButtonRelease ||
2041  pEvent->type == MotionNotify)
2042  {
2043  return 0; // not handled (use WB_POINTER messages generated by toolkit)
2044  }
2045  else if(pEvent->type == KeyPress || pEvent->type == KeyRelease)
2046  {
2047  return 0; // NOT handled (use WB_CHAR messages instead)
2048  }
2049 
2050  // CLIENT MESSAGE
2051  else if(pEvent->type == ClientMessage)
2052  {
2053  // ClientMessage events - I want WB_CHAR and WB_POINTER
2054 
2055  if(pEvent->xclient.message_type == aWB_CHAR)
2056  {
2057  iRval = EditDoCharEvent(&(pEvent->xclient), pDisplay, wID, pDialogControl);
2058 
2059  if(iRval > 0)
2060  {
2061  aNotification = aTEXT_CHANGED;
2062  }
2063  else if(iRval < 0) // key handled, text NOT changed
2064  {
2065  iRval = 1; // to indicate that no further key processing is needed
2066  }
2067  }
2068  else if(pEvent->xclient.message_type == aWB_POINTER)
2069  {
2070  iRval = EditDoPointerEvent(&(pEvent->xclient), pDisplay, wID, pDialogControl);
2071 
2072  if(iRval) // "handled"
2073  {
2074  aNotification = aTEXT_CHANGED; // TODO: is this necessary??
2075  }
2076  }
2077  // PROPERTY NOTIFICATIONS - special handling for 'CAPTION' assignments
2078  else if(pEvent->xclient.message_type == aDLGC_PROP_NOTIFY)
2079  {
2080  // if I change the 'caption' property I will need to update the xTextObject accordingly
2081 
2082  if(pEvent->xclient.data.l[0] == aDLGC_CAPTION)
2083  {
2084 // WB_ERROR_PRINT("TEMPORARY: %s - caption notification \"%s\"\n", __FUNCTION__, pDialogControl->pCaption);
2085 
2086  // mirror the text within the TEXT_OBJECT
2087  pPrivate->xTextObject.vtable->set_text(&(pPrivate->xTextObject), pDialogControl->pCaption, 0);
2088 
2089  // invalidate the entire window if not already done
2090  if(WBIsMapped(pDisplay, wID)) // if I'm visible...
2091  {
2092  WBInvalidateGeom(wID, NULL, 1); // paint it now
2093  }
2094  else
2095  {
2096  WBInvalidateGeom(wID, NULL, 0); // just invalidate it
2097  }
2098  }
2099  }
2100  else if(pEvent->xclient.message_type == aWB_TIMER)
2101  {
2102  int bHasFocus = pDialogControl->pDlgControlEntry
2103  ? pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_HAS_FOCUS
2104  : 0;
2105 
2106  pPrivate->xTextObject.vtable->cursor_blink(&(pPrivate->xTextObject), bHasFocus);
2107 
2108  iRval = 1; // handled
2109 // aNotification = None;
2110  }
2111  else
2112  {
2113  iRval = 0; // NOT handled
2114  }
2115  }
2116  else
2117  {
2118  iRval = 0; // not handled (default case)
2119  }
2120 
2121 
2122  // *********************
2123  // CONTROL NOTIFICATIONS
2124  // *********************
2125 
2126  if(iRval && aNotification != None &&
2127  pDialogControl->pOwner &&
2128  pDialogControl->pDlgControlEntry)
2129  {
2130  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2131  "%s:%d - Post Event: %08xH %08xH %08xH %pH\n", __FUNCTION__, __LINE__,
2132  (int)aCONTROL_NOTIFY, (int)aNotification,
2133  (int)pDialogControl->pDlgControlEntry->iID, pDialogControl);
2134 
2135  DLGNotifyOwnerAsync(pDialogControl, aCONTROL_NOTIFY, aNotification,
2136  pDialogControl->pDlgControlEntry->iID,
2137  WBCreatePointerHash(pDialogControl), 0, 0);
2138  }
2139 
2140  return iRval; // 0 if not handled, 1 if handled
2141 }
2142 
2143 
2144 static int PushButtonDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
2145  Window wID, WBDialogControl *pSelf); // these are different
2146 static int ButtonDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
2147  Window wID, WBDialogControl *pSelf);
2148 static void ManageRadioButtonGroupSelectState(WBDialogControl *pDialogControl);
2149 
2150 static int ButtonHandleCheckEvent(Display *pDisplay, Window wID, WBDialogControl *pDialogControl, int iType, int iCheck)
2151 {
2152  // for now, I use the type indicated by 'ulFlags' in case I have a control
2153  // of a different class that behaves as one of these kinds of buttons
2154 
2155  if(iType == BUTTON_CheckButton || iType == BUTTON_TriStateButton)
2156  {
2157  if(pDialogControl->pDlgControlEntry &&
2158  (iType != BUTTON_TriStateButton || !(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_TRISTATE)))
2159  {
2160  if(iCheck < 0 || // toggle
2161  (iCheck > 0 && !(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_CHECKED)) || // set
2162  (iCheck == 0 && (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_CHECKED))) // clear
2163  pDialogControl->pDlgControlEntry->iFlags ^= WBDialogEntry_CHECKED;
2164  // post a notify message
2165 
2166  DLGNotifyOwner(pDialogControl, aBUTTON_PRESS,
2167  (long)(pDialogControl->pDlgControlEntry ? pDialogControl->pDlgControlEntry->iID : pDialogControl->wID),
2168  WBCreatePointerHash(pDialogControl->pDlgControlEntry), 0, 0, 0);
2169 
2170  WBInvalidateRect(wID, NULL, 0);
2171  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2172 
2173  return 1; // handled!
2174  }
2175  }
2176  else if(iType == BUTTON_RadioButton || iType == BUTTON_FirstRadioButton)
2177  {
2178  if(pDialogControl->pDlgControlEntry)
2179  {
2180  // FIRST, run through all of the radio buttons in this 'group' and fix 'em
2181  ManageRadioButtonGroupSelectState(pDialogControl);
2182 
2183  // NEXT, if the check state changed, fix it and notify everyone
2184  if(!(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_CHECKED))
2185  {
2186  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_CHECKED;
2187  // post a notify message
2188 
2189  DLGNotifyOwner(pDialogControl, aBUTTON_PRESS,
2190  (long)(pDialogControl->pDlgControlEntry ? pDialogControl->pDlgControlEntry->iID : pDialogControl->wID),
2191  WBCreatePointerHash(pDialogControl->pDlgControlEntry), 0, 0, 0);
2192 
2193  WBInvalidateRect(wID, NULL, 0);
2194  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2195  }
2196 
2197  return 1; // handled!
2198  }
2199  }
2200 
2201  return 0; // NOT handled
2202 }
2203 
2204 static int button_callback(Window wID, XEvent *pEvent)
2205 {
2206 Display *pDisplay = WBGetWindowDisplay(wID);
2207 WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
2208 int iType;
2209 
2210 
2211  if(pDialogControl && pEvent->type == Expose)
2212  {
2213  int iType = pDialogControl->ulFlags & BUTTON_TYPEMASK;
2214 
2215  if(iType == BUTTON_PushButton || iType == BUTTON_DefPushButton
2216  || iType == BUTTON_CancelButton)
2217  {
2218  // pushbuttons have their own appearance so they must be painted differently
2219 
2220  return PushButtonDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl); // temporary
2221  }
2222 
2223  // other buttons are some kind of gadget plus text, so they paint with the same proc
2224  return ButtonDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl); // temporary
2225  }
2226 
2227  // special handling for 'destroy'
2228  if(pEvent->type == DestroyNotify &&
2229  pEvent->xdestroywindow.window == wID)
2230  {
2231  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2232  "%s - DestroyNotify\n", __FUNCTION__);
2233 
2234  WBSetWindowData(wID, 0, NULL);
2235 
2236  if(pDialogControl)
2237  {
2238  if(pDialogControl->aClass == aPUSHBUTTON_CONTROL ||
2239  pDialogControl->aClass == aDEFPUSHBUTTON_CONTROL ||
2240  pDialogControl->aClass == aCANCELBUTTON_CONTROL)
2241  {
2242  Pixmap pxOld = ((struct _WB_PUSHBUTTON_CONTROL_ *)pDialogControl)->pixmap;
2243 
2244  ((struct _WB_PUSHBUTTON_CONTROL_ *)pDialogControl)->pixmap = None;
2245 
2246  if(pxOld != None)
2247  {
2249  if(!pDisplay)
2250  {
2251  XFreePixmap(WBGetDefaultDisplay(), pxOld);
2252  }
2253  else
2254  {
2255  XFreePixmap(pDisplay, pxOld);
2256  }
2258  }
2259  }
2260 
2261  if(pDialogControl->pCaption)
2262  {
2263  WBFree(pDialogControl->pCaption);
2264  }
2265 
2266  if(pDialogControl->pPropList)
2267  {
2268  DLGCDestroyProperties(pDialogControl->pPropList);
2269  pDialogControl->pPropList = NULL; // as a matter of course
2270  }
2271 
2272  WBDestroyPointerHashPtr(pDialogControl);
2273  WBFree(pDialogControl);
2274  }
2275 
2276  return 1;
2277  }
2278 
2279  // CONTROL NOTIFICATIONS
2280 
2281  if(pDialogControl->pOwner &&
2282  pDialogControl->pDlgControlEntry)
2283  {
2284  if(pEvent->type == ButtonPress)
2285  {
2286  // button press event - what kind of button am I?
2287  if((pDialogControl->aClass == aPUSHBUTTON_CONTROL ||
2288  pDialogControl->aClass == aDEFPUSHBUTTON_CONTROL ||
2289  pDialogControl->aClass == aCANCELBUTTON_CONTROL)
2290  && ((XButtonEvent *)pEvent)->button == 1) // left button only
2291  {
2292  // re-paint button "pressed"
2293  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_PRESSED;
2294 
2295  WB_ERROR_PRINT("TEMPORARY: %s - button press\n", __FUNCTION__);
2296 
2297  WBInvalidateRect(wID, NULL, 0);
2298  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2299 
2300  return 0; // not handled - button release will activate these buttons (is this right?)
2301  }
2302 
2303  // TODO: ALSO handle pushbutton, defpushbutton, cancelbutton based on
2304  // the type, not the class.
2305 
2306  iType = pDialogControl->ulFlags & BUTTON_TYPEMASK; // TODO: use the class or the type?
2307 
2308  if((iType == BUTTON_CheckButton || iType == BUTTON_TriStateButton ||
2309  iType == BUTTON_RadioButton || iType == BUTTON_FirstRadioButton) &&
2310  ((XButtonEvent *)pEvent)->button == 1) // left button only
2311  {
2312  if(ButtonHandleCheckEvent(pDisplay, wID, pDialogControl, iType, -1)) // flip check state for checkbox; click for radio
2313  {
2314  return 1;
2315  }
2316  }
2317  }
2318  else if(pEvent->type == ButtonRelease)
2319  {
2320  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Mouse,
2321  "%s - BUTTON RELEASE for BUTTON %d\n",
2322  __FUNCTION__, ((XButtonEvent *)pEvent)->button);
2323 
2324  // for pushbuttons, kick an even notifier upstairs to the owning window/control
2325  if((pDialogControl->aClass == aPUSHBUTTON_CONTROL ||
2326  pDialogControl->aClass == aDEFPUSHBUTTON_CONTROL ||
2327  pDialogControl->aClass == aCANCELBUTTON_CONTROL)
2328  && ((XButtonEvent *)pEvent)->button == 1) // left button only
2329  {
2331  pDialogControl->pDlgControlEntry->iID,
2332  WBCreatePointerHash(pDialogControl), 0, 0);
2333 
2334  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2335  "%s:%d - Post Event: %08xH %08xH %08xH %pH\n", __FUNCTION__, __LINE__,
2336  (int)aCONTROL_NOTIFY, (int)aBUTTON_PRESS,
2337  (int)pDialogControl->pDlgControlEntry->iID, pDialogControl);
2338 
2339 // WBEndModal(wID, pItem->iAction);
2340 
2341  if(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_PRESSED)
2342  {
2343  pDialogControl->pDlgControlEntry->iFlags &= ~WBDialogEntry_PRESSED; // flip the bit back off
2344 
2345  WBInvalidateRect(wID, NULL, 0);
2346  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2347  }
2348 
2349  return 1; // handled
2350  }
2351  }
2352  else if(pEvent->type == KeyPress)
2353  {
2354  // certain key press events SHOULD cause me to do something, like "press"
2355  // the button and give positive feedback.
2356 
2357  // TODO: implement spacebar and enter key doing this
2358 
2359  if(pDialogControl->aClass == aPUSHBUTTON_CONTROL ||
2360  pDialogControl->aClass == aDEFPUSHBUTTON_CONTROL ||
2361  pDialogControl->aClass == aCANCELBUTTON_CONTROL)
2362  {
2363  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, NULL, NULL, &iACS);
2364 
2365  WB_ERROR_PRINT("TEMPORARY: %s- keydown event, %d iACS=%d\n", __FUNCTION__, iKey, iACS);
2366 
2367  if((iKey == ' ' || iKey == '\n' || iKey == '\r')
2368  && iACS == 0 && pDialogControl->pDlgControlEntry)
2369  {
2370 // WB_ERROR_PRINT("TEMPORARY: %s - key press\n", __FUNCTION__);
2371 
2372  pDialogControl->pDlgControlEntry->iFlags |= WBDialogEntry_PRESSED;
2373 
2374  WBInvalidateRect(wID, NULL, 0);
2375  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2376 
2377 // pDialogControl->pDlgControlEntry->iFlags &= ~WBDialogEntry_PRESSED; // flip the bit back off
2378  }
2379 
2380  return 1; // handled
2381  }
2382 
2383  // TODO: ALSO handle pushbutton, defpushbutton, cancelbutton based on
2384  // the type, not the class.
2385 
2386  iType = pDialogControl->ulFlags & BUTTON_TYPEMASK; // TODO: use the class or the type?
2387 
2388  if(iType == BUTTON_CheckButton || iType == BUTTON_TriStateButton ||
2389  iType == BUTTON_RadioButton || iType == BUTTON_FirstRadioButton)
2390  {
2391  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, NULL, NULL, &iACS);
2392 
2393  WB_ERROR_PRINT("TEMPORARY: %s- keydown event, %d iACS=%d\n", __FUNCTION__, iKey, iACS);
2394 
2395  if((iKey == ' ' || iKey == '\n' || iKey == '\r')
2396  && iACS == 0 && pDialogControl->pDlgControlEntry)
2397  {
2398  if(ButtonHandleCheckEvent(pDisplay, wID, pDialogControl, iType, -1)) // flip check state for checkbox; click for radio
2399  {
2400  return 1;
2401  }
2402  }
2403  }
2404  }
2405  else if(pEvent->type == KeyRelease)
2406  {
2407  // KeyRelease
2408 
2409  // KeyPress - space bar will toggle the button or press it (as required)
2410  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, NULL, NULL, &iACS);
2411 
2412  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2413  "%s - KEY RELEASE for KEY %d\n",
2414  __FUNCTION__, ((XKeyEvent *)pEvent)->keycode);
2415 
2416  if((pDialogControl->aClass == aPUSHBUTTON_CONTROL ||
2417  pDialogControl->aClass == aDEFPUSHBUTTON_CONTROL ||
2418  pDialogControl->aClass == aCANCELBUTTON_CONTROL) &&
2419  iACS == 0 &&
2420  (iKey == ' ' || iKey == '\n' || iKey == '\r')) // space bar, enter, return
2421  {
2423  pDialogControl->pDlgControlEntry->iID,
2424  WBCreatePointerHash(pDialogControl), 0, 0);
2425 
2426  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2427  "%s:%d - Post Event: %08xH %08xH %08xH %pH\n", __FUNCTION__, __LINE__,
2428  (int)aCONTROL_NOTIFY, (int)aBUTTON_PRESS,
2429  (int)pDialogControl->pDlgControlEntry->iID, pDialogControl);
2430 
2431  if(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_PRESSED)
2432  {
2433  pDialogControl->pDlgControlEntry->iFlags &= ~WBDialogEntry_PRESSED; // flip the bit back off
2434 
2435  WBInvalidateRect(wID, NULL, 0);
2436  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2437  }
2438 
2439 // WBEndModal(wID, pItem->iAction);
2440  return 1; // handled
2441  }
2442  }
2443  else if(pEvent->type == ClientMessage)
2444  {
2445  // control notifications are processed here.
2446 
2447  if(pEvent->xclient.message_type == aDLGC_CONTROL_SET)
2448  {
2449  iType = pDialogControl->ulFlags & BUTTON_TYPEMASK; // TODO: use the class or the type?
2450 
2451  if(pEvent->xclient.data.l[0] == ControlGetSet_TRISTATE &&
2452  iType == BUTTON_TriStateButton)
2453  {
2454  if((int)(pEvent->xclient.data.l[1]) < 0 ||
2455  (pEvent->xclient.data.l[1] == 0 && (pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_TRISTATE)) ||
2456  (pEvent->xclient.data.l[1] != 0 && !(pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_TRISTATE)))
2457  {
2458  pDialogControl->pDlgControlEntry->iFlags ^= WBDialogEntry_TRISTATE;
2459 
2460  WBInvalidateRect(wID, NULL, 0);
2461  WBUpdateWindowImmediately(wID); // make sure I paint it NOW
2462 
2463  DLGNotifyOwnerAsync(pDialogControl, aCONTROL_NOTIFY, aBUTTON_PRESS, // notify state change
2464  pDialogControl->pDlgControlEntry->iID,
2465  WBCreatePointerHash(pDialogControl), 0, 0);
2466  }
2467  }
2468  else if(pEvent->xclient.data.l[0] == ControlGetSet_CHECK &&
2469  ButtonHandleCheckEvent(pDisplay, wID, pDialogControl, iType,
2470  (int)(pEvent->xclient.data.l[1])))
2471  {
2472  // because the state might have changed, notify the owner anyway
2473 
2475  pDialogControl->pDlgControlEntry->iID,
2476  WBCreatePointerHash(pDialogControl), 0, 0);
2477 
2478  return 1; // handled
2479  }
2480  }
2481  else if(pEvent->xclient.message_type == aDLGC_CONTROL_GET)
2482  {
2483  iType = pDialogControl->ulFlags & BUTTON_TYPEMASK; // TODO: use the class or the type?
2484 
2485  // TODO: should I return this info for *ANY* button ??
2486 
2487  if(pEvent->xclient.data.l[0] == ControlGetSet_TRISTATE &&
2488  iType == BUTTON_TriStateButton)
2489  {
2490  return pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_TRISTATE
2491  ? 1 : 0;
2492  }
2493  else if(pEvent->xclient.data.l[0] == ControlGetSet_CHECK &&
2494  (iType == BUTTON_CheckButton || iType == BUTTON_TriStateButton ||
2495  iType == BUTTON_RadioButton || iType == BUTTON_FirstRadioButton))
2496  {
2497  return pDialogControl->pDlgControlEntry->iFlags & WBDialogEntry_CHECKED
2498  ? 1 : 0;
2499  }
2500  }
2501  }
2502  }
2503 
2504  return 0; // not handled
2505 }
2506 
2507 static void ManageRadioButtonGroupSelectState(WBDialogControl *pDialogControl)
2508 {
2509 WBDialogWindow *pOwner = pDialogControl->pOwner; // convenience assignment
2510 WBDialogControl *pDlgC;
2511 Window wIDFirst, wIDTemp, wIDTemp2;
2512 Window wIDCurrent = pDialogControl->wID;
2513 int iType = pDialogControl->ulFlags & BUTTON_TYPEMASK; // TODO: use the class or the type?
2514 
2515 
2516  if(!pDialogControl)
2517  {
2518  WB_ERROR_PRINT("ERROR: %s - pDialogControl is NULL\n", __FUNCTION__);
2519 
2520  return;
2521  }
2522 
2523  // run through all of the radio buttons in this 'group' and fix 'em. ONLY
2524  // the dialog control passed into this function may be 'checked'. The others
2525  // *MUST* be UNchecked.
2526 
2527  // first, find out which dialog control is the 'First' radio button
2528  if(iType == BUTTON_FirstRadioButton)
2529  {
2530  pDlgC = pDialogControl;
2531  wIDFirst = pDlgC->wID;
2532  }
2533  else if(iType != BUTTON_RadioButton)
2534  {
2535  WB_ERROR_PRINT("ERROR: %s - pDialogControl is NOT a radio button\n", __FUNCTION__);
2536 
2537  return; // bail out
2538  }
2539  else
2540  {
2541  wIDFirst = DLGGetFirstDialogControl(pOwner);
2542  wIDTemp2 = pDialogControl->wID; // first known radio button
2543 
2544  wIDTemp = DLGGetPrevDialogControl(pOwner, wIDTemp2);
2545  pDlgC = NULL;
2546 
2547  while(wIDTemp != None && wIDTemp != pDialogControl->wID)
2548  {
2549  pDlgC = DLGGetDialogControlStruct(wIDTemp);
2550 
2551  if(pDlgC)
2552  {
2554  {
2555  wIDFirst = wIDTemp; // I found "the first one" for the group
2556  break;
2557  }
2558 
2559  if((pDlgC->ulFlags & BUTTON_TYPEMASK) == BUTTON_RadioButton)
2560  {
2561  wIDTemp2 = wIDTemp; // first known radio button [in case no 'first' button, ALL are in the same group]
2562  }
2563 
2564  pDlgC = NULL; // set to NULL now, as a flag, mostly
2565 
2566  if(wIDTemp == wIDFirst) // first control in dialog box. stop searching.
2567  {
2568  break;
2569  }
2570  }
2571 
2572  wIDTemp = DLGGetPrevDialogControl(pOwner, wIDTemp); // keep searching backwards
2573  }
2574 
2575  // enumeration will begin with 'wIDFirst', so assign that with wIDTemp2
2576  // if I did not actually find a 'first' radio button
2577  if(!pDlgC && wIDTemp2 != None)
2578  {
2579  wIDFirst = wIDTemp2; // use the first known radio button as the first in the group
2580 
2581  pDlgC = DLGGetDialogControlStruct(wIDFirst);
2582  }
2583  }
2584 
2585  while(pDlgC)
2586  {
2587  if(((pDlgC->ulFlags & BUTTON_TYPEMASK) == BUTTON_FirstRadioButton) ||
2588  ((pDlgC->ulFlags & BUTTON_TYPEMASK) == BUTTON_RadioButton))
2589  {
2590  if(pDlgC->wID != wIDCurrent && pDlgC->pDlgControlEntry)
2591  {
2593  {
2595 
2596  // post a notify message
2597 
2599  (long)(pDlgC->pDlgControlEntry ? pDlgC->pDlgControlEntry->iID : pDlgC->wID),
2600  WBCreatePointerHash(pDlgC->pDlgControlEntry), 0, 0, 0);
2601 
2602  WBInvalidateRect(pDlgC->wID, NULL, 0);
2603  WBUpdateWindowImmediately(pDlgC->wID); // make sure I paint it NOW
2604  }
2605  }
2606  }
2607 
2608  wIDTemp = DLGGetNextDialogControl(pOwner, pDlgC->wID); // keep searching
2609  if(wIDTemp == None || wIDTemp == wIDFirst)
2610  {
2611  break; // I am done (error or wrap-around)
2612  }
2613 
2614  pDlgC = DLGGetDialogControlStruct(wIDTemp);
2615 
2616  if(pDlgC && (pDlgC->ulFlags & BUTTON_TYPEMASK) == BUTTON_FirstRadioButton) // found another 'first'?
2617  {
2618  break; // start of new group. end of previous one. bail.
2619  }
2620  }
2621 }
2622 
2623 
2624 
2625 static int ListDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
2626  Window wID, WBDialogControl *pSelf);
2627 
2628 static int ListDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
2629  Window wID, WBDialogControl *pSelf);
2630 
2631 static int list_callback(Window wID, XEvent *pEvent)
2632 {
2633  int i1, iRval = 0;
2634  Atom aNotification = None;
2635  Display *pDisplay = WBGetWindowDisplay(wID);
2636  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
2637 // char tbuf[32];
2638 // int nChar = sizeof(tbuf);
2639  LISTINFO *pListInfo = NULL;
2640  WB_DIALOG_PROP *pProp;
2641 
2642  if(pDialogControl && pEvent->type == Expose)
2643  {
2644  return ListDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl);
2645  }
2646 
2647  pProp = (WB_DIALOG_PROP *)WBDialogControlGetDialogProp(pDialogControl, aDLGC_LISTINFO);
2648 
2649  if(pProp)
2650  {
2651  pListInfo = (LISTINFO *)pProp->pVal;
2652  }
2653 
2654 
2655  // special handling for 'destroy'
2656  if(pEvent->type == DestroyNotify &&
2657  pEvent->xdestroywindow.window == wID)
2658  {
2659  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
2660  "%s - DestroyNotify\n", __FUNCTION__);
2661 
2662  if(((WBListControl *)pDialogControl)->fsBold == None)
2663  {
2664  // free up the allocated font set, if there is one
2665  XFreeFontSet(pDisplay, ((WBListControl *)pDialogControl)->fsBold);
2666 
2667  ((WBListControl *)pDialogControl)->fsBold = None;
2668  }
2669 
2670  WBSetWindowData(wID, 0, NULL);
2671 
2672  if(pDialogControl)
2673  {
2674  if(pDialogControl->pCaption)
2675  {
2676  WBFree(pDialogControl->pCaption);
2677  }
2678 
2679  if(pDialogControl->pPropList)
2680  {
2681  DLGCDestroyProperties(pDialogControl->pPropList);
2682  pDialogControl->pPropList = NULL; // as a matter of course
2683  }
2684 
2685  WBDestroyPointerHashPtr(pDialogControl);
2686  WBFree(pDialogControl);
2687  }
2688 
2689  return 1;
2690  }
2691 
2692  // handle scroll bars (mousie-clickie and keystrokes)
2693  // this will generate 'scroll notify' events (as appropriate)
2694  i1 = DLGScrollBarHandler(wID, pDialogControl, pEvent);
2695 
2696  if(i1)
2697  {
2698  return i1;
2699  }
2700 
2701 #if 0
2702  if(pEvent->type == KeyPress)
2703  {
2704 #ifndef NO_DEBUG
2705  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, tbuf, &nChar, &iACS);
2706  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2707  "%s KEY PRESS for KEY %d KEYCODE %d\n", __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode);
2708 
2709  // TODO: extended select modifier keys, toggles, 'auto-complete' select, etc.
2710 
2711 #endif // NO_DEBUG
2712  iRval = 1; // handled
2713  }
2714  else if(pEvent->type == KeyRelease)
2715  {
2716  // KeyRelease
2717 
2718  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, tbuf, &nChar, &iACS);
2719 
2720  if(nChar > 0)
2721  {
2722  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2723  "%s KEY RELEASE for KEY %d KEYCODE %d MASK=%d (%xH)\n",
2724  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
2725  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
2726 
2727 // if(iKey == 8) // backspace
2728 // {
2729 // // TODO: delete char before cursor or highlighted text
2730 // // for now just delete the LAST character
2731 //
2732 // int iLen = strlen(pDialogControl->pCaption);
2733 // if(iLen > 0)
2734 // {
2735 // pDialogControl->pCaption[iLen - 1] = 0;
2736 // }
2737 //
2738 // WB_DEBUG_PRINT(DebugLevel_Excessive | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2739 // "%s - BACKSPACE key pressed\n", __FUNCTION__);
2740 // }
2741 // else
2742 // {
2743 // // TODO: insert or concatenate? for now concatenate
2744 // WBCatString(&(pDialogControl->pCaption), tbuf);
2745 // }
2746 //
2747 // aNotification = aTEXT_CHANGED;
2748 // WBInvalidateGeom(wID, NULL, 1);
2749  }
2750  else
2751  {
2752  if(iACS & WB_KEYEVENT_KEYSYM)
2753  {
2754  // TODO: international, 'dead' and other KEYSYM key assignments
2755 #define KEYSYM_MATCH_CURSOR_NAME(X) (iKey == XK_##X || iKey == XK_KP_##X)
2756  if(KEYSYM_MATCH_CURSOR_NAME(Home))
2757  {
2758  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2759  "%s - Home key pressed\n", __FUNCTION__);
2760  }
2761  else if(KEYSYM_MATCH_CURSOR_NAME(End))
2762  {
2763  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2764  "%s - End key pressed\n", __FUNCTION__);
2765  }
2766  else if(KEYSYM_MATCH_CURSOR_NAME(Left)) // if HSCROLL enabled
2767  {
2768  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2769  "%s - Left key pressed\n", __FUNCTION__);
2770  }
2771  else if(KEYSYM_MATCH_CURSOR_NAME(Right)) // if HSCROLL enabled
2772  {
2773  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2774  "%s - Right key pressed\n", __FUNCTION__);
2775  }
2776  else if(KEYSYM_MATCH_CURSOR_NAME(Up))
2777  {
2778  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2779  "%s - Up key pressed\n", __FUNCTION__);
2780  }
2781  else if(KEYSYM_MATCH_CURSOR_NAME(Down))
2782  {
2783  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2784  "%s - Down key pressed\n", __FUNCTION__);
2785  }
2786  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Up))
2787  {
2788  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2789  "%s - Page Up key pressed\n", __FUNCTION__);
2790  }
2791  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Down))
2792  {
2793  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2794  "%s - Page Down key pressed\n", __FUNCTION__);
2795  }
2796  else if(KEYSYM_MATCH_CURSOR_NAME(Begin)) // beginning of current line
2797  {
2798  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2799  "%s - Beginning Of Line key pressed\n", __FUNCTION__);
2800  }
2801 #undef KEYSYM_MATCH_CURSOR_NAME
2802  else
2803  {
2804  // is it a cursor key? let's find out
2805  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
2806  "%s - CURSOR KEY? %d (%08xH) %d (%08xH)\n",
2807  __FUNCTION__, iKey, iKey, iACS, iACS);
2808  }
2809  }
2810  }
2811 
2812  iRval = 1;
2813  }
2814 #endif // 0
2815 
2816  // processing notifications sent to me
2817 
2818  if(pEvent->type == ClientMessage &&
2819  pEvent->xclient.message_type == aCONTROL_NOTIFY)
2820  {
2821  char *p1 = WBGetAtomName(pDisplay,(Atom)pEvent->xclient.data.l[0]);
2822  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
2823  "%s - CONTROL_NOTIFY for window %d (%08xH) - %s %ld\n", __FUNCTION__,
2824  (int)wID, (int)wID, p1, pEvent->xclient.data.l[1]);
2825  if(p1)
2826  {
2827  WBFree(p1);
2828  }
2829  }
2830  else if(pEvent->type == ClientMessage &&
2831  pEvent->xclient.message_type == aWB_CHAR)
2832  {
2833  iRval = ListDoCharEvent(&(pEvent->xclient), pDisplay, wID, pDialogControl);
2834 
2835  if(iRval > 0)
2836  {
2837 // POOBAH
2838  DLGNotifyOwner(pDialogControl, aCONTROL_NOTIFY, aLIST_NOTIFY,
2839  pDialogControl->pDlgControlEntry->iID,
2840  WB_LIST_SELCHANGE, pListInfo->nPos, 0); // synchronous notification
2841  return 1; // "handled"
2842  }
2843 
2844  iRval = 0; // "not handled"
2845  }
2846  else if(pEvent->type == ClientMessage &&
2847  pEvent->xclient.message_type == aWB_POINTER)
2848  {
2849  if(pEvent->xclient.data.l[0] == WB_POINTER_CLICK)
2850  {
2851  // TODO: handle shift-click, ctrl-click, alt-click
2852 
2853  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
2854  !pEvent->xclient.data.l[2])
2855  {
2856  int iX = pEvent->xclient.data.l[3];
2857  int iY = pEvent->xclient.data.l[4];
2858 
2859  WB_SCROLLINFO *pScrollInfo = (WB_SCROLLINFO *)WBDialogControlGetProperty2(pDialogControl, aDLGC_SCROLLINFO);
2860 
2861  if(WB_LIKELY(pScrollInfo != NULL) &&
2862  WB_UNLIKELY(WBPointInGeom(iX, iY, pScrollInfo->geomVBar) != 0))
2863  {
2864  // mouse click was INSIDE of the scroll bar area - this should have already been handled
2865 
2866  WB_ERROR_PRINT("UNHANDLED SCROLL BAR mouse message inside VBAR %d %d %d %d %d\n",
2867  (int)pEvent->xclient.data.l[0],
2868  (int)pEvent->xclient.data.l[1],
2869  (int)pEvent->xclient.data.l[2],
2870  (int)pEvent->xclient.data.l[3],
2871  (int)pEvent->xclient.data.l[4]);
2872 
2873  return 0;
2874  }
2875 
2876  // use information about the list to determine where I clicked (which selected item or not)
2877  // TODO: encapsulate item selection via message post
2878 
2879  if(pListInfo && pListInfo->nItemHeight > 0)
2880  {
2881  i1 = (iY - 1) / pListInfo->nItemHeight; // item number within list 'display area'
2882 
2883 // WB_ERROR_PRINT("TEMPORARY: clicked on item %d, top item is %d\n", i1, pListInfo->nTop);
2884 
2885  if(i1 >= 0 && i1 <= pListInfo->nHeight)
2886  {
2887  i1 += pListInfo->nTop; // actual index
2888  }
2889  else
2890  {
2891  i1 = -1; // as a flag
2892  }
2893  }
2894  if(i1 >= 0 && i1 < pListInfo->nItems)
2895  {
2896  if(pListInfo->nPos != i1)
2897  {
2898  // set new selection
2899  pListInfo->nPos = i1;
2900 
2901  if(i1 < pListInfo->nTop) // adjust top if needed
2902  {
2903  pListInfo->nTop = i1;
2904  }
2905  else if(i1 >= pListInfo->nHeight + pListInfo->nTop)
2906  {
2907  pListInfo->nTop = i1 - pListInfo->nHeight + 1;
2908  }
2909 
2910  WBInvalidateGeom(wID, NULL, 0); // asynchronous re-paint
2911  WBUpdateWindow(wID); // posts expose event
2912 
2913  DLGNotifyOwner(pDialogControl, aCONTROL_NOTIFY, aLIST_NOTIFY,
2914  pDialogControl->pDlgControlEntry->iID,
2915  WB_LIST_SELCHANGE, pListInfo->nPos, 0); // synchronous notification
2916  }
2917  }
2918 
2919  return 1; // handled
2920  }
2921  }
2922  else if(pEvent->xclient.data.l[0] == WB_POINTER_DBLCLICK)
2923  {
2924  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
2925  !pEvent->xclient.data.l[2])
2926  {
2927  int iX = pEvent->xclient.data.l[3];
2928  int iY = pEvent->xclient.data.l[4];
2929 
2930  // NOTE: no need to notify selection (would have already been done)
2931 
2932  WB_SCROLLINFO *pScrollInfo = (WB_SCROLLINFO *)WBDialogControlGetProperty2(pDialogControl, aDLGC_SCROLLINFO);
2933 
2934  if(WB_LIKELY(pScrollInfo != NULL) &&
2935  WB_UNLIKELY(WBPointInGeom(iX, iY, pScrollInfo->geomVBar) != 0))
2936  {
2937  WB_ERROR_PRINT("UNHANDLED SCROLL BAR mouse message %d %d %d %d %d\n",
2938  (int)pEvent->xclient.data.l[0],
2939  (int)pEvent->xclient.data.l[1],
2940  (int)pEvent->xclient.data.l[2],
2941  (int)pEvent->xclient.data.l[3],
2942  (int)pEvent->xclient.data.l[4]);
2943 
2944  return 0;
2945  }
2946 
2947  // for now assume selection hasn't changed, and post a double-click notification
2948  // back to the list control's owner so that appropriate action will be taken
2949 
2950  DLGNotifyOwner(pDialogControl, aCONTROL_NOTIFY, aLIST_NOTIFY,
2951  pDialogControl->pDlgControlEntry->iID,
2952  WB_LIST_DBLCLICK, pListInfo->nPos, 0); // synchronous notification
2953 
2954  return 1;
2955  }
2956 
2957  return 0; // so no further processing happens
2958  }
2959  else if(pEvent->xclient.data.l[0] == WB_POINTER_CANCEL)
2960  {
2961  // canceling drag (as appropriate)
2962 
2963  WB_SCROLLINFO *pScrollInfo = (WB_SCROLLINFO *)WBDialogControlGetProperty2(pDialogControl, aDLGC_SCROLLINFO);
2964 
2965  if(pScrollInfo &&
2966  pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
2967  !pEvent->xclient.data.l[2])
2968  {
2969  WB_ERROR_PRINT("UNHANDLED SCROLL BAR mouse message %d %d %d %d %d\n",
2970  (int)pEvent->xclient.data.l[0],
2971  (int)pEvent->xclient.data.l[1],
2972  (int)pEvent->xclient.data.l[2],
2973  (int)pEvent->xclient.data.l[3],
2974  (int)pEvent->xclient.data.l[4]);
2975 
2976  pScrollInfo->iScrollState &= ~WBScrollState_LDRAG;
2977  }
2978 
2979  return 1;
2980  }
2981  else if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG ||
2982  pEvent->xclient.data.l[0] == WB_POINTER_MOVE)
2983  {
2984  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
2985  !pEvent->xclient.data.l[2])
2986  {
2987  int iX = pEvent->xclient.data.l[3];
2988  int iY = pEvent->xclient.data.l[4];
2989 
2990  WB_SCROLLINFO *pScrollInfo = (WB_SCROLLINFO *)WBDialogControlGetProperty2(pDialogControl, aDLGC_SCROLLINFO);
2991 
2992  if(WB_LIKELY(pScrollInfo != NULL) &&
2993  WB_UNLIKELY(WBPointInGeom(iX, iY, pScrollInfo->geomVBar) != 0))
2994  {
2995  WB_ERROR_PRINT("UNHANDLED SCROLL BAR mouse message %d %d %d %d %d\n",
2996  (int)pEvent->xclient.data.l[0],
2997  (int)pEvent->xclient.data.l[1],
2998  (int)pEvent->xclient.data.l[2],
2999  (int)pEvent->xclient.data.l[3],
3000  (int)pEvent->xclient.data.l[4]);
3001  }
3002  }
3003 
3004  return 0; // for now (to enforce 'NOT HANDLED')
3005  }
3006  else if(pEvent->xclient.data.l[0] == WB_POINTER_DROP)
3007  {
3008  return 1; // "handled" (just a notification anyway)
3009  }
3010  }
3011  else if(pEvent->type == ClientMessage &&
3012  pEvent->xclient.message_type == aSCROLL_NOTIFY)
3013  {
3014  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3015  "%s - SCROLL_NOTIFY for window %d (%08xH) - %ld %ld %ld\n", __FUNCTION__,
3016  (int)wID, (int)wID, pEvent->xclient.data.l[0],
3017  pEvent->xclient.data.l[1], pEvent->xclient.data.l[2]);
3018 
3019  if(pEvent->xclient.data.l[0] == WB_SCROLL_VERTICAL)
3020  {
3021  int iOldTop = pListInfo->nTop;
3022  int iOldPos = pListInfo->nPos;
3023 
3024  switch(pEvent->xclient.data.l[1])
3025  {
3026  case WB_SCROLL_FORWARD:
3027  pListInfo->nPos ++;
3028  break;
3029  case WB_SCROLL_BACKWARD:
3030  pListInfo->nPos --;
3031  break;
3032  case WB_SCROLL_PAGEFWD:
3033  pListInfo->nPos += pListInfo->nHeight;
3034  break;
3035  case WB_SCROLL_PAGEBACK:
3036  pListInfo->nPos -= pListInfo->nHeight;
3037  break;
3038  case WB_SCROLL_FIRST:
3039  pListInfo->nPos = 0;
3040  break;
3041  case WB_SCROLL_LAST:
3042  pListInfo->nPos = pListInfo->nItems - 1;
3043  break;
3044  case WB_SCROLL_KNOB:
3045  pListInfo->nTop = pEvent->xclient.data.l[2];
3046  pListInfo->nPos += pListInfo->nTop - iOldTop;
3047  break;
3048  case WB_SCROLL_RELATIVE:
3049  pListInfo->nPos += pEvent->xclient.data.l[2];
3050  break;
3051  case WB_SCROLL_ABSOLUTE:
3052  pListInfo->nPos = pEvent->xclient.data.l[2];
3053  break;
3054  }
3055 
3056  if(iOldTop != pListInfo->nTop || iOldPos != pListInfo->nPos)
3057  {
3058  if(pListInfo->nPos < 0)
3059  {
3060  pListInfo->nPos = 0;
3061  }
3062  else if(pListInfo->nPos >= pListInfo->nItems)
3063  {
3064  pListInfo->nPos = pListInfo->nItems - 1;
3065  }
3066  if(pListInfo->nTop > pListInfo->nPos)
3067  {
3068  pListInfo->nTop = pListInfo->nPos;
3069  }
3070  else if(pListInfo->nTop + pListInfo->nHeight <= pListInfo->nPos)
3071  {
3072  pListInfo->nTop = pListInfo->nPos - pListInfo->nHeight + 1;
3073  }
3074 
3075  if(iOldTop != pListInfo->nTop || iOldPos != pListInfo->nPos)
3076  {
3077  WBInvalidateGeom(wID, NULL, 0);
3078 
3079  if(pEvent->xclient.data.l[1] == WB_SCROLL_KNOB)
3080  {
3082  }
3083  else
3084  {
3085  WBUpdateWindow(wID);
3086  }
3087  }
3088  }
3089 
3090  return 1;
3091  }
3092 
3093  return 1;
3094  }
3095 
3096 
3097 
3098  // CONTROL NOTIFICATIONS to OWNER
3099 
3100  if(iRval && aNotification != None &&
3101  pDialogControl->pOwner &&
3102  pDialogControl->pDlgControlEntry)
3103  {
3104  DLGNotifyOwnerAsync(pDialogControl, aCONTROL_NOTIFY, aNotification,
3105  pDialogControl->pDlgControlEntry->iID,
3106  WBCreatePointerHash(pDialogControl), 0, 0);
3107 
3108  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3109  "%s:%d - Post Event: %08xH %08xH %08xH %pH\n", __FUNCTION__, __LINE__,
3110  (int)aCONTROL_NOTIFY, (int)aNotification,
3111  (int)pDialogControl->pDlgControlEntry->iID, pDialogControl);
3112  }
3113 
3114  return iRval; // 0 if not handled, 1 if handled
3115 }
3116 
3117 
3118 static int file_list_callback(Window wID, XEvent *pEvent)
3119 {
3120 //Display *pDisplay = WBGetWindowDisplay(wID);
3121 WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
3122 char *p1;
3123 const char *p2;
3124 void *pV;
3125 unsigned long dw1;
3126 char tbuf[NAME_MAX + 4];
3127 
3128 
3129 // WB_ERROR_PRINT("TEMPORARY: %s\n", __FUNCTION__);
3130 
3131  if(pEvent->type == ClientMessage &&
3132  pEvent->xclient.message_type == aDLGC_PROP_NOTIFY)
3133  {
3134  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3135  "%s - DLGC_PROP_NOTIFY for window %d (%08xH)\n", __FUNCTION__,
3136  (int)wID, (int)wID);
3137 
3138  if(pEvent->xclient.data.l[0] == aDLGC_PATH) // TODO: include a 'DLGC_FILTER' property as well
3139  {
3140  if(pDialogControl->pOwner)
3141  {
3142  WBBeginWaitCursor(pDialogControl->pOwner->wID);
3143  }
3144  else
3145  {
3146  WBBeginWaitCursor(wID);
3147  }
3148 
3149  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3150  "%s - DLGC_PROP_NOTIFY DLGC_PATH for window %d (%08xH)\n", __FUNCTION__,
3151  (int)wID, (int)wID);
3152 
3153  // property change notification for aPATH must refresh contents
3154  DLGDelControlListEntry(pDialogControl, ControlListIndex_DELETE_ALL); // delete all
3155 
3156  p2 = WBDialogControlGetProperty(pDialogControl, aDLGC_PATH); // original path info
3157 
3158  p1 = WBCopyString(p2); // working copy
3159  if(!p1 || !*p1)
3160  {
3161  // TODO: get current working directory?
3162 
3163  // empty path implies empty list
3164  goto restore_cursor; // this will also re-paint
3165  }
3166  if(p1[strlen(p1) - 1] != '/')
3167  {
3168  WBCatString(&p1, "/*");
3169  }
3170  else
3171  {
3172  WBCatString(&p1, "*");
3173  }
3174 
3175  if(!p1 || !*p1) // in case of error
3176  {
3177  WB_ERROR_PRINT("%s - Memory allocation failure\n", __FUNCTION__);
3178 
3179  goto restore_cursor;
3180  }
3181 
3182  pV = WBAllocDirectoryList(p1);
3183 
3184  if(!pV) // in case of error
3185  {
3186  WB_ERROR_PRINT("%s - unable to get directory list for \"%s\"\n", __FUNCTION__, p1);
3187  WBFree(p1);
3188 
3189  goto restore_cursor;
3190  }
3191 
3192  WBFree(p1);
3193  p1 = NULL;
3194 
3195  // always add the '..' first, unless the path is '/'
3196  if(!p2 || p2[0] != '/' || p2[1])
3197  {
3198  strcpy(tbuf, "@.."); // directory '..'
3199  DLGAddControlListEntry(pDialogControl, tbuf, -1, ControlListIndex_INSERT_FIRST);
3200  }
3201 
3202  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3203  "%s - enumerating directory\n", __FUNCTION__);
3204 
3205  while(!WBNextDirectoryEntry(pV, tbuf + 1, sizeof(tbuf) - 1, &dw1))
3206  {
3207  if(S_ISDIR(dw1))
3208  {
3209  tbuf[0] = '@';
3210  }
3211  else if(S_ISLNK(dw1))
3212  {
3213  // TODO: determine what link's type is
3214  if(WBGetDirectoryListFileStat(pV, tbuf, &dw1))
3215  {
3216  tbuf[0] = '^'; // can't 'stat' so mark as 'symlink' (for now, maybe reject it?)
3217  }
3218  else if(S_ISDIR(dw1))
3219  {
3220  tbuf[0] = '@'; // treat symlink as a directory since it points to one
3221  }
3222  else
3223  {
3224  tbuf[0] = '~'; // assume it's a regular file
3225  }
3226  }
3227  else
3228  {
3229  tbuf[0] = '~';
3230  }
3231 
3232 // WB_WARN_PRINT("TEMPORARY - %s %d (%08xH)\n", tbuf, (int)dw1, (int)dw1);
3233 
3234  // TODO: directories are excluded
3235  DLGAddControlListEntry(pDialogControl, tbuf, -1, ControlListIndex_INSERT_LAST);
3236  }
3237 
3238 // WB_WARN_PRINT("TEMPORARY - DONE enumerating directory\n");
3239 
3241  DEBUG_DUMP_LIST(pDialogControl);
3242 
3243 restore_cursor:
3244 
3245  WBInvalidateGeom(wID, NULL, 1); // invalidate and generate expose message (always)
3246 
3247  if(pDialogControl->pOwner)
3248  {
3249  WBEndWaitCursor(pDialogControl->pOwner->wID);
3250  }
3251  else
3252  {
3253  WBEndWaitCursor(wID);
3254  }
3255 
3256  return 1;
3257  }
3258 
3259  // TODO: other stuff?
3260 
3261  // return 1; do this when it's handled by THIS proc
3262  }
3263 
3264  return list_callback(wID, pEvent); // allow base control class to handle it
3265 }
3266 
3267 
3268 static int tree_callback(Window wID, XEvent *pEvent)
3269 {
3270  int iRval = 0;
3271  Atom aNotification = None;
3272  Display *pDisplay = WBGetWindowDisplay(wID);
3273  WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
3274 // char tbuf[32];
3275 // int nChar = sizeof(tbuf);
3276 
3277 
3278  if(pDialogControl && pEvent->type == Expose)
3279  {
3280  return ListDoExposeEvent(&(pEvent->xexpose), pDisplay, wID, pDialogControl);
3281  }
3282 
3283  // special handling for 'destroy'
3284  if(pEvent->type == DestroyNotify &&
3285  pEvent->xdestroywindow.window == wID)
3286  {
3287  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
3288  "%s - DestroyNotify\n", __FUNCTION__);
3289 
3290  WBSetWindowData(wID, 0, NULL);
3291 
3292  if(pDialogControl)
3293  {
3294  if(pDialogControl->pCaption)
3295  {
3296  WBFree(pDialogControl->pCaption);
3297  }
3298 
3299  if(pDialogControl->pPropList)
3300  {
3301  DLGCDestroyProperties(pDialogControl->pPropList);
3302  pDialogControl->pPropList = NULL; // as a matter of course
3303  }
3304 
3305  WBDestroyPointerHashPtr(pDialogControl);
3306  WBFree(pDialogControl);
3307  }
3308 
3309  return 1;
3310  }
3311 
3312  if(pEvent->type == FocusIn)
3313  {
3314  WB_ERROR_PRINT("TEMPORARY: %s - FocusIn should not be handled here\n", __FUNCTION__);
3315  }
3316 
3317 
3318  // TREE and LIST are similar
3319 
3320  // TODO: keystroke handling via WB_CHAR
3321 
3322 
3323  // CONTROL NOTIFICATIONS
3324 
3325  if(iRval && aNotification != None &&
3326  pDialogControl->pOwner &&
3327  pDialogControl->pDlgControlEntry)
3328  {
3329  DLGNotifyOwnerAsync(pDialogControl, aCONTROL_NOTIFY, aNotification,
3330  pDialogControl->pDlgControlEntry->iID,
3331  WBCreatePointerHash(pDialogControl), 0, 0);
3332 
3333  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3334  "%s:%d - Post Event: %08xH %08xH %08xH %pH\n", __FUNCTION__, __LINE__,
3335  (int)aCONTROL_NOTIFY, (int)aNotification,
3336  (int)pDialogControl->pDlgControlEntry->iID, pDialogControl);
3337  }
3338 
3339  return iRval; // 0 if not handled, 1 if handled
3340 }
3341 
3342 static int path_tree_callback(Window wID, XEvent *pEvent)
3343 {
3344 //Display *pDisplay = WBGetWindowDisplay(wID);
3345 WBDialogControl *pDialogControl = DLGGetDialogControlStruct(wID);
3346 char *p1;
3347 void *pV;
3348 unsigned long dw1;
3349 char tbuf[NAME_MAX + 4];
3350 
3351 
3352  if(pEvent->type == ClientMessage &&
3353  pEvent->xclient.type == aDLGC_PROP_NOTIFY)
3354  {
3355  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3356  "%s - DLGC_PROP_NOTIFY for window %d (%08xH)\n", __FUNCTION__,
3357  (int)wID, (int)wID);
3358 
3359  if(pEvent->xclient.data.l[0] == aDLGC_PATH) // TODO: include a 'DLGC_FILTER' property as well
3360  {
3361  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
3362  "%s - DLGC_PROP_NOTIFY DLGC_PATH for window %d (%08xH)\n", __FUNCTION__,
3363  (int)wID, (int)wID);
3364 
3365  // property change notification for aPATH must refresh contents
3366  DLGDelControlListEntry(pDialogControl, ControlListIndex_DELETE_ALL); // delete all
3367 
3368  p1 = WBCopyString(WBDialogControlGetProperty(pDialogControl, aDLGC_PATH));
3369  if(!p1 || !*p1)
3370  {
3371  return 1; // empty path implies empty list
3372  }
3373  if(p1[strlen(p1) - 1] != '/')
3374  {
3375  WBCatString(&p1, "/*");
3376  }
3377  else
3378  {
3379  WBCatString(&p1, "*");
3380  }
3381 
3382  if(!p1 || !*p1) // in case of error
3383  {
3384  WB_ERROR_PRINT("%s - Memory allocation failure\n", __FUNCTION__);
3385  return 1;
3386  }
3387 
3388  pV = WBAllocDirectoryList(p1);
3389  WBFree(p1);
3390  p1 = NULL;
3391 
3392  if(!pV) // in case of error
3393  {
3394  WB_ERROR_PRINT("%s - unable to get directory list\n", __FUNCTION__);
3395  return 1;
3396  }
3397 
3398 // WB_WARN_PRINT("TEMPORARY - enumerating directory\n");
3399 
3400  while(!WBNextDirectoryEntry(pV, tbuf, sizeof(tbuf), &dw1))
3401  {
3402  if(S_ISDIR(dw1))
3403  {
3404  }
3405  else if(S_ISLNK(dw1))
3406  {
3407  // TODO: determine what link's type is
3408 
3409  if(WBStat(tbuf, &dw1) || !S_ISDIR(dw1))
3410  {
3411  continue;
3412  }
3413  }
3414  else
3415  {
3416  continue; // ignore regular files
3417  }
3418 
3419 // WB_WARN_PRINT("TEMPORARY - %s %d (%08xH)\n", tbuf, (int)dw1, (int)dw1);
3420 
3421  DLGAddControlListEntry(pDialogControl, tbuf, -1, ControlListIndex_INSERT_LAST);
3422  }
3423 
3424 // WB_WARN_PRINT("TEMPORARY - DONE enumerating directory\n");
3425 
3427  DEBUG_DUMP_LIST(pDialogControl);
3428 
3429  return 1;
3430  }
3431  }
3432 
3433  return tree_callback(wID, pEvent); // allow base control class to handle it
3434 }
3435 
3436 
3437 
3438 
3439 //*****************************
3440 // I N P U T H A N D L I N G
3441 //*****************************
3442 
3443 
3444 // NOTE: returns non-zero if text changes
3445 
3446 static int EditDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
3447  Window wID, WBDialogControl *pSelf)
3448 {
3449 WBEditControl *pPrivate = (WBEditControl *)pSelf;
3450 int iRval = 0, iACS, iKey, nChar;//, iLen;
3451 char *pBuf, *pData;
3452 WB_RECT rctTemp;
3453 
3454 
3455  iKey = pEvent->data.l[0]; // result from WBKeyEventProcessKey()
3456  iACS = pEvent->data.l[1];
3457  nChar = pEvent->data.l[2];
3458  pBuf = (char *)&(pEvent->data.l[3]);
3459 
3460  if(nChar > 0) // normal ASCII characters
3461  { // DebugLevel_Heavy
3462  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3463  "%s KEY RELEASE for KEY %d KEYCODE %d MASK=%d (%xH)\n",
3464  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
3465  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
3466 
3467  if(iKey == 8) // backspace
3468  {
3469  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3470  "%s - BACKSPACE key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3471 
3472  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
3473  {
3474  pPrivate->xTextObject.vtable->del_select(&(pPrivate->xTextObject)); // delete selection
3475  }
3476  else
3477  {
3478  pPrivate->xTextObject.vtable->del_chars(&(pPrivate->xTextObject), -1); // delete the character to the left
3479  }
3480 
3481  // re-assign caption
3482  if(pSelf->pCaption)
3483  {
3484  WBFree(pSelf->pCaption);
3485  }
3486 
3487  pSelf->pCaption = pPrivate->xTextObject.vtable->get_text(&(pPrivate->xTextObject));
3488 
3489  iRval = 1; // text changed
3490  }
3491  else if(iKey == 13 || iKey == 10 // CR or LF (TODO: check flags to see if I should accept this)
3492  || iKey == 9) // tab (TODO: check flags to see if I should accept this)
3493  {
3494  // TODO: check for multi-line control, add line feeds as needed
3495 
3496  return 0; // LF may trigger default button, allow default handling
3497  // since the text was not changed return 0 _NOW_ so that WB_CHAR handling happens in default processing
3498  }
3499  else if(iKey == 1) // CTRL+A
3500  {
3501  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3502  "%s - CTRL+A key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3503 
3504  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
3505  {
3506  rctTemp.left = rctTemp.top = 0;
3507  rctTemp.right = rctTemp.bottom = INT_MAX;
3508 
3509  pPrivate->xTextObject.vtable->set_select(&(pPrivate->xTextObject), &rctTemp);
3510  }
3511 
3512  iRval = -1; // text NOT changed
3513  }
3514  else if(iKey == 3) // CTRL+C
3515  {
3516  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
3517  {
3518  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
3519  {
3520  WB_DEBUG_PRINT(/*KEYSYM_DEBUG_FLAG*/DebugLevel_ERROR | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3521  "%s - CTRL+C key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3522 
3523  pData = pPrivate->xTextObject.vtable->get_sel_text(&(pPrivate->xTextObject), NULL);
3524 
3525  if(pData)
3526  {
3527  if(aUTF8_STRING != None)
3528  {
3529  WBSetClipboardData(pDisplay, aUTF8_STRING, 8, pData, strlen(pData) + 1);
3530  }
3531  else
3532  {
3533  WBSetClipboardData(pDisplay, aSTRING, 8, pData, strlen(pData) + 1);
3534  }
3535  WBFree(pData);
3536  pData = NULL; // by convention
3537  }
3538  else
3539  {
3540  XBell(pDisplay, -100);
3541  WB_ERROR_PRINT("TEMPORARY: NULL returned from get_sel_text()\n");
3542  }
3543  }
3544  else
3545  {
3546  XBell(pDisplay, -100);
3547  WB_ERROR_PRINT("TEMPORARY - %s - no selection, can't 'COPY'\n", __FUNCTION__);
3548  }
3549  }
3550 
3551  iRval = -1; // text NOT changed
3552  }
3553  else if(iKey == 22) // CTRL+V
3554  {
3555  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3556  "%s - CTRL+V key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3557 
3558  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
3559  {
3560  Atom aType = aUTF8_STRING;
3561  int iFormat = 8;
3562  unsigned long nData = 0;
3563 
3564  if(aType == None)
3565  {
3566  aType = aSTRING;
3567  }
3568 
3569  WB_ERROR_PRINT("TEMPORARY %s - CTRL+V key pressed\n", __FUNCTION__);
3570 
3571 // pData = (char *)CHGetSelectionData(pDisplay, aCLIPBOARD, aUTF8_STRING, aUTF8_STRING, //aCLIPBOARD, aC_STRING, aSTRING,
3572 // &aType, &iFormat, &nData);
3573  pData = (char *)WBGetClipboardData(pDisplay, &aType, &iFormat, &nData);
3574 
3575  if(!pData || !nData)
3576  {
3577  if(pData)
3578  {
3579  WBFree(pData);
3580  }
3581 
3582  aType = aSTRING;
3583  pData = (char *)WBGetClipboardData(pDisplay, &aType, &iFormat, &nData);
3584  }
3585 
3586  if(pData && nData > 0)
3587  {
3588  if(!pData[nData])
3589  {
3590  nData--;
3591  }
3592  }
3593 
3594  if(pData)
3595  {
3596  // TODO: convert to correct format (ASCII)
3597  if(iFormat != 8)
3598  {
3599  if(iFormat == 8 * sizeof(wchar_t))
3600  {
3601  char *pNew = WBAlloc(sizeof(wchar_t) * (nData + 2));
3602  if(pNew)
3603  {
3604  memset(pNew, 0, sizeof(wchar_t) * (nData + 2));
3605  wcstombs(pNew, (const wchar_t *)pData, sizeof(wchar_t) * (nData + 2));
3606  }
3607 
3608  WBFree(pData);
3609  pData = pNew;
3610  }
3611  else
3612  {
3613  XBell(pDisplay, -100);
3614  WB_ERROR_PRINT("TEMPORARY - %s - clipboard format %d, can't 'PASTE'\n", __FUNCTION__, iFormat);
3615 
3616  WBFree(pData);
3617  pData = NULL;
3618  }
3619  }
3620 
3621  if(pData)
3622  {
3623  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
3624  {
3625  pPrivate->xTextObject.vtable->replace_select(&(pPrivate->xTextObject), pData, nData);
3626  }
3627  else
3628  {
3629  pPrivate->xTextObject.vtable->ins_chars(&(pPrivate->xTextObject), pData, nData);
3630  }
3631 
3632  WBFree(pData);
3633  pData = NULL; // by convention
3634  }
3635  else
3636  {
3637  XBell(pDisplay, -100);
3638  WB_ERROR_PRINT("TEMPORARY - %s - NULL pData, can't 'PASTE'\n", __FUNCTION__);
3639  }
3640  }
3641  else
3642  {
3643  XBell(pDisplay, -100);
3644  WB_ERROR_PRINT("TEMPORARY: NULL returned from WBGetClipboardData()\n");
3645  }
3646  }
3647 
3648  iRval = 1; // text changed
3649  }
3650  else if(iKey == 24) // CTRL+X
3651  {
3652  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3653  "%s - CTRL+X key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3654 
3655  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
3656  {
3657  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
3658  {
3659  WB_DEBUG_PRINT(/*KEYSYM_DEBUG_FLAG*/DebugLevel_ERROR | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3660  "%s - CTRL+C key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3661 
3662  pData = pPrivate->xTextObject.vtable->get_sel_text(&(pPrivate->xTextObject), NULL);
3663 
3664  if(pData)
3665  {
3666  if(aUTF8_STRING != None)
3667  {
3668  WBSetClipboardData(pDisplay, aUTF8_STRING, 8, pData, strlen(pData) + 1);
3669  }
3670  else
3671  {
3672  WBSetClipboardData(pDisplay, aSTRING, 8, pData, strlen(pData) + 1);
3673  }
3674 
3675  WBFree(pData);
3676  pData = NULL; // by convention
3677 
3678  pPrivate->xTextObject.vtable->del_select(&(pPrivate->xTextObject)); // delete selection
3679  }
3680  else
3681  {
3682  XBell(pDisplay, -100);
3683  WB_ERROR_PRINT("TEMPORARY: NULL returned from get_sel_text()\n");
3684  }
3685  }
3686  else
3687  {
3688  XBell(pDisplay, -100);
3689  WB_ERROR_PRINT("TEMPORARY - %s - no selection, can't 'CUT'\n", __FUNCTION__);
3690  }
3691  }
3692 
3693  iRval = 1; // text changed
3694  }
3695  else if(iKey == 26) // ctrl+Z
3696  {
3697  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3698  "%s - CTRL+Z key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3699 
3700  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
3701  {
3702  if(pPrivate->xTextObject.vtable->can_undo(&(pPrivate->xTextObject)))
3703  {
3704  pPrivate->xTextObject.vtable->undo(&(pPrivate->xTextObject));
3705  }
3706  else
3707  {
3708  XBell(pDisplay, -100);
3709  }
3710  }
3711  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift, no alt
3712  {
3713  if(pPrivate->xTextObject.vtable->can_redo(&(pPrivate->xTextObject)))
3714  {
3715  pPrivate->xTextObject.vtable->redo(&(pPrivate->xTextObject));
3716  }
3717  else
3718  {
3719  XBell(pDisplay, -100);
3720  }
3721  }
3722 
3723  iRval = 1; // text changed
3724  }
3725  else if(iKey == '\x1b') // ESC
3726  {
3727  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3728  "%s - ESC key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
3729 
3730  return 0; // not processed
3731  }
3732  else
3733  {
3734  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
3735  {
3736  pPrivate->xTextObject.vtable->replace_select(&(pPrivate->xTextObject), pBuf, nChar); // replace
3737  }
3738  else
3739  {
3740  // insert one or more ASCII characters
3741  pPrivate->xTextObject.vtable->ins_chars(&(pPrivate->xTextObject), pBuf, nChar);
3742  }
3743 
3744  // re-assign caption
3745  if(pSelf->pCaption)
3746  {
3747  WBFree(pSelf->pCaption);
3748  }
3749 
3750  pSelf->pCaption = pPrivate->xTextObject.vtable->get_text(&(pPrivate->xTextObject));
3751  }
3752 
3753  // update 'pCaption' with the complete text (cached value)
3754 
3755  if(pSelf->pCaption)
3756  {
3757  WBFree(pSelf->pCaption); // cached text
3758  }
3759 
3760  pSelf->pCaption = pPrivate->xTextObject.vtable->get_text(&(pPrivate->xTextObject));
3761 
3762  iRval = 1; // text changed
3763  }
3764  else
3765  {
3766  iRval = -1; // text normally doesn't change with these, but change to '1' if it does
3767 
3768  if(iACS & WB_KEYEVENT_KEYSYM)
3769  {
3770  // TODO: international, 'dead' and other KEYSYM key assignments
3771 #define KEYSYM_MATCH_CURSOR_NAME(X) (iKey == XK_##X || iKey == XK_KP_##X)
3772 
3773  if(KEYSYM_MATCH_CURSOR_NAME(Home))
3774  {
3775  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3776  "%s - Home key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3777 
3778  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3779  {
3780  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3781  pPrivate->xTextObject.vtable->cursor_home(&(pPrivate->xTextObject));
3782  }
3783  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3784  {
3785  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3786  pPrivate->xTextObject.vtable->cursor_top(&(pPrivate->xTextObject));
3787  }
3788  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3789  {
3790  pPrivate->xTextObject.vtable->cursor_home(&(pPrivate->xTextObject));
3791  }
3792  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+home
3793  {
3794  pPrivate->xTextObject.vtable->cursor_top(&(pPrivate->xTextObject));
3795  }
3796  }
3797  else if(KEYSYM_MATCH_CURSOR_NAME(End))
3798  {
3799  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3800  "%s - End key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3801 
3802  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3803  {
3804  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3805  pPrivate->xTextObject.vtable->cursor_end(&(pPrivate->xTextObject));
3806  }
3807  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3808  {
3809  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3810  pPrivate->xTextObject.vtable->cursor_bottom(&(pPrivate->xTextObject));
3811  }
3812  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3813  {
3814  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3815  pPrivate->xTextObject.vtable->cursor_end(&(pPrivate->xTextObject));
3816  }
3817  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+end
3818  {
3819  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3820  pPrivate->xTextObject.vtable->cursor_bottom(&(pPrivate->xTextObject));
3821  }
3822  }
3823  else if(KEYSYM_MATCH_CURSOR_NAME(Left))
3824  {
3825  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3826  "%s - Left key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3827 
3828  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3829  {
3830  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3831  pPrivate->xTextObject.vtable->cursor_left(&(pPrivate->xTextObject));
3832  }
3833  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3834  {
3835  // TODO: alter selection via selection method
3836  }
3837  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3838  {
3839  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3840  pPrivate->xTextObject.vtable->cursor_left(&(pPrivate->xTextObject));
3841  }
3842  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+left
3843  {
3844  // TODO: previous word
3845  }
3846  }
3847  else if(KEYSYM_MATCH_CURSOR_NAME(Right))
3848  {
3849  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3850  "%s - Right key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3851 
3852  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3853  {
3854  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3855  pPrivate->xTextObject.vtable->cursor_right(&(pPrivate->xTextObject));
3856  }
3857  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3858  {
3859  // TODO: alter selection via selection method
3860  }
3861  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3862  {
3863  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3864  pPrivate->xTextObject.vtable->cursor_right(&(pPrivate->xTextObject));
3865  }
3866  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+right
3867  {
3868  // TODO: next word
3869  }
3870  }
3871  else if(KEYSYM_MATCH_CURSOR_NAME(Up))
3872  {
3873  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3874  "%s - Up key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3875 
3876  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3877  {
3878  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3879  pPrivate->xTextObject.vtable->cursor_up(&(pPrivate->xTextObject));
3880  }
3881  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3882  {
3883  // TODO: alter selection via selection method
3884  XBell(pDisplay, -100);
3885  }
3886  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3887  {
3888  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3889  pPrivate->xTextObject.vtable->cursor_up(&(pPrivate->xTextObject));
3890  }
3891  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+up
3892  {
3893  // TODO: what should this do?
3894  XBell(pDisplay, -100);
3895  }
3896  }
3897  else if(KEYSYM_MATCH_CURSOR_NAME(Down))
3898  {
3899  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3900  "%s - Down key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3901 
3902  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3903  {
3904  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3905  pPrivate->xTextObject.vtable->cursor_down(&(pPrivate->xTextObject));
3906  }
3907  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3908  {
3909  // TODO: alter selection via selection method
3910  XBell(pDisplay, -100);
3911  }
3912  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3913  {
3914  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3915  pPrivate->xTextObject.vtable->cursor_down(&(pPrivate->xTextObject));
3916  }
3917  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+down
3918  {
3919  // TODO: what should this do?
3920  XBell(pDisplay, -100);
3921  }
3922  }
3923  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Up))
3924  {
3925  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3926  "%s - Page Up key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3927 
3928  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3929  {
3930  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3931  pPrivate->xTextObject.vtable->page_up(&(pPrivate->xTextObject));
3932  }
3933  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3934  {
3935  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3936  pPrivate->xTextObject.vtable->page_left(&(pPrivate->xTextObject));
3937  }
3938  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3939  {
3940  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3941  pPrivate->xTextObject.vtable->page_up(&(pPrivate->xTextObject));
3942  }
3943  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+PgUp
3944  {
3945  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3946  pPrivate->xTextObject.vtable->page_left(&(pPrivate->xTextObject));
3947  }
3948  }
3949  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Down))
3950  {
3951  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3952  "%s - Page Down key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3953 
3954  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3955  {
3956  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3957  pPrivate->xTextObject.vtable->page_down(&(pPrivate->xTextObject));
3958  }
3959  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // shift+ctrl
3960  {
3961  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3962  pPrivate->xTextObject.vtable->page_right(&(pPrivate->xTextObject));
3963  }
3964  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3965  {
3966  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3967  pPrivate->xTextObject.vtable->page_down(&(pPrivate->xTextObject));
3968  }
3969  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // ctrl+PgDown
3970  {
3971  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3972  pPrivate->xTextObject.vtable->page_right(&(pPrivate->xTextObject));
3973  }
3974  }
3975  else if(KEYSYM_MATCH_CURSOR_NAME(Begin)) // beginning of current line
3976  {
3977  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
3978  "%s - Beginning Of Line key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
3979 
3980  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
3981  {
3982  pPrivate->xTextObject.vtable->begin_highlight(&(pPrivate->xTextObject));
3983  if(pPrivate->xTextObject.vtable->get_col(&(pPrivate->xTextObject)))
3984  {
3985  pPrivate->xTextObject.vtable->cursor_home(&(pPrivate->xTextObject));
3986  }
3987  }
3988  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
3989  {
3990  pPrivate->xTextObject.vtable->end_highlight(&(pPrivate->xTextObject));
3991  if(pPrivate->xTextObject.vtable->get_col(&(pPrivate->xTextObject)))
3992  {
3993  pPrivate->xTextObject.vtable->cursor_home(&(pPrivate->xTextObject));
3994  }
3995  }
3996  }
3997  else if(KEYSYM_MATCH_CURSOR_NAME(Insert)) // toggle 'insert' mode
3998  {
3999  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4000  "%s - Insert key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
4001 
4002  if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
4003  {
4004  if(pPrivate->xTextObject.vtable->get_insmode(&(pPrivate->xTextObject))
4006  {
4007  pPrivate->xTextObject.vtable->set_insmode(&(pPrivate->xTextObject), InsertMode_INSERT);
4008  }
4009  else
4010  {
4012  }
4013  }
4014  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // SHIFT+insert (paste)
4015  {
4016  Atom aType = aUTF8_STRING;
4017  int iFormat = 8;
4018  unsigned long nData = 0;
4019 
4020  if(aType == None)
4021  {
4022  aType = aSTRING;
4023  }
4024 
4025  WB_ERROR_PRINT("TEMPORARY %s - SHIFT+insert key pressed\n", __FUNCTION__);
4026 
4027 // pData = (char *)CHGetSelectionData(pDisplay, aCLIPBOARD, aC_STRING, aC_STRING,
4028 // &aType, &iFormat, &nData);
4029  pData = (char *)WBGetClipboardData(pDisplay, &aType, &iFormat, &nData);
4030 
4031  if(pData && nData > 0)
4032  {
4033  if(!pData[nData])
4034  {
4035  nData--;
4036  }
4037  }
4038 
4039  if(pData)
4040  {
4041  // TODO: convert to correct format (ASCII)
4042  if(iFormat != 8)
4043  {
4044  if(iFormat == 8 * sizeof(wchar_t))
4045  {
4046  char *pNew = WBAlloc(sizeof(wchar_t) * (nData + 2));
4047  if(pNew)
4048  {
4049  memset(pNew, 0, sizeof(wchar_t) * (nData + 2));
4050  wcstombs(pNew, (const wchar_t *)pData, sizeof(wchar_t) * (nData + 2));
4051  }
4052 
4053  WBFree(pData);
4054  pData = pNew;
4055  }
4056  else
4057  {
4058  XBell(pDisplay, -100);
4059  WB_ERROR_PRINT("TEMPORARY - %s - clipboard format %d, can't 'PASTE'\n", __FUNCTION__, iFormat);
4060 
4061  WBFree(pData);
4062  pData = NULL;
4063  }
4064  }
4065 
4066  if(pData)
4067  {
4068  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
4069  {
4070  pPrivate->xTextObject.vtable->replace_select(&(pPrivate->xTextObject), pData, nData);
4071  }
4072  else
4073  {
4074  pPrivate->xTextObject.vtable->ins_chars(&(pPrivate->xTextObject), pData, nData);
4075  }
4076 
4077  WBFree(pData);
4078  pData = NULL; // by convention
4079  }
4080  else
4081  {
4082  XBell(pDisplay, -100);
4083  WB_ERROR_PRINT("TEMPORARY - %s - NULL pData, can't 'PASTE'\n", __FUNCTION__);
4084  }
4085  }
4086  else
4087  {
4088  XBell(pDisplay, -100);
4089  WB_ERROR_PRINT("TEMPORARY: NULL returned from WBGetClipboardData()\n");
4090  }
4091  }
4092  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // CTRL+insert (copy)
4093  {
4094  char *pData = pPrivate->xTextObject.vtable->get_sel_text(&(pPrivate->xTextObject), NULL);
4095 
4096  if(pData)
4097  {
4098  if(aUTF8_STRING != None)
4099  {
4100  WBSetClipboardData(pDisplay, aUTF8_STRING, 8, pData, strlen(pData) + 1);
4101  }
4102  else
4103  {
4104  WBSetClipboardData(pDisplay, aSTRING, 8, pData, strlen(pData) + 1);
4105  }
4106 
4107  WBFree(pData);
4108  }
4109  else
4110  {
4111  WB_ERROR_PRINT("TEMPORARY: NULL returned from get_sel_text()\n");
4112  }
4113  }
4114  }
4115  else if(KEYSYM_MATCH_CURSOR_NAME(Delete)) // delete key (keypad may use this)
4116  {
4117  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4118  "%s - Delete key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
4119 
4120  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift+del (cut)
4121  {
4122  // perform 'CUT'
4123  }
4124  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
4125  {
4126  if(pPrivate->xTextObject.vtable->has_select(&(pPrivate->xTextObject)))
4127  {
4128  pPrivate->xTextObject.vtable->del_select(&(pPrivate->xTextObject)); // delete selection
4129  }
4130  else
4131  {
4132  pPrivate->xTextObject.vtable->del_chars(&(pPrivate->xTextObject), 1); // delete the character to the right
4133  }
4134  }
4135 
4136  iRval = 1; // text changed
4137 
4138  // re-assign caption
4139  if(pSelf->pCaption)
4140  {
4141  WBFree(pSelf->pCaption);
4142  }
4143 
4144  pSelf->pCaption = pPrivate->xTextObject.vtable->get_text(&(pPrivate->xTextObject));
4145 
4146  iRval = 1; // text changed
4147  }
4148 #undef KEYSYM_MATCH_CURSOR_NAME
4149  else
4150  {
4151  // is it a cursor key? let's find out
4152  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4153  "%s - CURSOR KEY? %d (%08xH) %d (%08xH)\n",
4154  __FUNCTION__, iKey, iKey, iACS, iACS);
4155 
4156  iRval = 0; // force this for unknown key combinations
4157  }
4158  }
4159  }
4160 
4161  return iRval;
4162 }
4163 
4164 static int EditDoPointerEvent(XClientMessageEvent *pEvent, Display *pDisplay,
4165  Window wID, WBDialogControl *pSelf)
4166 {
4167 WBEditControl *pPrivate = (WBEditControl *)pSelf;
4168 int iACS;
4169 int iX, iY;
4170 
4171 
4172  if(pEvent->type != ClientMessage ||
4173  pEvent->message_type != aWB_POINTER)
4174  {
4175  return 0; // sanity check (temporary, remove later?)
4176  }
4177 
4178 
4179  // left-click - position cursor, cancel selection
4180  // shift-left-click - select from cursor to THIS point
4181  // (other modifiers, ignore the modifier key)
4182  // right-click - drop-down edit menu
4183  // middle click - select word? paste?
4184  // scroll wheel up/down - should be handled by scrollbar thingy
4185  // left-drag - select from starting position
4186  // right-drag - drag/drop?
4187  // middle-drag - ?
4188 
4189  // TODO: check which button I clicked - it's data.l[1] - WB_POINTER_BUTTON1 through WB_POINTER_BUTTON5 (bitmask)
4190 
4191  iACS = pEvent->data.l[2];
4192 
4193  iX = pEvent->data.l[3];
4194  iY = pEvent->data.l[4];
4195 
4196  switch(pEvent->data.l[0])
4197  {
4198  case WB_POINTER_CLICK:
4199 // WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_CLICK\n", __FUNCTION__);
4200  pPrivate->xTextObject.vtable->mouse_click(&(pPrivate->xTextObject), iX, iY, pEvent->data.l[1], iACS);
4201  break;
4202 
4203  case WB_POINTER_DBLCLICK:
4204  WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_DBLCLICK\n", __FUNCTION__);
4205  break;
4206 
4207  case WB_POINTER_DRAG:
4208 // WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_DRAG\n", __FUNCTION__);
4209  pPrivate->xTextObject.vtable->begin_mouse_drag(&(pPrivate->xTextObject));
4210  return wID; // do this to support pointer drag
4211 
4212  case WB_POINTER_DROP:
4213 // WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_DROP\n", __FUNCTION__);
4214  pPrivate->xTextObject.vtable->end_mouse_drag(&(pPrivate->xTextObject));
4215  break;
4216 
4217  case WB_POINTER_MOVE:
4218 // WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_MOVE\n", __FUNCTION__);
4219  pPrivate->xTextObject.vtable->mouse_click(&(pPrivate->xTextObject), iX, iY, 0, 0); // mouse motion only
4220  break;
4221 
4222  case WB_POINTER_CANCEL:
4223  WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_CANCEL\n", __FUNCTION__);
4224  break;
4225  case WB_POINTER_SCROLLUP:
4226  WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_SCROLLUP\n", __FUNCTION__);
4227  break;
4228  case WB_POINTER_SCROLLDOWN:
4229  WB_ERROR_PRINT("TEMPORARY - %s - WB_POINTER_SCROLLDOWN\n", __FUNCTION__);
4230  break;
4231 
4232 
4233  default:
4234 
4235  WB_ERROR_PRINT("TEMPORARY - %s - unhandled mousie message\n", __FUNCTION__);
4236  break;
4237  }
4238 
4239  return 0; // for now (necessary to avoid warnings, and NOT do bad stuff)
4240 }
4241 
4242 
4243 static int ListDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
4244  Window wID, WBDialogControl *pSelf)
4245 {
4246 int iRval = 0, iACS, iKey, nChar;//, iLen;
4247 //char *pBuf;
4248 
4249 
4250  iKey = pEvent->data.l[0]; // result from WBKeyEventProcessKey()
4251  iACS = pEvent->data.l[1];
4252  nChar = pEvent->data.l[2];
4253 // pBuf = (char *)&(pEvent->data.l[3]);
4254 
4255  if(nChar > 0) // normal ASCII characters
4256  {
4257  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4258  "%s KEY RELEASE for KEY %d KEYCODE %d MASK=%d (%xH)\n",
4259  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
4260  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
4261 
4262  return 0; // for now
4263 #if 0
4264  if(iKey == 8) // backspace
4265  {
4266  // TODO: delete char before cursor or highlighted text
4267  // for now just delete the LAST character
4268 
4269  iLen = strlen(pSelf->pCaption);
4270 
4271  if(iLen > 0)
4272  {
4273  pSelf->pCaption[iLen - 1] = 0;
4274  }
4275 
4276  WB_DEBUG_PRINT(DebugLevel_Excessive | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4277  "%s - BACKSPACE key pressed\n", __FUNCTION__);
4278  }
4279  else if(iKey == 13 || iKey == 10 // CR or LF (TODO: check flags to see if I should accept this)
4280  || iKey == 9) // tab (TODO: check flags to see if I should accept this)
4281  {
4282  // TODO: check for multi-line control, add line feeds as needed
4283 
4284  return 0; // LF may trigger default button, allow default handling
4285  // since the text was not changed return 0 _NOW_ so that WB_CHAR handling happens in default processing
4286  }
4287  else
4288  {
4289  // TODO: insert or concatenate? for now concatenate
4290  WBCatString(&(pSelf->pCaption), pBuf);
4291  }
4292 
4293  iRval = 1; // text changed
4294 #endif // 0
4295  }
4296  else
4297  {
4298  if(iACS & WB_KEYEVENT_KEYSYM)
4299  {
4300  // TODO: international, 'dead' and other KEYSYM key assignments
4301 #define KEYSYM_MATCH_CURSOR_NAME(X) (iKey == XK_##X || iKey == XK_KP_##X)
4302 
4303  if(KEYSYM_MATCH_CURSOR_NAME(Home))
4304  {
4305  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4306  "%s - Home key pressed\n", __FUNCTION__);
4307  }
4308  else if(KEYSYM_MATCH_CURSOR_NAME(End))
4309  {
4310  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4311  "%s - End key pressed\n", __FUNCTION__);
4312  }
4313  else if(KEYSYM_MATCH_CURSOR_NAME(Left))
4314  {
4315  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4316  "%s - Left key pressed\n", __FUNCTION__);
4317  }
4318  else if(KEYSYM_MATCH_CURSOR_NAME(Right))
4319  {
4320  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4321  "%s - Right key pressed\n", __FUNCTION__);
4322  }
4323  else if(KEYSYM_MATCH_CURSOR_NAME(Up))
4324  {
4325  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4326  "%s - Up key pressed\n", __FUNCTION__);
4327  }
4328  else if(KEYSYM_MATCH_CURSOR_NAME(Down))
4329  {
4330  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4331  "%s - Down key pressed\n", __FUNCTION__);
4332  }
4333  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Up))
4334  {
4335  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4336  "%s - Page Up key pressed\n", __FUNCTION__);
4337  }
4338  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Down))
4339  {
4340  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4341  "%s - Page Down key pressed\n", __FUNCTION__);
4342  }
4343  else if(KEYSYM_MATCH_CURSOR_NAME(Begin)) // beginning of current line
4344  {
4345  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4346  "%s - Beginning Of Line key pressed\n", __FUNCTION__);
4347  }
4348  else if(KEYSYM_MATCH_CURSOR_NAME(Insert)) // toggle 'insert' mode
4349  {
4350  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4351  "%s - Insert key pressed\n", __FUNCTION__);
4352  }
4353  else if(KEYSYM_MATCH_CURSOR_NAME(Delete)) // delete key (keypad may use this)
4354  {
4355  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4356  "%s - Delete key pressed\n", __FUNCTION__);
4357 
4358  // TODO: delete character under cursor
4359 
4360 // iRval = 1; // text changed
4361  iRval = 0; // for now...
4362  }
4363 #undef KEYSYM_MATCH_CURSOR_NAME
4364  else
4365  {
4366  // is it a cursor key? let's find out
4367  WB_DEBUG_PRINT(KEYSYM_DEBUG_FLAG | DebugSubSystem_Event | DebugSubSystem_DialogCtrl | DebugSubSystem_Keyboard,
4368  "%s - CURSOR KEY? %d (%08xH) %d (%08xH)\n",
4369  __FUNCTION__, iKey, iKey, iACS, iACS);
4370 
4371  iRval = 0; // force this for unknown key combinations
4372  }
4373  }
4374  }
4375 
4376  return iRval;
4377 }
4378 
4379 
4380 
4381 
4382 
4383 //*************
4384 // E X P O S E
4385 //*************
4386 
4387 
4388 static int StaticDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
4389  Window wID, WBDialogControl *pSelf)
4390 {
4391 int iHPos, iVPos, iType;
4392 XWindowAttributes xwa; /* Temp Get Window Attribute struct */
4393 XFontSet fontSet;
4394 XCharStruct xBounds;
4395 GC gc; // = WBGetWindowDefaultGC(wID);
4396 WB_GEOM geomPaint, geomBorder;
4397 
4398 
4399  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
4400  "%s - Expose %d (%08xH)\n", __FUNCTION__, (int)wID, (int)wID);
4401 
4402  if (XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
4403  {
4404  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4405  return 0;
4406  }
4407 
4408  fontSet = WBGetWindowFontSet(wID);
4409 
4410  if(fontSet == None)
4411  {
4412  // TODO: get font from dialog info
4413  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4414  return 0;
4415  }
4416 
4417  iHPos = WBFontSetAvgCharWidth(pDisplay, fontSet); // average char width for text border (TODO: RTL text ??)
4418  xBounds = WBFontSetMaxBounds(pDisplay, fontSet);
4419 
4420 
4421  // get graphics context copy and begin painting
4422  gc = WBBeginPaint(wID, pEvent, &geomPaint);
4423  if(!gc)
4424  {
4425  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4426  return 0;
4427  }
4428 
4429  iType = pSelf->ulFlags & STATIC_TYPEMASK; // different types paint differently
4430 
4431  //------------------
4432  // ERASE BACKGROUND
4433  //------------------
4434 
4435  WBClearWindow(wID, gc);
4436 
4437  // 3D border
4438  if(iType == STATIC_Frame)
4439  {
4440  geomBorder.x = 0;
4441  geomBorder.y = xBounds.ascent + xBounds.descent + 2;
4442  geomBorder.width = xwa.width - geomBorder.x;
4443  geomBorder.height = xwa.height - geomBorder.y;
4444 
4445  // this text will apear in the upper left corner (sort of) of the border rectangle
4446 
4447  iVPos = xwa.border_width; // top of text at top of window
4448  iVPos += xBounds.ascent; // base of text
4449  }
4450  else
4451  {
4452  geomBorder.x = 0;
4453  geomBorder.y = 0;
4454  geomBorder.width = xwa.width - geomBorder.x;
4455  geomBorder.height = xwa.height - geomBorder.y;
4456 
4457  // vertically centered text (includes if it has a 3D border, below)
4458  iVPos = xBounds.ascent + xBounds.descent; // font height
4459  iVPos = (xwa.height - iVPos) >> 1; // half of the difference, now the top of text
4460  iVPos += xBounds.ascent; // add ascent back (base of text)
4461  }
4462 
4463  if(pSelf->ulFlags & STATIC_3DBorder)
4464  {
4465  // I will continue to allow for a focus border [for some this may be needed]
4466  // even if 'NO_BORDER' has been specified.
4467 
4469  {
4470  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
4471  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4472 
4473  geomBorder.x++;
4474  geomBorder.y++;
4475  geomBorder.height -= 2;
4476  geomBorder.width -= 2;
4477  }
4478 
4480  {
4481  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
4482  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
4483  }
4484  }
4485 
4486  // painting the window text
4487 
4488  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
4489 
4490  // where I put the text matters based on the control type (see iHPos, iVPos)
4491  if(iType == STATIC_Icon || iType == STATIC_Image)
4492  {
4493  Pixmap pixmap = ((struct _WB_IMAGE_CONTROL_ *)pSelf)->pixmap;
4494  Pixmap pixmap2 = ((struct _WB_IMAGE_CONTROL_ *)pSelf)->pixmap2;
4495 
4496  // TODO: get the image's geometry so I can properly center it (etc.)
4497 
4498  if(pixmap != None) // for now assume 36x36 icon only
4499  {
4500  if(pixmap2 != None) // an icon mask exists
4501  {
4502  GC gc2 = WBGetWindowCopyGC2(wID, gc);
4503 
4504  if(gc2 == None)
4505  {
4506  gc2 = WBGetWindowCopyGC(wID);
4507  }
4508 
4509  if(gc2 != None) // painting the icon the way I think it should be...
4510  {
4511  XSetClipOrigin(pDisplay, gc2, geomBorder.x + 2, geomBorder.y + 2);
4512  XSetClipMask(pDisplay, gc2, pixmap2);
4513  XCopyArea(pDisplay, pixmap, wID, gc2, 0, 0, 36, 36, geomBorder.x + 2, geomBorder.y + 2);
4514  XFreeGC(pDisplay, gc2);
4515  }
4516  else
4517  {
4518  WB_WARN_PRINT("%s - WARNING: unable to create GC copy to use bitmask to paint icon\n", __FUNCTION__);
4519  XCopyArea(pDisplay, pixmap, wID, gc, 0, 0, 36, 36, geomBorder.x + 2, geomBorder.y + 2);
4520  }
4521  }
4522  else
4523  {
4524  XCopyArea(pDisplay, pixmap, wID, gc, 0, 0, 36, 36, geomBorder.x + 2, geomBorder.y + 2);
4525  }
4526  }
4527  }
4528  else if(pSelf->pCaption)
4529  {
4530  WB_RECT rctText;
4531 
4532  long iAlign = DTAlignment_UNDERSCORE;
4533  int iHAlignFlags = pSelf->pDlgControlEntry->iFlags & WBDialogEntry_HA_TEXT_MASK;
4534  int iVAlignFlags = pSelf->pDlgControlEntry->iFlags & WBDialogEntry_VA_TEXT_MASK;
4535 
4536  if(iHAlignFlags == WBDialogEntry_HA_TEXT_LEFT)
4537  {
4538  iAlign |= DTAlignment_HLEFT;
4539  }
4540  else if(iHAlignFlags == WBDialogEntry_HA_TEXT_RIGHT)
4541  {
4542  iAlign |= DTAlignment_HRIGHT;
4543  }
4544  else if(iHAlignFlags == WBDialogEntry_HA_TEXT_CENTER)
4545  {
4546  iAlign |= DTAlignment_HCENTER;
4547  }
4548 
4549  if(iVAlignFlags == WBDialogEntry_VA_TEXT_TOP)
4550  {
4551  iAlign |= DTAlignment_VTOP;
4552  }
4553  else if(iVAlignFlags == WBDialogEntry_VA_TEXT_BOTTOM)
4554  {
4555  iAlign |= DTAlignment_VBOTTOM;
4556  }
4557  else if(iVAlignFlags == WBDialogEntry_VA_TEXT_CENTER)
4558  {
4559  iAlign |= DTAlignment_VCENTER;
4560  }
4561 
4562 // rctText.left = geomBorder.x + iHPos;
4563 // rctText.right = rctText.left + geomBorder.width - 2 * iHPos;
4564 // rctText.top = geomBorder.y + xBounds.ascent / 2;
4565 // rctText.bottom = rctText.top + geomBorder.height - xBounds.ascent;
4566 
4567  rctText.left = geomBorder.x;
4568  rctText.right = geomBorder.x + geomBorder.width;
4569  rctText.top = geomBorder.y;
4570  rctText.bottom = geomBorder.y + geomBorder.height;
4571 
4572  DTDrawMultiLineText(fontSet, pSelf->pCaption, pDisplay, gc, wID, DEFAULT_STATIC_TAB_WIDTH, 0,
4573  &rctText, iAlign); //DTAlignment_UNDERSCORE | DTAlignment_VCENTER);
4574  }
4575 
4576  // by convention, restore original objects/state
4577 
4579  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
4581 
4582  WBEndPaint(wID, gc);
4583 
4584  return 1; // processed
4585 }
4586 
4587 
4588 static int EditDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
4589  Window wID, WBDialogControl *pSelf)
4590 {
4591 WBEditControl *pPrivate = (WBEditControl *)pSelf;
4592 XWindowAttributes xwa; /* Temp Get Window Attribute struct */
4593 XFontSet fontSet;
4594 GC gc; // = WBGetWindowDefaultGC(wID);
4595 WB_GEOM geomPaint, geomBorder;
4596 
4597 
4598  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
4599  "%s - Expose %d (%08xH)\n", __FUNCTION__, (int)wID, (int)wID);
4600 
4601  if (XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
4602  {
4603  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4604  return 0;
4605  }
4606 
4607  fontSet = WBGetWindowFontSet(wID);
4608 
4609  if(fontSet == None)
4610  {
4611  // TODO: get font from dialog info
4612  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4613  return 0;
4614  }
4615 
4616 
4617  // get graphics context copy and begin painting
4618  gc = WBBeginPaint(wID, pEvent, &geomPaint);
4619  if(!gc)
4620  {
4621  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4622  return 0;
4623  }
4624 
4625  // font setup
4626  WBClearWindow(wID, gc);
4627 
4628  geomBorder.x = 0;
4629  geomBorder.y = 0;
4630  geomBorder.width = xwa.width - geomBorder.x;
4631  geomBorder.height = xwa.height - geomBorder.y;
4632 
4633  // TODO: scrollbars, 'display window' scroll position within physical display
4634 
4635 // TODO: uncomment these when iVPos needs to be used - linux gcc warning avoidance
4636 // // vertically centered text (for single-line version)
4637 // iVPos = pFont->max_bounds.ascent + pFont->max_bounds.descent; // font height
4638 // iVPos = (xwa.height - iVPos) >> 1; // half of the difference - top of text
4639 // iVPos += pFont->max_bounds.ascent;
4640 
4641  if(pSelf->pOwner && pSelf->pDlgControlEntry) //pSelf->ulFlags & STATIC_3DBorder)
4642  {
4644  {
4645  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
4646  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
4647  }
4648  else // draw a thin, 2D border
4649  {
4650  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
4651  pSelf->clrBG.pixel);
4652  }
4653  }
4654 
4655 // WB_ERROR_PRINT("TEMPORARY: %s - caption is \"%s\"\n", __FUNCTION__, pSelf->pCaption);
4656 
4657  geomBorder.x += 4;
4658  geomBorder.y += 4;
4659  geomBorder.width -= 8;
4660  geomBorder.height -= 8;
4661 
4662  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
4663 
4664  pPrivate->xTextObject.vtable->do_expose(&(pPrivate->xTextObject), pDisplay, wID,
4665  gc, &geomPaint, &geomBorder, fontSet);
4666 
4667 
4668 #if 0
4669 
4670  // painting the window text
4671 
4672  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
4673 
4674  if(pSelf->pCaption) // use TEXT not caption
4675  {
4676  const char *szText = pSelf->pCaption;
4677  int iU1=0, iU2=0;
4678 
4679 // if(i1 == pSelf->iSelected) // text selection
4680 // {
4681 // XSetForeground(pDisplay, gc, pSelf->clrABG.pixel);
4682 // XSetBackground(pDisplay, gc, pSelf->clrABG.pixel);
4683 //
4684 // XFillRectangle(pDisplay, wID, gc, pItem->iPosition, pSelf->iY, pItem->iTextWidth, pSelf->iHeight + 2);
4685 //
4686 // XSetForeground(pDisplay, gc, pSelf->clrAFG.pixel);
4687 // }
4688 
4689 #if 0
4690  if(strchr(szText, '_')) // underline in text? TODO: use this info to set hotkey
4691  {
4692  char *p1;
4693  strcpy(tbuf, szText);
4694  p1 = tbuf;
4695  while(*p1)
4696  {
4697  if(*p1 == '_')
4698  {
4699  *p1 = 0;
4700 
4701  if(p1 == tbuf)
4702  iU1 = 0;
4703  else
4704  iU1 = XTextWidth(pFont, tbuf, p1 - tbuf);
4705 
4706  if(p1[1])
4707  {
4708  iU2 = XTextWidth(pFont, p1, 1);
4709  strcpy(p1, p1 + 1);
4710  }
4711  else
4712  iU2 = iU1; // shouldn't happen
4713  }
4714  p1++;
4715  }
4716 
4717  szText = tbuf;
4718  }
4719 #endif // 0
4720 
4721  // TODO: use DTDrawSingleLineText or DTDrawMultiLineText instead
4722 
4723  if(*szText)
4724  {
4725  XDrawString(pDisplay, wID, gc, iHPos, iVPos, szText, strlen(szText));
4726  }
4727 
4728 // if(i1 == pSelf->iSelected) // selected item
4729 // {
4730 // XSetForeground(pDisplay, gc, clrMenuFG.pixel);
4731 // XSetBackground(pDisplay, gc, clrMenuBG.pixel);
4732 // }
4733  }
4734 
4735 #endif // 0
4736 
4737  // by convention, restore original objects/state
4738 
4740  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
4742 
4743  WBEndPaint(wID, gc);
4744 
4745  return 1; // processed
4746 }
4747 
4748 
4749 static int ButtonDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
4750  Window wID, WBDialogControl *pSelf)
4751 {
4752 int iType;
4753 XWindowAttributes xwa; /* Temp Get Window Attribute struct */
4754 XFontSet fontSet;
4755 XCharStruct xBounds;
4756 GC gc; // = WBGetWindowDefaultGC(wID);
4757 WB_GEOM geomPaint, geomBorder, geomBox;
4758 WB_RECT rctText;
4759 
4760 
4761  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
4762  "%s - Expose %d (%08xH)\n", __FUNCTION__, (int)wID, (int)wID);
4763 
4764  if (XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
4765  {
4766  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4767  return 0;
4768  }
4769 
4770  fontSet = WBGetWindowFontSet(wID);
4771 
4772  if(fontSet == None)
4773  {
4774  // TODO: get font from dialog info
4775  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4776  return 0;
4777  }
4778 
4779  xBounds = WBFontSetMaxBounds(pDisplay, fontSet);
4780 
4781  // get graphics context copy and begin painting
4782  gc = WBBeginPaint(wID, pEvent, &geomPaint);
4783  if(!gc)
4784  {
4785  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
4786  return 0;
4787  }
4788 
4789  WBClearWindow(wID, gc);
4790 
4791  iType = pSelf->ulFlags & BUTTON_TYPEMASK;
4792 
4793  if(iType == BUTTON_CheckButton || iType == BUTTON_TriStateButton)
4794  {
4795  geomBorder.x = xwa.border_width;
4796  geomBorder.y = xwa.border_width;
4797  geomBorder.width = xwa.width - xwa.border_width;
4798  geomBorder.height = xwa.height - xwa.border_width;
4799 
4801  {
4802  WBDrawDashedRect(pDisplay, wID, gc, &geomBorder,
4803  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4804  }
4805 
4806  // use the font's ascent value as the size of my 'x' box
4807 
4808  geomBox.x = geomBorder.x + (geomBorder.height - xBounds.ascent) / 2;
4809  geomBox.y = geomBorder.y + (geomBorder.height - xBounds.ascent - 2) / 2;
4810  geomBox.width = xBounds.ascent + 2;
4811  geomBox.height = xBounds.ascent + 2;
4812 
4813  // fill checkbox part with white, or for tri-stated state, use grey (background)
4815  {
4816  XSetForeground(pDisplay, gc, WBGetWindowBGColor(wID));
4817  }
4818  else
4819  {
4821  {
4822  XSetForeground(pDisplay, gc, pSelf->clrAFG.pixel);
4823  }
4824  else
4825  {
4826  XSetForeground(pDisplay, gc, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
4827  }
4828  }
4829 
4830  XFillRectangle(pDisplay, wID, gc, geomBox.x, geomBox.y, geomBox.width, geomBox.height);
4831 
4832  // draw checkbox as an 'innie'
4833  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBox, pSelf->clrBD3.pixel, pSelf->clrBD2.pixel);
4834 
4835  geomBox.x ++; // remaining area should be inside of the 3D border now
4836  geomBox.y ++;
4837  geomBox.width -= 2;
4838  geomBox.height -= 2;
4839 
4840  XSetForeground(pDisplay, gc, BlackPixel(pDisplay, DefaultScreen(pDisplay))); // make sure black foreground
4841 
4842  // now draw the 'x' as appropriate, but not for a tri-stated control
4844  {
4846  {
4847  XSetForeground(pDisplay, gc, pSelf->clrABG.pixel);
4848  }
4849  else
4850  {
4851  XSetForeground(pDisplay, gc, BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4852  }
4853 
4855  {
4856  XPoint xpt[2];
4857  // center a small X within geomBox
4858 
4859  xpt[0].x = geomBox.x + geomBox.width / 4;
4860  xpt[0].y = geomBox.y + geomBox.height / 4;
4861  xpt[1].x = geomBox.x + 3 * geomBox.width / 4 - 1;
4862  xpt[1].y = geomBox.y + 3 * geomBox.height / 4;
4863 
4864  XDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
4865 
4866  xpt[0].x++;
4867  xpt[1].x++;
4868  XDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
4869 
4870  xpt[0].x = geomBox.x + geomBox.width / 4;
4871  xpt[1].y = geomBox.y + geomBox.height / 4;
4872  xpt[1].x = geomBox.x + 3 * geomBox.width / 4 - 1;
4873  xpt[0].y = geomBox.y + 3 * geomBox.height / 4;
4874 
4875  XDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
4876 
4877  xpt[0].x++;
4878  xpt[1].x++;
4879  XDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
4880 
4881 // // draw the 'x' as text [why not!]
4882 //
4883 // rctText.left = geomBox.x;
4884 // rctText.right = geomBox.x + geomBox.width;
4885 // rctText.top = geomBox.y; // + xBounds.ascent / 2
4886 // //- xBounds.descent / 2; // better centering
4887 // rctText.bottom = rctText.top + geomBox.height; // - xBounds.ascent;
4888 //
4889 // DTDrawSingleLineText(fontSet, "x", pDisplay, gc, wID, 0, 0, &rctText, // TODO: use bold font?
4890 // DTAlignment_HCENTER | DTAlignment_VCENTER);
4891  }
4892  }
4893 
4894  // fix the border so it's "just the text part"
4895  geomBorder.x += geomBox.width + (geomBorder.height - xBounds.ascent); // where the text will be
4896  geomBorder.width -= geomBox.width + (geomBorder.height - xBounds.ascent); // and the adjusted width
4897  }
4898  else if(iType == BUTTON_RadioButton || iType == BUTTON_FirstRadioButton)
4899  {
4900  geomBorder.x = xwa.border_width;
4901  geomBorder.y = xwa.border_width;
4902  geomBorder.width = xwa.width - xwa.border_width;
4903  geomBorder.height = xwa.height - xwa.border_width;
4904 
4906  {
4907  WBDrawDashedRect(pDisplay, wID, gc, &geomBorder,
4908  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4909  }
4910 
4911  // use the font's ascent value as the size of my 'x' box
4912 
4913  geomBox.x = geomBorder.x + (geomBorder.height - xBounds.ascent) / 2;
4914  geomBox.y = geomBorder.y + (geomBorder.height - xBounds.ascent - 2) / 2;
4915  geomBox.width = xBounds.ascent + 2;
4916  geomBox.height = xBounds.ascent + 2;
4917 
4918  // set the 'fill' color based on the button state
4920  {
4921  XSetForeground(pDisplay, gc, pSelf->clrAFG.pixel);
4922  }
4923  else
4924  {
4925  XSetForeground(pDisplay, gc, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
4926  }
4927 
4928  // fill in the circle bounded by geomBox.
4930  XFillArc(pDisplay, wID, gc,
4931  geomBox.x, geomBox.y,
4932  geomBox.width, geomBox.height,
4933  0, 360 * 64); // full circle
4935 
4936 
4938  {
4939  WBDraw3DBorderElipse(pDisplay, wID, gc, &geomBox,
4940  pSelf->clrBD3.pixel, pSelf->clrBD2.pixel);
4941  }
4942  else
4943  {
4944  WBDraw3DBorderElipse(pDisplay, wID, gc, &geomBox,
4945  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
4946  }
4947 
4948  // now, draw a filled-in circle that's half the width of the outer part
4949  // if the button is 'checked'
4950 
4952  {
4953  XSetForeground(pDisplay, gc, BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4954 
4956  XFillArc(pDisplay, wID, gc,
4957  geomBox.x + geomBox.width / 4,
4958  geomBox.y + geomBox.height / 4,
4959  geomBox.width - 2 * (geomBox.width / 4),
4960  geomBox.height - 2 * (geomBox.height / 4),
4961  0, 360 * 64); // full circle
4963  }
4964 
4965  // fix the border so it's "just the text part"
4966  geomBorder.x += geomBox.width + (geomBorder.height - xBounds.ascent); // where the text will be
4967  geomBorder.width -= geomBox.width + (geomBorder.height - xBounds.ascent); // and the adjusted width
4968  }
4969  else // uknown button type - paint it like a button, for now
4970  {
4971  // paint the 3D-looking border
4972 
4973  geomBorder.x = xwa.border_width;
4974  geomBorder.y = xwa.border_width;
4975  geomBorder.width = xwa.width - xwa.border_width;
4976  geomBorder.height = xwa.height - xwa.border_width;
4977 
4979  {
4980  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
4981  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
4982  geomBorder.x++;
4983  geomBorder.y++;
4984  geomBorder.height -= 2;
4985  geomBorder.width -= 2;
4986  }
4987 
4988  // note - if a button is 'pressed' I draw the colors inverted
4989 
4991  {
4992  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
4993  pSelf->clrBD3.pixel, pSelf->clrBD2.pixel);
4994  }
4995  else
4996  {
4997  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
4998  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
4999  }
5000  }
5001 
5002 // // painting the window text
5003 // i2 = WBFontSetAvgCharWidth(pDisplay, fontSet); // average char width for text border (TODO: RTL text ??)
5004 // iHPos = xwa.border_width + i2; // position of beginning of text (left side + space)
5005 
5006 #if 0
5007  iVPos = pFont->max_bounds.ascent + pFont->max_bounds.descent; // font height
5008  iVPos = (xwa.height - iVPos) >> 1; // half of the difference - top of text
5009  iVPos += pFont->max_bounds.ascent;
5010 #endif // 0
5011 
5012  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
5013 
5014  if(pSelf->pCaption)
5015  {
5016  const char *szText = pSelf->pCaption;
5017  long iAlign = DTAlignment_UNDERSCORE;
5018  int iHAlignFlags = pSelf->pDlgControlEntry->iFlags & WBDialogEntry_HA_TEXT_MASK;
5019  int iVAlignFlags = pSelf->pDlgControlEntry->iFlags & WBDialogEntry_VA_TEXT_MASK;
5020 
5021  if(iHAlignFlags == WBDialogEntry_HA_TEXT_LEFT)
5022  {
5023  iAlign |= DTAlignment_HLEFT;
5024  }
5025  else if(iHAlignFlags == WBDialogEntry_HA_TEXT_RIGHT)
5026  {
5027  iAlign |= DTAlignment_HRIGHT;
5028  }
5029  else if(iHAlignFlags == WBDialogEntry_HA_TEXT_CENTER)
5030  {
5031  iAlign |= DTAlignment_HCENTER;
5032  }
5033 
5034  if(iVAlignFlags == WBDialogEntry_VA_TEXT_TOP)
5035  {
5036  iAlign |= DTAlignment_VTOP;
5037  }
5038  else if(iVAlignFlags == WBDialogEntry_VA_TEXT_BOTTOM)
5039  {
5040  iAlign |= DTAlignment_VBOTTOM;
5041  }
5042  else if(iVAlignFlags == WBDialogEntry_VA_TEXT_CENTER)
5043  {
5044  iAlign |= DTAlignment_VCENTER;
5045  }
5046 
5047  XSetBackground(pDisplay, gc, pSelf->clrABG.pixel);
5048  XSetForeground(pDisplay, gc, pSelf->clrAFG.pixel);
5049 
5050 // rctText.left = geomBorder.x + iHPos;
5051 // rctText.right = rctText.left + geomBorder.width - 2 * iHPos;
5052 // rctText.top = geomBorder.y + xBounds.ascent / 2
5053 // - xBounds.descent / 2; // better centering
5054 // rctText.bottom = rctText.top + geomBorder.height - xBounds.ascent;
5055 
5056  rctText.left = geomBorder.x;
5057  rctText.right = geomBorder.x + geomBorder.width;
5058  rctText.top = geomBorder.y;
5059  rctText.bottom = geomBorder.y + geomBorder.height;
5060 
5061  DTDrawMultiLineText(fontSet, szText, pDisplay, gc, wID, DEFAULT_BUTTON_TAB_WIDTH, 0,
5062  &rctText, iAlign);
5063  }
5064 
5065  // by convention, restore original objects/state
5066 
5068  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
5070 
5071  WBEndPaint(wID, gc);
5072 
5073  return 1; // processed
5074 }
5075 
5076 
5077 static int PushButtonDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
5078  Window wID, WBDialogControl *pSelf)
5079 {
5080 int i2, iHPos;
5081 XWindowAttributes xwa; /* Temp Get Window Attribute struct */
5082 XFontSet fontSet;
5083 XCharStruct xBounds;
5084 GC gc; // = WBGetWindowDefaultGC(wID);
5085 WB_GEOM geomPaint, geomBorder;
5086 
5087 
5088  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
5089  "%s - Expose %d (%08xH)\n", __FUNCTION__, (int)wID, (int)wID);
5090 
5091  if(XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
5092  {
5093  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5094  return 0;
5095  }
5096 
5097  fontSet = WBGetWindowFontSet(wID); // I assigned the "bold font" to this on create
5098 
5099  if(fontSet == None)
5100  {
5101  // TODO: get font from dialog info
5102  WB_ERROR_PRINT("%s - NO FONT, line %d\n", __FUNCTION__, __LINE__);
5103  return 0;
5104  }
5105 
5106  xBounds = WBFontSetMaxBounds(pDisplay, fontSet);
5107 
5108  // get graphics context copy and begin painting
5109  gc = WBBeginPaint(wID, pEvent, &geomPaint);
5110 
5111  if(!gc)
5112  {
5113  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5114 
5115  return 0;
5116  }
5117 
5118  WBClearWindow(wID, gc);
5119 
5120  // paint the 3D-looking border
5121 
5122  geomBorder.x = xwa.border_width;
5123  geomBorder.y = xwa.border_width;
5124  geomBorder.width = xwa.width - xwa.border_width;
5125  geomBorder.height = xwa.height - xwa.border_width;
5126 
5127  if(pSelf->pDlgControlEntry->iFlags & WBDialogEntry_DEFAULT) // I am the default pushbutton
5128  {
5129  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
5130  pSelf->clrBD3.pixel);
5131 
5132  geomBorder.x++;
5133  geomBorder.y++;
5134  geomBorder.height -= 2;
5135  geomBorder.width -= 2;
5136  }
5137 
5139  {
5140  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
5141  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
5142 
5143  geomBorder.x++;
5144  geomBorder.y++;
5145  geomBorder.height -= 2;
5146  geomBorder.width -= 2;
5147  }
5148 
5149  // note - if a button is 'pressed' I draw the colors inverted
5150 
5152  {
5153  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
5154  pSelf->clrBD3.pixel, pSelf->clrBD2.pixel);
5155  }
5156  else
5157  {
5158  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
5159  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
5160  }
5161 
5162  // painting the window text
5163 
5164  i2 = WBFontSetAvgCharWidth(pDisplay, fontSet); // average char width for text border (TODO: RTL text ??)
5165  iHPos = xwa.border_width + i2; // position of beginning of text (left side + space)
5166 #if 0
5167  iVPos = pFont->max_bounds.ascent + pFont->max_bounds.descent; // font height
5168  iVPos = (xwa.height - iVPos) >> 1; // half of the difference - top of text
5169  iVPos += pFont->max_bounds.ascent;
5170 #endif // 0
5171 
5172  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
5173 
5174  // TODO: icon button (rather than text) or combination icon/text
5175 
5176  if(pSelf->pCaption)
5177  {
5178  WB_RECT rctText;
5179  const char *szText = pSelf->pCaption;
5180 
5181  XSetBackground(pDisplay, gc, pSelf->clrABG.pixel);
5182  XSetForeground(pDisplay, gc, pSelf->clrAFG.pixel);
5183 
5184  rctText.left = geomBorder.x + iHPos;
5185  rctText.right = rctText.left + geomBorder.width - 2 * iHPos;
5186  rctText.top = geomBorder.y + xBounds.ascent / 2
5187  - xBounds.descent / 2; // better centering
5188  rctText.bottom = rctText.top + geomBorder.height - xBounds.ascent;
5189 
5190  DTDrawMultiLineText(fontSet, szText, pDisplay, gc, wID, DEFAULT_BUTTON_TAB_WIDTH, 0, &rctText,
5192  }
5193 
5194  // by convention, restore original objects/state
5195 
5197  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
5199 
5200  WBEndPaint(wID, gc);
5201 
5202  return 1; // processed
5203 }
5204 
5205 
5206 static int ListDoExposeEvent(XExposeEvent *pEvent, Display *pDisplay,
5207  Window wID, WBDialogControl *pSelf)
5208 {
5209 int i1, iVScrollWidth, iHScrollHeight;
5210 int nHeight, nItemHeight;
5211 XWindowAttributes xwa; /* Temp Get Window Attribute struct */
5212 XFontSet fontSet;
5213 XCharStruct xBounds;
5214 GC gc;
5215 Region rgnTemp;
5216 WB_GEOM geomPaint, geomBorder;
5217 WB_SCROLLINFO *pScrollInfo;
5218 LISTINFO *pListInfo;
5219 WB_DIALOG_PROP *pProp;
5220 
5221 
5222  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
5223  "%s - Expose %d (%08xH)\n", __FUNCTION__, (int)wID, (int)wID);
5224 
5225  if(XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
5226  {
5227  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5228  return 0;
5229  }
5230 
5231  fontSet = WBGetWindowFontSet(wID);
5232 
5233  if(fontSet == None)
5234  {
5235  // TODO: get font from dialog info
5236  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5237  return 0;
5238  }
5239 
5240  xBounds = WBFontSetMaxBounds(pDisplay, fontSet);
5241 
5242  // get graphics context copy and begin painting
5243  gc = WBBeginPaint(wID, pEvent, &geomPaint);
5244  if(!gc)
5245  {
5246  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5247  return 0;
5248  }
5249 
5250 
5251  geomBorder.x = 0;
5252  geomBorder.y = 0;
5253  geomBorder.width = xwa.width - geomBorder.x;
5254  geomBorder.height = xwa.height - geomBorder.y;
5255  geomBorder.border = 0; // no additional window border [this MUST be assigned]
5256 
5258  {
5259  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
5260  BlackPixel(pDisplay, DefaultScreen(pDisplay)));
5261  }
5262  else
5263  {
5264  // use the background color for the dialog window itself
5265  WBDrawBorderRect(pDisplay, wID, gc, &geomBorder,
5266  pSelf->pOwner ? pSelf->pOwner->clrBG.pixel : pSelf->clrABG.pixel);
5267  }
5268 
5269  geomBorder.x++;
5270  geomBorder.y++;
5271  geomBorder.height -= 2;
5272  geomBorder.width -= 2;
5273 
5274  // calculate a few things
5275 
5276  iVScrollWidth = WBTextWidth(fontSet, "X", 1) * 2 + 4; // width of vertical scrollbar
5277  iHScrollHeight = xBounds.ascent + xBounds.descent + 4;
5278 
5280 
5281  if(pProp)
5282  {
5283  pListInfo = (LISTINFO *)pProp->pVal;
5284  }
5285  else
5286  {
5287  pListInfo = NULL;
5288 
5289  WBClearWindow(wID, gc);
5290 // XClearWindow(pDisplay, wID); // only necessary when there's no list info
5291  }
5292 
5293  // border
5294  WBDraw3DBorderRect(pDisplay, wID, gc, &geomBorder,
5295  pSelf->clrBD2.pixel, pSelf->clrBD3.pixel);
5296 
5297  // again reduce the size of the border rectangle by 1 pixel on all sides
5298  geomBorder.x++;
5299  geomBorder.y++;
5300  geomBorder.height -= 2;
5301  geomBorder.width -= 2;
5302 
5303  // painting the scrollbar (assume vertical only)
5304 
5306  if(!pScrollInfo)
5307  {
5308  pScrollInfo = (WB_SCROLLINFO *)WBAlloc(sizeof(*pScrollInfo));
5309  if(!pScrollInfo)
5310  {
5311  WB_ERROR_PRINT("%s:%d Out Of Memory\n", __FUNCTION__, __LINE__);
5312  return -1;
5313  }
5314 
5315  bzero(pScrollInfo, sizeof(*pScrollInfo));
5316  }
5317 
5318  // what is the height of the dialog box in 'items'? For now an item's height is
5319  // equal to pFont->max_bounds.ascent + pFont->max_bounds.descent + 6;
5320 
5321  nItemHeight = xBounds.ascent + xBounds.descent + 6;
5322  nHeight = (geomBorder.height - 4) / nItemHeight; // assume no horizontal scrollbar
5323 
5324  if(!pListInfo || pListInfo->nItems <= nHeight)
5325  {
5326  WBCalcVScrollBar(pScrollInfo, &geomBorder, iVScrollWidth, iHScrollHeight, 0, -1);
5327 
5328  if(pListInfo) // TODO: allocate empty list info
5329  {
5330  pListInfo->nTop = 0;
5331  pListInfo->nPos = -1; // "N/A"
5332  }
5333  }
5334  else
5335  {
5336  WBCalcVScrollBar(pScrollInfo, &geomBorder, iVScrollWidth, iHScrollHeight,
5337  pListInfo->nItems - nHeight + 1, pListInfo->nTop);
5338  if(pListInfo->nPos < 0)
5339  {
5340  pListInfo->nPos = pListInfo->nTop;
5341  }
5342  }
5343 
5344 // WB_ERROR_PRINT("TEMPORARY: %s - V scroll bar geomBorder %d,%d,%d,%d\n", __FUNCTION__,
5345 // geomBorder.x, geomBorder.y, geomBorder.width, geomBorder.height);
5346 
5347  if(pListInfo)
5348  {
5349  pListInfo->nHeight = nHeight; // cache this
5350  pListInfo->nItemHeight = nItemHeight;
5351  }
5352 
5353  WBDialogControlSetProperty2(pSelf, aDLGC_SCROLLINFO, pScrollInfo); // store updated scroll info (in case it changed)
5354 
5355  WBPaintVScrollBar(pScrollInfo, pDisplay, wID, gc, &geomBorder); // for now use 'border' geometry, later fix?
5356 
5357  // set the border rectangle so that it excludes scrollbar
5358  geomBorder.width = pScrollInfo->geomVBar.x
5359  - pScrollInfo->geomVBar.border
5360  - geomBorder.x;
5361 
5362  // painting the window text
5363  // FIRST, make sure that the bounding rectangle for painting
5364  // does NOT exceed geomBorder by setting the new clip region
5365 
5366  rgnTemp = WBGetPaintRegion(wID); // current paint region
5367 
5368  if(rgnTemp != None)
5369  {
5370  Region rgnTemp2 = WBGeomToRegion(&geomBorder);
5371  if(rgnTemp2 != None)
5372  {
5373  XIntersectRegion(rgnTemp2, rgnTemp, rgnTemp);
5374  XDestroyRegion(rgnTemp2);
5375 
5376  XSetRegion(pDisplay, gc, rgnTemp); // my new clipping region
5377  }
5378 
5379  XDestroyRegion(rgnTemp); // must destroy now
5380  }
5381 
5382  XSetForeground(pDisplay, gc, pSelf->clrFG.pixel);
5383 
5384  if(pListInfo) // use TEXT not caption
5385  {
5386  for(i1=pListInfo->nTop; i1 <= pListInfo->nTop + nHeight; i1++)
5387  {
5388  WB_GEOM geomItem;
5389 
5390  geomItem.x = geomBorder.x + 1;
5391  geomItem.width = geomBorder.width - 2;
5392  geomItem.y = geomBorder.y + nItemHeight * (i1 - pListInfo->nTop);
5393  geomItem.height = nItemHeight;
5394 
5395 // if(i1 == pListInfo->nPos) // the currently selected item
5396 // {
5397 // WB_ERROR_PRINT("TEMPORARY - drawing selected item %d\n", i1);
5398 // }
5399 // else
5400 // {
5401 // WB_ERROR_PRINT("TEMPORARY - NOT drawing selected item %d (%d)\n", i1, pListInfo->nPos);
5402 //
5403 // }
5404 
5405  if(i1 < pListInfo->nItems)
5406  {
5407  if(pListInfo->pfnDisplay)// void (*pfnDisplay)(WBDialogControl *pControl, void *pData, int iSelected, GC gcPaint, WB_GEOM *pGeom);
5408  {
5409  pListInfo->pfnDisplay(pSelf, pListInfo->aItems[i1], i1 == pListInfo->nPos, gc, &geomItem, fontSet);
5410  }
5411  else
5412  {
5413  DLGCDefaultListControlDisplayProc(pSelf, pListInfo->aItems[i1], i1 == pListInfo->nPos, gc, &geomItem, fontSet);
5414  }
5415  }
5416  else
5417  {
5418  if(pListInfo->pfnDisplay)// void (*pfnDisplay)(WBDialogControl *pControl, void *pData, int iSelected, GC gcPaint, WB_GEOM *pGeom);
5419  {
5420  pListInfo->pfnDisplay(pSelf, NULL, 0, gc, &geomItem, fontSet);
5421  }
5422  else
5423  {
5424  DLGCDefaultListControlDisplayProc(pSelf, NULL, 0, gc, &geomItem, fontSet);
5425  }
5426  }
5427  }
5428  }
5429 
5430  // by convention, restore original objects/state
5431 
5433  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
5435 
5436  WBEndPaint(wID, gc);
5437 
5438  return 1; // processed
5439 }
5440 
5441 
5442 
5443 
5444 // supporting functions
5445 
5446 static void FileListControlDisplayProc(WBDialogControl *pList, void *pData, int iSelected, GC gc, WB_GEOM *pGeom, XFontSet fontSet)
5447 {
5448 int iHPos;
5449 XCharStruct xBounds;
5450 Window wID = pList->wID;
5451 Display *pDisplay = WBGetWindowDisplay(wID);
5452 
5453 
5454  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
5455  "%s - Expose %d (%08xH) pData=%p\n", __FUNCTION__, (int)wID, (int)wID, pData);
5456 
5457  if(fontSet == None)
5458  {
5459  fontSet = WBGetWindowFontSet(wID);
5460  if(fontSet == None)
5461  {
5462  fontSet = WBGetDefaultFontSet(pDisplay);
5463  if(fontSet == None)
5464  {
5465  WB_ERROR_PRINT("%s - NO FONT, line %d\n", __FUNCTION__, __LINE__);
5466  return;
5467  }
5468  }
5469  }
5470 
5471  if(pData && *(char *)pData == '@') // it's a directory
5472  {
5473  // get the BOLD version of the same font for directories
5474 
5475  if(((WBListControl *)pList)->fsBold != None)
5476  {
5477  fontSet = ((WBListControl *)pList)->fsBold;
5478  }
5479  else
5480  {
5481  ((WBListControl *)pList)->fsBold = WBCopyModifyFontSet(pDisplay, fontSet, 0, WBFontFlag_WT_BOLD); // BOLD version
5482  if(((WBListControl *)pList)->fsBold == None)
5483  {
5484  // TODO: make a copy without the 'bold' ??? (this should already have happened)
5485  WB_ERROR_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
5486 
5487  return;
5488  }
5489  else
5490  {
5491  fontSet = ((WBListControl *)pList)->fsBold;
5492  }
5493  }
5494  }
5495 
5496  xBounds = WBFontSetMaxBounds(pDisplay, fontSet);
5497  iHPos = WBFontSetAvgCharWidth(pDisplay, fontSet); // average character width for hpos
5498 
5499  // font setup
5501 // XClearWindow(pDisplay, wID); // TODO: rather than erase background, see if I need to
5502  XSetForeground(pDisplay, gc, iSelected ? pList->clrHBG.pixel : pList->clrBG.pixel);
5503  XFillRectangle(pDisplay, wID, gc, pGeom->x, pGeom->y, pGeom->width, pGeom->height);
5505 
5506  if(iSelected)
5507  {
5508  WBDrawDashedRect(pDisplay, wID, gc, pGeom, pList->clrBD2.pixel);
5509  }
5510 
5511 
5512 // // vertically centered text
5513 // iVPos = xBounds.ascent + xBounds.descent; // font height
5514 // iVPos = (pGeom->height - iVPos) >> 1; // half of the difference - top of text
5515 // iVPos += xBounds.ascent; // base of the text
5516 
5517  // painting the window text
5518 
5519  if(pData)
5520  {
5521  if(((const char *)pData)[0] == '@' &&
5522  ((const char *)pData)[1] == '.' &&
5523  ((const char *)pData)[2] == '.' &&
5524  !((const char *)pData)[3])
5525  {
5526  XPoint aPoints[4];
5527 // int i1;
5528  // draw a left arrow using the highlight color
5529 
5530  XSetForeground(pDisplay, gc, iSelected ? pList->clrBG.pixel : pList->clrHBG.pixel);
5531 
5532  XFillRectangle(pDisplay, wID, gc,
5533  pGeom->x + iHPos + xBounds.ascent / 2,
5534  pGeom->y + pGeom->height / 2 - xBounds.ascent / 4, // half-way - ascent / 4
5535  iHPos * 2 - xBounds.ascent / 2,
5536  xBounds.ascent / 2); // half height of text
5537 
5538  // now make an 'arrow' (TODO: 3D-looking? I would need more colors...)
5539 
5540  aPoints[0].x = pGeom->x + iHPos;
5541  aPoints[0].y = pGeom->y + pGeom->height / 2;
5542  aPoints[1].x = aPoints[0].x + xBounds.ascent;
5543  aPoints[1].y = aPoints[0].y + xBounds.ascent * 2 / 3 - 1;
5544  aPoints[2].x = aPoints[1].x;
5545  aPoints[2].y = aPoints[0].y - xBounds.ascent * 2 / 3 + 1;
5546  aPoints[3].x = aPoints[0].x;
5547  aPoints[3].y = aPoints[0].y;
5548 
5549  XFillPolygon(pDisplay, wID, gc, aPoints, 4, Nonconvex, CoordModeOrigin);
5550 
5551  // 3D highlights for arrow
5552  XSetForeground(pDisplay, gc, iSelected ? pList->clrBD3.pixel : pList->clrBD2.pixel);
5553  XDrawLine(pDisplay, wID, gc, aPoints[0].x, aPoints[0].y, aPoints[1].x - 1, aPoints[1].y);
5554  XDrawLine(pDisplay, wID, gc, aPoints[1].x + 1, pGeom->y + pGeom->height / 2 - xBounds.ascent / 4,
5555  pGeom->x + iHPos * 3, pGeom->y + pGeom->height / 2 - xBounds.ascent / 4);
5556  XDrawLine(pDisplay, wID, gc, pGeom->x + iHPos * 3, pGeom->y + pGeom->height / 2 - xBounds.ascent / 4 + 1,
5557  pGeom->x + iHPos * 3, pGeom->y + pGeom->height / 2 + xBounds.ascent / 4 - 1);
5558 
5559  XSetForeground(pDisplay, gc, iSelected ? pList->clrBD2.pixel : pList->clrBD3.pixel);
5560  XDrawLine(pDisplay, wID, gc, aPoints[0].x, aPoints[0].y, aPoints[2].x - 1, aPoints[2].y);
5561  XDrawLine(pDisplay, wID, gc, aPoints[1].x + 1, pGeom->y + pGeom->height / 2 + xBounds.ascent / 4,
5562  pGeom->x + iHPos * 3, pGeom->y + pGeom->height / 2 + xBounds.ascent / 4);
5563  }
5564  else
5565  {
5566  const char *szText = (const char *)pData + 1;
5567 
5568  if(*(const char *)pData == '^') // symlink
5569  {
5570  XSetForeground(pDisplay, gc, iSelected ? pList->clrBG.pixel : pList->clrHBG.pixel);
5571  }
5572  else // regular file
5573  {
5574  XSetForeground(pDisplay, gc, iSelected ? pList->clrHFG.pixel : pList->clrFG.pixel);
5575  }
5576 
5577  XSetBackground(pDisplay, gc, iSelected ? pList->clrHBG.pixel : pList->clrBG.pixel);
5578 
5579  if(*szText)
5580  {
5581  WB_RECT rctBounds;
5582 
5583  rctBounds.top = pGeom->y;
5584  rctBounds.bottom = pGeom->y + pGeom->height;
5585  rctBounds.left = pGeom->x + iHPos;
5586  rctBounds.right = pGeom->x + pGeom->width - iHPos;
5587 
5588 // XDrawString(pDisplay, wID, gc, pGeom->x + iHPos, pGeom->y + iVPos, szText, strlen(szText));
5589  DTDrawSingleLineText(fontSet, szText, pDisplay, gc, wID, 0, 0, &rctBounds,
5591  }
5592 
5593  if(iSelected) // selected item
5594  {
5595  XSetForeground(pDisplay, gc, pList->clrFG.pixel);
5596  XSetBackground(pDisplay, gc, pList->clrBG.pixel);
5597  }
5598  }
5599  }
5600 
5601  // by convention, restore original objects/state
5602 
5604  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
5606 }
5607 
5608 
5609 
5610 
5611 
5612 
5613 
STATIC - display with a 3D-looking border.
void WBEndWaitCursor(Window wID)
decrement &#39;wait cursor&#39; count, restore to default when zero
#define WB_LIKELY(x)
optimization for code branching when condition is &#39;likely&#39;. use within conditionals ...
Atom aLOSTFOCUS
CONTROL_NOTIFY ClientMessage for LOSTFOCUS event.
BUTTON - Default Push Button (activate by <ENTER>)
GC WBBeginPaint(Window wID, XExposeEvent *pEvent, WB_GEOM *pgBounds)
&#39;Paint&#39; helper, creates a GC for use in updating the window in an Expose event handler ...
static __inline__ XStandardColormap * PXM_StandardColormapFromColormap(Display *pDisplay, Colormap colormap)
create temporary XStandardColormap from a Colormap
Atom aDLGC_SCROLLINFO
dialog control SCROLLINFO property - see WB_SCROLLINFO structure
int cbStructSize
assigned at allocation time, the total size of this structure
2nd parameter (direction) - up, left
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.
#define WB_POINTER_DBLCLICK
WB_POINTER &#39;double-click&#39; event, send in lieu of WB_POINTER_CLICK for double-click.
&#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.
#define WB_POINTER_CLICK
Mouse &#39;click&#39; event.
Atom aGOTFOCUS
CONTROL_NOTIFY ClientMessage for GOTFOCUS event.
const TEXT_OBJECT_VTABLE * vtable
method function pointers (similar to C++ virtual member functions)
Definition: text_object.h:951
int(* can_undo)(struct _text_object_ *pThis)
Indicate whether an &#39;undo&#39; operation is possible (mostly for menu UI)
Definition: text_object.h:602
Horizontal text alignment bits.
set for "default" controls
List control structure.
Atom aDLGC_PROP_NOTIFY
DLGC_PROP_NOTIFY ClientMessage, notify control of property change.
void WBSetWindowFontSet(Window wID, XFontSet fontSet)
assigns the default XFontSet to a window
TEXT_OBJECT xTextObject
A Text Object associated with the editable text.
Atom aDLGC_LISTINFO
dialog control LISTINFO property - see DLGInitControlListInfo() etc.
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:299
STATIC - &#39;type mask&#39; for static controls.
static __inline__ void DLGNotifyOwner(WBDialogControl *pDialogControl, Atom aNotify, long lData0, long lData1, long lData2, long lData3, long lData4)
Notify Owner by calling the owner window&#39;s callback function directly with an event.
#define WB_POINTER_DROP
WB_POINTER &#39;drop&#39; event, only sent if drag/drop supported AND was not &#39;canceled&#39;; see WB_POINTER_CANC...
Pixmap pixmap
foreground pixmap
void DLGDelControlListEntry(WBDialogControl *pCtrl, int iIndex)
Delete a list entry from a control&#39;s list info at a specified index (or deletes ALL entries) ...
Utilities for copying and drawing text, determining text extents, and so on.
char *(* get_sel_text)(const struct _text_object_ *pThis, const WB_RECT *pRct)
get the current selection rectangle as WB_RECT
Definition: text_object.h:519
Atom aDLGC_CONTROL_SET
CONTROL_SET ClientMessage - use this to set specific supported control properties by sending it to th...
this control supports a LISTINFO property.
bold font weight (mutually exclusive0
Definition: font_helper.h:439
Atom aPATH_TREE_CONTROL
Standard Dialog Control - path tree - directory hierarchy - see PATH_TREE_CONTROL_STR.
Pixmap pixmap2
background (transparency) pixmap
int WBKeyEventProcessKey(const XKeyEvent *pEvent, char *pBuf, int *pcbLen, int *piAltCtrlShift)
Generic keyboard event translation utility.
void(* end_highlight)(struct _text_object_ *pThis)
End a highlight block.
Definition: text_object.h:665
int(* get_insmode)(const struct _text_object_ *pThis)
Get the current insert mode for the object.
Definition: text_object.h:427
BUTTON - Tri-state button.
int nTop
scroll position of the top item currently displayed
internal flag, indicates that an underscore underlines the next character
Definition: draw_text.h:121
GC WBGetWindowCopyGC(Window wID)
makes a copy of the default GC so that it can be modified
BUTTON - Checkbox button.
void(* end_mouse_drag)(struct _text_object_ *pThis)
End a mouse &#39;drag&#39; operation.
Definition: text_object.h:701
#define LOAD_COLOR0(X, Y)
macro to load a color, mostly for readability
Atom aMOUSE_DBLCLICK
CONTROL_NOTIFY ClientMessage for MOUSE_DBLCLICK event.
void DTDrawSingleLineText(XFontSet fontSet, const char *szText, Display *pDisplay, GC gc, Drawable dw, int iTabWidth, int iTabOrigin, const WB_RECT *prcBounds, int iAlignment)
draw single-line text
Definition: draw_text.c:1533
#define WB_POINTER_SCROLLDOWN
WB_POINTER &#39;scroll down&#39; event, caused by mouse button 5.
XColor clrHFG
highlighted state-based foreground color
void(* cursor_top)(struct _text_object_ *pThis)
Move the cursor to the top line.
Definition: text_object.h:758
int(* get_col)(const struct _text_object_ *pThis)
Get the current column cursor for the object.
Definition: text_object.h:538
WBDialogControl * WBDialogControlCreate(Atom aClass, WBDialogWindow *pOwner, WBDialogEntry *pDialogEntry, int iX, int iY, int iWidth, int iHeight, const char *szTitle, const char *szPropertyList)
Create a dialog control window.
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.
&#39;tristate&#39; flag. when &#39;setting&#39;, -1 &#39;toggles&#39;, 1 sets it, 0 clears it. when &#39;getting&#39;, zero is &#39;normal&#39;, non-zero &#39;tristate&#39;
void * WBAllocDirectoryList(const char *szDirSpec)
Allocate a &#39;Directory List&#39; object for a specified directory spec.
Definition: file_help.c:1187
Atom aLIST_NOTIFY
CONTROL_NOTIFY ClientMessage for LIST_NOTIFY event.
void WBSetWindowClassName(Window wID, const char *szClassName)
Assignes the window&#39;s class name pointer.
XColor clrBG
background color
void WBSetParentWindow(Window wID, Window wIDParent)
Assigns the parent to the specified window within the internal structure.
void(* page_right)(struct _text_object_ *pThis)
Move the current cursor position right one page.
Definition: text_object.h:743
WB_GEOM geomVBar
geometry for the vertical scroll bar excluding border (empty if not visible)
for pushbuttons, causes it to be drawn &#39;pressed&#39;
unsigned int ulTag
The value DIALOG_CONTROL_TAG.
void WBDraw3DBorderRect(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor1, unsigned long lBorderColor2)
Draw a 3D &#39;border&#39; rectangle.
top-aligned text (using highest vertical ascent)
Definition: draw_text.h:84
void(* cursor_left)(struct _text_object_ *pThis)
Move the current cursor position left one column.
Definition: text_object.h:718
Atom aDLGC_CONTROL_GET
CONTROL_GET ClientMessage - use this to get specific supported control properties by sending it to th...
static __inline__ void WBInitializeInPlaceTextObject(TEXT_OBJECT *pTextObject, Window wIDOwner)
initialize an &#39;in-place&#39; TEXT_OBJECT structure
Definition: text_object.h:1028
Static &#39;Image&#39; control structure.
void(* highlight_colors)(struct _text_object_ *pThis, XColor clrHFG, XColor clrHBG)
Call this to assign the highlight colors. Default colors are GC&#39;s BG and FG.
Definition: text_object.h:337
WBDialogEntry * pDlgControlEntry
pointer to dialog box&#39;s WBDialogEntry
int WBTextWidth(XFontSet fontSet, const char *szText, int cbText)
Obtain the pixel width of specified text for a specified XFontSet.
Definition: font_helper.c:2067
Window DLGGetNextDialogControl(WBDialogWindow *pDialog, Window idControl)
Return the Window ID of the NEXT dialog control within the &#39;tab order&#39;, based on the specified contro...
#define WB_MOUSE_INPUT_MASK
&#39;Mouse&#39; input mask, bit flag for window creation
#define WB_KEYBOARD_INPUT_MASK
&#39;Keyboard&#39; input mask, bit flag for window creation
int DLGAddControlListEntry(WBDialogControl *pCtrl, const char *pData, long cbData, int iIndex)
Add a list entry to a control&#39;s list info.
void(* set_text)(struct _text_object_ *pThis, const char *szText, unsigned long cbLen)
Call this function to re-assign all text in the control.
Definition: text_object.h:359
1st parameter (bar) - The vertical scroll bar for the control or window.
void WBDraw3DBorderElipse(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor1, unsigned long lBorderColor2)
Draw a 3D &#39;border&#39; elipse within a bounding geometry.
2nd parameter (direction) - &#39;knob track&#39; - pos in data.l[2]
TEXT_OBJECT xTextObject
A Text Object associated with the edit text.
Atom aDLGC_PATH
dialog control PATH property, for file and directory controls
Atom aDEFPUSHBUTTON_CONTROL
Standard Dialog Control - default Pushbutton control (has dark border, accepts <ENTER> as hotkey) - s...
BUTTON - Cancel Push Button (activate by <ESC>)
unsigned int border
int DLGPixelHeight(WBDialogWindow *pDlg, int iHeight)
Height of a single dialog unit (in pixels)
unsigned long ulFlags
generic flag bits
Atom aWM_PROTOCOLS
WM supported protocols.
horizontally centered text. tabs are treated as white space
Definition: draw_text.h:78
void(* cursor_home)(struct _text_object_ *pThis)
Move the cursor &#39;home&#39; (left or BOL)
Definition: text_object.h:748
void WBUpdateWindowImmediately(Window wID)
&#39;Paint&#39; helper, generates an immediate Expose event for non-empty &#39;invalid&#39; region ...
Edit control structure.
Atom aWB_CHAR
keystroke/character notifications generated by API
WB_UINT32 WBCreatePointerHash(void *pPointer)
Create/obtain a 32-bit &#39;secure&#39; hash for a pointer.
&#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
int iScrollState
scroll state flags - see enumeration WBScrollState_ENUM
XColor clrBD
border color
int(* can_redo)(struct _text_object_ *pThis)
Indicate whether a &#39;redo&#39; operation is possible (mostly for menu UI)
Definition: text_object.h:614
void PXM_PixelToRGB(XStandardColormap *pMap, XColor *pColor)
Convert the pixel menber of an XColor to RGB.
Window DLGGetFirstDialogControl(WBDialogWindow *pDialog)
Return the Window ID of the FIRST dialog control within the &#39;tab order&#39;.
void(* undo)(struct _text_object_ *pThis)
Perform a single &#39;undo&#39; operation.
Definition: text_object.h:608
Horizontally align text center.
Horizontally align text right.
int nItemHeight
height of a single item (in pixels)
XColor clrBD2
3D border color 2 (light)
STATIC - Image control window.
int WBSetClipboardData(Display *pDisplay, Atom aType, int iFormat, const void *pData, unsigned long nData)
Get clipboard data of requested type.
WBWinEvent pDLGControlCallback
control&#39;s callback function
int nHeight
height (in items) of display area, recalculated on resize/expose
Atom aWB_POINTER
pointer click/double-click/drag notifications generated by API
BUTTON - Radio button (generic)
WBDialogPropList * pPropList
pointer to the property list (may be NULL)
#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.
void WBRegisterWindowCallback(Window wID, WBWinEvent pCallback)
register callback function for a window (required)
Atom aLIST_CONTROL
Standard Dialog Control - list - single, multi, extended select (h, v, multicol) - see LIST_CONTROL_S...
void WBDrawBorderRect(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor)
Draw a &#39;border&#39; rectangle.
const char * WBDialogControlGetProperty(WBDialogControl *pCtrl, Atom aPropName)
Mid-level dialog control property retrieval (character string)
void DeleteTimer(Display *pDisplay, Window wID, long lID)
Deletes an existing timer&#39;s resources.
Atom aClass
basic control class atom
Atom aSCROLL_NOTIFY
#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
XColor clrHBG
highlighted state-based background color
Structure that defines scroll bar info for both horizontal and vertical scroll bars.
STATIC - Text control window.
void WBClearWindow(Window wID, GC gc)
&#39;Paint&#39; helper, erases background by painting the background color within the clipping region ...
Window wID
Window ID of the dialog control window.
int WBStat(const char *szLinkName, unsigned long *pdwModeAttrReturn)
Obtain the &#39;stat&#39; flags for a file name, resolving links as needed.
Definition: file_help.c:1574
&#39;checked&#39; state
Region WBGetPaintRegion(Window wID)
&#39;Paint&#39; helper, returns a copy of the current &#39;paint&#39; region for the window
void WBCreateWindowDefaultGC(Window wID, unsigned long clrFG, unsigned long clrBG)
creates a default GC for a window
int WBGetDirectoryListFileStat(const void *pDirectoryList, const char *szFileName, unsigned long *pdwModeAttrReturn)
Obtain the &#39;stat&#39; flags for a file name, resolving links as needed, with respect to a &#39;Directory List...
Definition: file_help.c:1589
void(* pfnDisplay)(WBDialogControl *pControl, void *pData, int iSelected, GC gcPaint, WB_GEOM *pGeom, XFontSet fontSet)
display callback function to paint the entry on the display surface
left button in &#39;drag&#39; state on vertical scroll bar (relies on drag cancel)
unsigned long WBGetWindowFGColor(Window wID)
Returns the currently assigned foreground color.
center using entire text height (ascent + descent for single line)
Definition: draw_text.h:86
void WBDestroyPointerHashPtr(void *pPointer)
Destroy a 32-bit &#39;secure&#39; hash for a pointer regardless of reference count.
2nd parameter (direction) - bottom, end
void * WBAlloc(int nSize)
High performance memory sub-allocator &#39;allocate&#39;.
int(* has_select)(const struct _text_object_ *pThis)
Returns a non-zero value if there is currently a &#39;selection&#39;.
Definition: text_object.h:505
unsigned int width
#define END_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro follows the call(s)