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