X11 Work Bench Toolkit  1.0
dialog_support.c
1 // _ _ _ _ //
3 // __| |(_) __ _ | | ___ __ _ ___ _ _ _ __ _ __ ___ _ __ | |_ ___ //
4 // / _` || | / _` || | / _ \ / _` | / __|| | | || '_ \ | '_ \ / _ \ | '__|| __| / __| //
5 // | (_| || || (_| || || (_) || (_| | \__ \| |_| || |_) || |_) || (_) || | | |_ _| (__ //
6 // \__,_||_| \__,_||_| \___/ \__, |_____|___/ \__,_|| .__/ | .__/ \___/ |_| \__|(_)\___| //
7 // |___/|_____| |_| |_| //
8 // //
9 // //
10 // additional dialog control support //
11 // This file contains various support and functionality that is common to dialog controls //
12 // //
14 
15 
16 /*****************************************************************************
17 
18  X11workbench - X11 programmer's 'work bench' application and toolkit
19  Copyright (c) 2010-2016 by Bob Frazier (aka 'Big Bad Bombastic Bob')
20  all rights reserved
21 
22  DISCLAIMER: The X11workbench application and toolkit software are supplied
23  'as-is', with no warranties, either implied or explicit.
24  Any claims to alleged functionality or features should be
25  considered 'preliminary', and might not function as advertised.
26 
27  BSD-like license:
28 
29  There is no restriction as to what you can do with this software, so long
30  as you include the above copyright notice and DISCLAIMER for any distributed
31  work that is equal to or derived from this one, along with this paragraph
32  that explains the terms of the license if the source is also being made
33  available. A "derived work" describes a work that uses a significant portion
34  of the source files or algorithms that are included with this one.
35  Specifically excluded from this are files that were generated by the software,
36  or anything that is included with the software that is part of another package
37  (such as files that were created or added during the 'configure' process).
38  Specifically included is the use of part or all of any of the X11 workbench
39  toolkit source or header files in your distributed application. If you do not
40  ship the source, the above copyright statement is still required to be placed
41  in a reasonably prominent place, such as documentation, splash screens, and/or
42  'about the application' dialog boxes.
43 
44  Use and distribution are in accordance with GPL, LGPL, and/or the above
45  BSD-like license. See COPYING and README files for more information.
46 
47 
48  Additional information at http://sourceforge.net/projects/X11workbench
49 
50 ******************************************************************************/
51 
52 
53 #ifdef linux /* needed for debian, possibly others */
54 #define _GNU_SOURCE /* in case features.h is involved on linux */
55 #define __USE_GNU /* this enables a few more things in the headers like 'qsort_r' */
56 // TODO: consider making this a 'configure' thing
57 #endif // linux
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62 #include <memory.h>
63 #include <string.h>
64 #include <strings.h>
65 #include <signal.h>
66 #include <time.h>
67 #include <sys/stat.h>
68 
69 #ifndef XK_Delete /* moslty for interix */
70 #define XK_MISCELLANY /* mostly for interix */
71 #include <X11/keysymdef.h> // some platforms don't automatically include this with X headers
72 #endif // XK_Delete
73 
74 #define DIALOG_SUPPORT_C /* prevents me from including the various Atom definitions */
75 
76 #include "window_helper.h"
77 #include "pixmap_helper.h" // pixmap helpers, including pre-defined icons
78 #include "dialog_window.h"
79 #include "dialog_controls.h"
80 #include "dialog_support.h" // internal-only definitions
81 #include "conf_help.h"
82 #include "file_help.h"
83 #include "draw_text.h"
84 #include "text_object.h"
85 #include "window_dressing.h"
86 
89 #define THIS_SUBSYSTEM DebugSubSystem_DialogCtrl
90 
91 
92 
93 
94 #define INIT_ATOM(X) if(a##X == None){ a##X = WBGetAtom(WBGetDefaultDisplay(),X##_STR); }
95 #define INIT_ATOM2(X,Y) if(X == None){ X = WBGetAtom(WBGetDefaultDisplay(),Y); }
96 
97 #define DEFAULT_LISTINFO_MAX 16384 /* default initial max # of items in LISTINFO */
98 
99 
100 
101 // atoms first
102 // TODO: make this documentation a bit better. for now the format is OK in doxygen, a little flakey here
103 
106 Atom aFRAME_CONTROL = None;
107 
109 Atom aTEXT_CONTROL = None;
110 
112 Atom aICON_CONTROL = None;
113 
115 Atom aIMAGE_CONTROL = None;
116 
118 Atom aEDIT_CONTROL = None;
119 
121 Atom aPUSHBUTTON_CONTROL = None;
122 
125 
128 
130 Atom aRADIOBUTTON_CONTROL = None;
131 
134 
136 Atom aCHECKBUTTON_CONTROL = None;
137 
140 
142 Atom aHSCROLL_CONTROL = None;
143 
145 Atom aVSCROLL_CONTROL = None;
146 
148 Atom aSLIDER_CONTROL = None;
149 
151 Atom aKNOB_CONTROL = None;
152 
154 Atom aLIST_CONTROL = None;
155 
157 Atom aCOMBO_CONTROL = None;
158 
160 Atom aTREE_CONTROL = None;
161 
163 Atom aCOMBOTREE_CONTROL = None;
164 
166 Atom aFILE_LIST_CONTROL = None;
167 
169 Atom aFILE_COMBO_CONTROL = None;
170 
172 Atom aPATH_TREE_CONTROL = None;
173 
175 Atom aTAB_CONTROL = None;
176 
177 
178 // NOTE: 'xatoms' is in the CORE group - consider moving this into CORE
179 
180 
181 
183 
195 Atom aBUTTON_PRESS = None;
209 Atom aLIST_NOTIFY = None;
222 Atom aTEXT_CHANGED = None;
237 Atom aTEXTSELECT_CHANGE = None;
250 Atom aGOTFOCUS = None;
263 Atom aLOSTFOCUS = None;
276 Atom aMOUSE_DOWN = None;
289 Atom aMOUSE_UP = None;
302 Atom aMOUSE_DRAG = None;
315 Atom aKEY_DOWN = None;
328 Atom aKEY_UP = None;
341 Atom aKEYSTROKE = None;
342 
352 Atom aDIALOG_INIT = None;
353 
364 Atom aDLGC_PROP_NOTIFY = None;
365 
377 Atom aLIST_SELCHANGE = None; // list selection has changed (send to self)
378 
379 // internal-only properties (still have global scope for inline functions, etc.)
386 Atom aDLGC_TEXT = None; // dialog control 'text' property, i.e. 'GetText'
391 Atom aDLGC_CAPTION = None; // dialog control 'caption' property, i.e. 'GetCaption' (not an actual property, notification only)
398 Atom aDLGC_FONT = None;
407 Atom aDLGC_SCROLLINFO = None; // scrollbar info structure (horizontal AND vertical)
408  // (scrollbars, listboxes, combo boxes, multi-line edit)
417 Atom aDLGC_LISTINFO = None; // listbox info structure
418 
428 Atom aDLGC_PATH = None;
429 
430 
432 {
433  INIT_ATOM(FRAME_CONTROL);
434  INIT_ATOM(TEXT_CONTROL);
435  INIT_ATOM(ICON_CONTROL);
436  INIT_ATOM(IMAGE_CONTROL);
437  INIT_ATOM(EDIT_CONTROL);
438  INIT_ATOM(PUSHBUTTON_CONTROL);
439  INIT_ATOM(DEFPUSHBUTTON_CONTROL);
440  INIT_ATOM(CANCELBUTTON_CONTROL);
441  INIT_ATOM(RADIOBUTTON_CONTROL);
442  INIT_ATOM(FIRSTRADIOBUTTON_CONTROL);
443  INIT_ATOM(CHECKBUTTON_CONTROL);
444  INIT_ATOM(TRISTATEBUTTON_CONTROL);
445  INIT_ATOM(HSCROLL_CONTROL);
446  INIT_ATOM(VSCROLL_CONTROL);
447  INIT_ATOM(SLIDER_CONTROL);
448  INIT_ATOM(KNOB_CONTROL);
449  INIT_ATOM(LIST_CONTROL);
450  INIT_ATOM(COMBO_CONTROL);
451  INIT_ATOM(TREE_CONTROL);
452  INIT_ATOM(COMBOTREE_CONTROL);
453  INIT_ATOM(FILE_LIST_CONTROL);
454  INIT_ATOM(FILE_COMBO_CONTROL);
455  INIT_ATOM(PATH_TREE_CONTROL);
456  INIT_ATOM(TAB_CONTROL);
457 
458 // INIT_ATOM2(aCONTROL_NOTIFY,"ControlNotify");
459  INIT_ATOM2(aBUTTON_PRESS,"ButtonPress");
460  INIT_ATOM2(aLIST_NOTIFY,"ListNotify");
461  INIT_ATOM2(aTEXT_CHANGED,"TextChanged");
462  INIT_ATOM2(aTEXTSELECT_CHANGE,"TextSelectChange");
463  INIT_ATOM2(aGOTFOCUS,"GotFocus");
464  INIT_ATOM2(aLOSTFOCUS,"LostFocus");
465  INIT_ATOM2(aMOUSE_DOWN,"MouseDown");
466  INIT_ATOM2(aMOUSE_UP,"MouseUp");
467  INIT_ATOM2(aMOUSE_DRAG,"MouseDrag");
468  INIT_ATOM2(aKEY_DOWN,"KeyDown");
469  INIT_ATOM2(aKEY_UP,"KeyUp");
470  INIT_ATOM2(aKEYSTROKE,"Keystroke");
471 
472  INIT_ATOM2(aDLGC_TEXT, "DLGC_TEXT");
473  INIT_ATOM2(aDLGC_CAPTION, "DLGC_CAPTION");
474  INIT_ATOM2(aDLGC_FONT, "DLGC_FONT");
475  INIT_ATOM2(aDLGC_SCROLLINFO, "DLGC_SCROLLINFO");
476  INIT_ATOM2(aDLGC_LISTINFO, "DLGC_LISTINFO");
477  INIT_ATOM2(aDLGC_PATH, "DLGC_PATH");
478 
479 
480  // other dialog-related messages
481  INIT_ATOM2(aDIALOG_INIT,"DialogInit");
482 // INIT_ATOM2(aDIALOG_SETFOCUS,"DialogSetFocus");
483  INIT_ATOM2(aDLGC_PROP_NOTIFY, "DLGCPropNotify");
484  INIT_ATOM2(aLIST_SELCHANGE, "LIST_SELCHANGE");
485 
486 }
487 
488 
490 // D I A L O G C O N T R O L P R O P E R T I E S
492 
493 
494 void WBDialogControlSetCaption(WBDialogControl *pCtrl, const char *szCaption)
495 {
496 char *szOldCaption = pCtrl->pCaption;
497 
498  pCtrl->pCaption = WBCopyString(szCaption);
499 
500  if(szOldCaption)
501  {
502  WBFree(szOldCaption);
503  }
504 
505  WBInvalidateGeom(pCtrl->wID, NULL, 0);
506  WBUpdateWindow(pCtrl->wID); // schedule update (not immediate)
507 
508  DLGNotifySelf(pCtrl, aDLGC_PROP_NOTIFY, aDLGC_CAPTION, 0, 0, 0, 0);
509 }
510 
512 {
513  if(!pCtrl->pCaption)
514  {
515  return "";
516  }
517 
518  return pCtrl->pCaption;
519 }
520 
521 void WBDialogControlSetPixmap(WBDialogControl *pCtrl, Pixmap pixmap)
522 {
523 Display *pDisplay = NULL;
524 
525  if(!pCtrl ||
526  (pCtrl->aClass != aICON_CONTROL && pCtrl->aClass != aIMAGE_CONTROL
527  && pCtrl->aClass != aPUSHBUTTON_CONTROL && pCtrl->aClass != aDEFPUSHBUTTON_CONTROL
528  && pCtrl->aClass != aCANCELBUTTON_CONTROL))
529  {
530  return;
531  }
532 
533  pDisplay = WBGetWindowDisplay(pCtrl->wID);
534 
535  if(!pDisplay)
536  {
537  pDisplay = WBGetDefaultDisplay();
538  }
539 
540  if(pCtrl->aClass == aICON_CONTROL ||
541  pCtrl->aClass == aIMAGE_CONTROL)
542  {
543  Pixmap pxOld = ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap;
544  Pixmap pxOld2 = ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap2;
545 
546  ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap = pixmap;
547  ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap2 = None;
548 
550  if(pxOld != None)
551  {
552  XFreePixmap(pDisplay, pxOld);
553  }
554  if(pxOld2 != None)
555  {
556  XFreePixmap(pDisplay, pxOld2);
557  }
559  }
560 
561  if(pCtrl->aClass == aPUSHBUTTON_CONTROL || pCtrl->aClass == aDEFPUSHBUTTON_CONTROL
562  || pCtrl->aClass == aCANCELBUTTON_CONTROL)
563  {
564  Pixmap pxOld = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap;
565  Pixmap pxOld2 = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2;
566 
567  ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap = pixmap;
568  ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2 = None;
569 
571  if(pxOld != None)
572  {
573  XFreePixmap(pDisplay, pxOld);
574  }
575  if(pxOld2 != None)
576  {
577  XFreePixmap(pDisplay, pxOld2);
578  }
580  }
581 }
582 
584 {
585  if(!pCtrl)
586  {
587  return None;
588  }
589 
590  if(pCtrl->aClass == aICON_CONTROL ||
591  pCtrl->aClass == aIMAGE_CONTROL)
592  {
593  return ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap;
594  }
595 
596  if(pCtrl->aClass == aPUSHBUTTON_CONTROL || pCtrl->aClass == aDEFPUSHBUTTON_CONTROL
597  || pCtrl->aClass == aCANCELBUTTON_CONTROL)
598  {
599  return ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap;
600  }
601 
602  return None;
603 }
604 
606 {
607 Display *pDisplay = NULL;
608 
609  if(!pCtrl ||
610  (pCtrl->aClass != aICON_CONTROL && pCtrl->aClass != aIMAGE_CONTROL
611  && pCtrl->aClass != aPUSHBUTTON_CONTROL && pCtrl->aClass != aDEFPUSHBUTTON_CONTROL
612  && pCtrl->aClass != aCANCELBUTTON_CONTROL))
613  {
614  return;
615  }
616 
617  pDisplay = WBGetWindowDisplay(pCtrl->wID);
618 
619  if(!pDisplay)
620  {
621  pDisplay = WBGetDefaultDisplay();
622  }
623 
624  if(pCtrl->aClass == aICON_CONTROL ||
625  pCtrl->aClass == aIMAGE_CONTROL)
626  {
627  Pixmap pxOld = ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap;
628  Pixmap pxOld2 = ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap2;
629 
630  ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap = pixmap;
631  ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap2 = pixmap2;
632 
634  if(pxOld != None)
635  {
636  XFreePixmap(pDisplay, pxOld);
637  }
638  if(pxOld2 != None)
639  {
640  XFreePixmap(pDisplay, pxOld2);
641  }
643  }
644 
645  if(pCtrl->aClass == aPUSHBUTTON_CONTROL || pCtrl->aClass == aDEFPUSHBUTTON_CONTROL
646  || pCtrl->aClass == aCANCELBUTTON_CONTROL)
647  {
648  Pixmap pxOld = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap;
649  Pixmap pxOld2 = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2;
650 
651  ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap = pixmap;
652  ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2 = pixmap2;
653 
655  if(pxOld != None)
656  {
657  XFreePixmap(pDisplay, pxOld);
658  }
659  if(pxOld2 != None)
660  {
661  XFreePixmap(pDisplay, pxOld2);
662  }
664  }
665 }
666 
667 Pixmap WBDialogControlGetIconPixmap(WBDialogControl *pCtrl, Pixmap *pPixmap2)
668 {
669  if(!pCtrl)
670  {
671  return None;
672  }
673 
674  if(pCtrl->aClass == aICON_CONTROL ||
675  pCtrl->aClass == aIMAGE_CONTROL)
676  {
677  if(pPixmap2)
678  {
679  *pPixmap2 = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2;
680  }
681 
682  return ((struct _WB_IMAGE_CONTROL_ *)pCtrl)->pixmap;
683  }
684 
685  if(pCtrl->aClass == aPUSHBUTTON_CONTROL || pCtrl->aClass == aDEFPUSHBUTTON_CONTROL
686  || pCtrl->aClass == aCANCELBUTTON_CONTROL)
687  {
688  if(pPixmap2)
689  {
690  *pPixmap2 = ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap2;
691  }
692 
693  return ((struct _WB_PUSHBUTTON_CONTROL_ *)pCtrl)->pixmap;
694  }
695 
696  return None;
697 }
698 
699 
700 int WBDialogControlSetPropList(WBDialogControl *pCtrl, const char *szPropList)
701 {
702 // property<tab>value<newline>
703 
704  return 0; // for now (not being used yet)
705 }
706 
707 int WBDialogControlSetProperty(WBDialogControl *pCtrl, Atom aPropName, const char *szPropVal)
708 {
709  WB_DIALOG_PROP p;
710 
711  p.aProp = aPropName;
712  p.lVal = 0;
713  p.pVal = WBCopyString(szPropVal);
714 
715  if(!p.pVal)
716  {
717  return -1;
718  }
719 
720  WBDialogControlSetDialogProp(pCtrl, &p);
721  return 0;
722 }
723 
724 void WBDialogControlSetProperty2(WBDialogControl *pCtrl, Atom aPropName, void *pPropVal)
725 {
726  WB_DIALOG_PROP p;
727 
728  p.aProp = aPropName;
729  p.lVal = 0;
730  p.pVal = pPropVal;
731 
732  WBDialogControlSetDialogProp(pCtrl, &p);
733 }
734 
735 const char *WBDialogControlGetProperty(WBDialogControl *pCtrl, Atom aPropName)
736 {
737 const WB_DIALOG_PROP *pP = WBDialogControlGetDialogProp(pCtrl, aPropName);
738 
739  if(pP)
740  {
741  return pP->pVal; // TODO: if NULL, lVal as a string?
742  }
743 
744  return ""; // so it's not NULL
745 }
746 
747 void *WBDialogControlGetProperty2(WBDialogControl *pCtrl, Atom aPropName)
748 {
749 const WB_DIALOG_PROP *pP = WBDialogControlGetDialogProp(pCtrl, aPropName);
750 
751  if(pP)
752  {
753  return (void *)(pP->pVal); // TODO: if NULL, lVal as a string?
754  }
755 
756  return NULL;
757 }
758 
759 
760 
761 #define INITIAL_PROPERTY_MAX 64
762 
763 static WBDialogPropList * __ConstructPropList(void)
764 {
765  int iInitialSize = sizeof(WBDialogPropList) + INITIAL_PROPERTY_MAX * sizeof(WB_DIALOG_PROP);
766  WBDialogPropList *pRval = (WBDialogPropList *)WBAlloc(iInitialSize);
767 
768  if(pRval)
769  {
770  pRval->nProps = 0;
771  pRval->nMaxProps = INITIAL_PROPERTY_MAX;
772  WB_WARN_PRINT("TEMPORARY: WBDialogPropList constructor %p %d, %d\n", pRval, pRval->nProps, pRval->nMaxProps);
773  }
774  else
775  {
776  WB_ERROR_PRINT("%s - not enough memory\n", __FUNCTION__);
777  }
778 
779  return pRval;
780 }
781 
783 {
784 int i1;
785 WBDialogPropList *pPropList;
786 WB_DIALOG_PROP *pProp = NULL;
787 Atom aProp;
788 
789  if(!pCtrl || !pPropVal)
790  {
791  WB_ERROR_PRINT("%s - pCtrl %p or pPropVal %p\n", __FUNCTION__,
792  pCtrl, pPropVal);
793 
794  return -1;
795  }
796 
797  if(!pCtrl->pPropList)
798  {
799  if(!(pCtrl->pPropList = __ConstructPropList()))
800  {
801  WB_ERROR_PRINT("%s - unable to allocate property list for window %d (%08xH)\n",
802  __FUNCTION__, (int)pCtrl->wID, (int)pCtrl->wID);
803 
804  return -2;
805  }
806  }
807 
808  pPropList = pCtrl->pPropList;
809  aProp = pPropVal->aProp;
810 
811  for(i1=0; i1 < pPropList->nProps; i1++)
812  {
813  register WB_DIALOG_PROP *pProp0 = &(pPropList->aDlgProp[i1]);
814 
815  if(pProp0 && pProp0->aProp == aProp)
816  {
817  pProp = pProp0;
818  break;
819  }
820  }
821 
822  if(!pProp)
823  {
824  if((pPropList->nProps + 1) >= pPropList->nMaxProps)
825  {
826  int iNewSize = (pPropList->nMaxProps + INITIAL_PROPERTY_MAX / 2)
827  * sizeof(pPropList->aDlgProp[0])
828  + sizeof(*pPropList);
829 
830  pPropList = (WBDialogPropList *)WBReAlloc(pPropList, iNewSize);
831  if(!pPropList)
832  {
833  WB_ERROR_PRINT("%s - unable to RE-allocate property list for window %d (%08xH)\n",
834  __FUNCTION__, (int)pCtrl->wID, (int)pCtrl->wID);
835 
836  return -3;
837  }
838 
839  pCtrl->pPropList = pPropList;
840  pPropList->nMaxProps += INITIAL_PROPERTY_MAX / 2;
841 
842  if(pPropList->nProps >= pPropList->nMaxProps)
843  {
844  WB_ERROR_PRINT("%s - internal inconsistency, nProps=%d, nMaxProps=%d\n",
845  __FUNCTION__, pPropList->nProps, pPropList->nMaxProps);
846  return -4;
847  }
848  }
849 
850  pProp = &(pPropList->aDlgProp[pPropList->nProps]);
851  pPropList->nProps++;
852 
853  pProp->aProp = aProp;
854  pProp->lVal = 0;
855  pProp->pVal = NULL;
856  }
857 
858  pProp->lVal = pPropVal->lVal; // just copy the lVal
859 
860  if(pProp->pVal != pPropVal->pVal) // if it changes... and ONLY if it changes
861  {
862  if(pProp->pVal)
863  {
864  if(pProp->aProp == aDLGC_LISTINFO)
865  {
866  DLGCListInfoDestructor((LISTINFO *)(pProp->pVal));
867  }
868  else
869  {
870  WBFree(pProp->pVal);
871  }
872  }
873 
874  pProp->pVal = pPropVal->pVal;
875  }
876 
877  // last but not least, tell the dialog control its properties were altered
878  // by directly calling its callback function with the 'property change' event
879 
880  WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
881  "%s - DLGC_PROP_NOTIFY (set) for window %d (%08xH)\n",
882  __FUNCTION__, (int)pCtrl->wID, (int)pCtrl->wID);
883 
884  DLGNotifySelf(pCtrl, aDLGC_PROP_NOTIFY, pPropVal->aProp, 0, 0, 0, 0);
885 
886  return 0; // success
887 }
888 
890 {
891 int i1, bNotify = 0;
892 WBDialogPropList *pPropList = pCtrl ? pCtrl->pPropList : NULL;
893 //WB_DIALOG_PROP *pProp2 = NULL;
894 WB_DIALOG_PROP sProp;
895 
896 
897  if(!pPropList)
898  {
899  return;
900  }
901 
902  for(i1=0; i1 < pPropList->nProps; i1++)
903  {
904  register WB_DIALOG_PROP *pProp = &(pPropList->aDlgProp[i1]);
905 
906  if(pProp && pProp->aProp == aProp)
907  {
908  if(pProp->pVal) // pointer?
909  {
910  if(pProp->aProp == aDLGC_LISTINFO)
911  {
912  DLGCListInfoDestructor((LISTINFO *)(pProp->pVal));
913  }
914  else
915  {
916  WBFree(pProp->pVal);
917  }
918 
919  pProp->pVal = NULL; // necessary, for the next step
920  }
921 
922  memcpy(&sProp, pProp, sizeof(WB_DIALOG_PROP)); // make a copy of the thing
923  bNotify = 1;
924 
925  // must remove this entry now
926  for(i1++; i1 < pPropList->nProps; i1++)
927  {
928  pPropList->aDlgProp[i1 - 1] = pPropList->aDlgProp[i1];
929  }
930 
931  pPropList->nProps--;
932  bzero(&(pPropList->aDlgProp[pPropList->nProps]), sizeof(pPropList->aDlgProp[pPropList->nProps]));
933 
934  break;
935  }
936  }
937 
938  // last but not least, tell the dialog control its properties were altered
939  // by directly calling its callback function with the 'property change' event
940 
941 // if(pProp2) NO NO NO! but this is how 'set' does it, since 'pProp2' is still valid
942 // {
943 // DLGNotifySelf(pCtrl, aDLGC_PROP_NOTIFY, pProp2->aProp, 0, 0, 0, 0);
944 // }
945 
946  // TODO: find a better way to notify for a property that was deleted.
947  // for now I copied the prop structure
948 
949  if(bNotify)
950  {
951  WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
952  "%s - DLGC_PROP_NOTIFY (del) for window %d (%08xH)\n",
953  __FUNCTION__, (int)pCtrl->wID, (int)pCtrl->wID);
954 
955  DLGNotifySelf(pCtrl, aDLGC_PROP_NOTIFY, sProp.aProp, 0, 0, 0, 0);
956  }
957 
958 }
959 
961 {
962 int i1;
963 WBDialogPropList *pPropList = pCtrl ? pCtrl->pPropList : NULL;
964 
965  if(!pPropList)
966  {
967  return NULL; // for NULL 'pCtrl' will always be the case
968  }
969 
970  for(i1=0; i1 < pPropList->nProps; i1++)
971  {
972  register WB_DIALOG_PROP *pProp = &(pPropList->aDlgProp[i1]);
973 
974  if(pProp && pProp->aProp == aProp)
975  {
976  return pProp;
977  }
978  }
979 
980  return NULL; // not found
981 }
982 
984 {
985 int i1;
986 
987  if(!pPropList)
988  {
989  return;
990  }
991 
992  for(i1=0; i1 < pPropList->nProps; i1++)
993  {
994  /*register*/ WB_DIALOG_PROP *pProp = &(pPropList->aDlgProp[i1]);
995 
996  if(pProp->pVal) // pointer?
997  {
998  if(pProp->aProp == aDLGC_LISTINFO)
999  {
1000  DLGCListInfoDestructor((LISTINFO *)(pProp->pVal));
1001  }
1002  else
1003  {
1004  WBFree(pProp->pVal);
1005  }
1006 
1007 #if 0
1008  { // debug code to prevent re-free problems with b0rked list
1009  int i2;
1010 
1011  for(i2=i1+1; i2 < pPropList->nProps; i2++)
1012  {
1013  register WB_DIALOG_PROP *pProp2 = &(pPropList->aDlgProp[i2]);
1014 
1015  if(pProp->pVal == pProp2->pVal)
1016  {
1017  if(pProp->aProp == pProp2->aProp)
1018  {
1019  WB_DEBUG_PRINT(DebugLevel_ERROR | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
1020  "%s - %d %d matching property name %d and value %p detected\n",
1021  __FUNCTION__, i1, i2, (int)(pProp->aProp), pProp->pVal);
1022  }
1023 
1024  pProp2->pVal = NULL;
1025  pProp2->aProp = 0; // for now set this to zero as well
1026  }
1027  }
1028  }
1029 #endif // 0
1030  }
1031 
1032  bzero(pProp, sizeof(*pProp)); // zero out whatever used to be there (as a matter of course)
1033  }
1034 
1035  pPropList->nProps = 0; // matter of course
1036 
1037  WBFree(pPropList); // caller must ensure no duplicate destruction happens
1038 }
1039 
1040 
1041 
1043 // L I S T I N F O H A N D L E R S
1045 
1046 void * DLGCDefaultListInfoAllocator(const void *pData, int cbData)
1047 {
1048  void *pRval;
1049 
1050  if(cbData < 0)
1051  {
1052  if(pData)
1053  {
1054  cbData = strlen((const char *)pData) + 1;
1055  }
1056  else
1057  {
1058  return NULL;
1059  }
1060  }
1061 
1062  pRval = WBAlloc(cbData + 1);
1063 
1064  if(pRval)
1065  {
1066  if(cbData)
1067  {
1068  if(pData)
1069  {
1070  memcpy(pRval, pData, cbData);
1071  }
1072  else
1073  {
1074  bzero(pRval, cbData);
1075  }
1076  }
1077 
1078  ((char *)pRval)[cbData] = 0; // there will always be at least that one extra byte for the zero
1079  }
1080 
1081  return pRval;
1082 }
1083 
1085  void *(*pfnAllocator)(const void *,int), void (*pfnDestructor)(void *),
1086  void (*pfnDisplay)(WBDialogControl *, void *, int, GC, WB_GEOM *, XFontSet),
1087  int (*pfnSort)(const void *, const void *))
1088 {
1089 WB_DIALOG_PROP propTemp;
1090 int i1;
1091 
1092  if(!pfnDisplay)
1093  {
1094  pfnDisplay = DLGCDefaultListControlDisplayProc;
1095  }
1096 
1097  propTemp.aProp = aDLGC_LISTINFO;
1098  propTemp.lVal = 0;
1099  propTemp.pVal = DLGCListInfoConstructor(pCtrl->wID, DEFAULT_LISTINFO_MAX, nFlags,
1100  pfnAllocator, pfnDestructor, pfnDisplay, NULL);
1101 
1102  if(!propTemp.pVal)
1103  {
1104  WB_ERROR_PRINT("%s - DLGCListInfoConstructor returns NULL\n", __FUNCTION__);
1105  return -2;
1106  }
1107 
1108  i1 = WBDialogControlSetDialogProp(pCtrl, &propTemp);
1109 
1110  if(i1)
1111  {
1112  WB_ERROR_PRINT("%s - WBDialogControlSetDialogProp returns %d\n", __FUNCTION__, i1);
1113  DLGCListInfoDestructor(propTemp.pVal);
1114  }
1115 
1116  return i1; // 0 means 'success'
1117 }
1118 
1119 int DLGModifyControlListInfo(WBDialogControl *pCtrl, int bFlags, int nFlags,
1120  int bAllocator, void *(*pfnAllocator)(const void *,int),
1121  int bDestructor, void (*pfnDestructor)(void *),
1122  int bDisplay, void (*pfnDisplay)(WBDialogControl *, void *, int, GC, WB_GEOM *, XFontSet),
1123  int bSort, int (*pfnSort)(const void *, const void *))
1124 {
1125 WB_DIALOG_PROP propTemp;
1126 const WB_DIALOG_PROP *pProp;
1127 LISTINFO *pLI;
1128 //int i1;
1129 
1130 
1132 
1133  if(!pProp)
1134  {
1135  // see DLGInitControlListInfoDefault for canonical default values (this should match it actually)
1136 
1137  return DLGInitControlListInfo(pCtrl, bFlags ? nFlags : ListInfoFlags_SORTED,
1138  bAllocator ? pfnAllocator : DLGCDefaultListInfoAllocator,
1139  bDestructor ? pfnDestructor : WBFree,
1140  bDisplay ? pfnDisplay : NULL,
1141  bSort ? pfnSort : NULL);
1142  }
1143 
1144  memcpy(&propTemp, pProp, sizeof(propTemp));
1145 
1146  if(!propTemp.pVal)
1147  {
1148  WB_ERROR_PRINT("%s - DLGCListInfoConstructor returns NULL\n", __FUNCTION__);
1149  return -2;
1150  }
1151 
1152  pLI = (LISTINFO *)propTemp.pVal;
1153 
1154  // assuming it's ok, assign the various information as specified.
1155 
1156  if(bFlags)
1157  {
1158  pLI->nFlags = nFlags;
1159  }
1160 
1161  if(bAllocator)
1162  {
1163  pLI->pfnAllocator = pfnAllocator;
1164  }
1165 
1166  if(bDestructor)
1167  {
1168  pLI->pfnDestructor = pfnDestructor;
1169  }
1170 
1171  if(bDisplay)
1172  {
1173  if(pfnDisplay)
1174  {
1175  pLI->pfnDisplay = pfnDisplay;
1176  }
1177  else
1178  {
1180  }
1181  }
1182 
1183  if(bSort)
1184  {
1185  if(pfnSort)
1186  {
1187  pLI->pfnSort = pfnSort;
1188  }
1189  else
1190  {
1191  pLI->pfnSort = (int (*)(const void *,const void *))strcmp;
1192  }
1193  }
1194 
1195  return 0;
1196 }
1197 
1198 LISTINFO *DLGCListInfoConstructor(Window wOwner, int nMax, int nFlags,
1199  void *(*pfnAllocator)(const void *,int), void (*pfnDestructor)(void *),
1200  void (*pfnDisplay)(WBDialogControl *, void *, int, GC, WB_GEOM *, XFontSet),
1201  int (*pfnSort)(const void *, const void *))
1202 {
1203 LISTINFO *pRval = WBAlloc(sizeof(*pRval) + nMax * sizeof(const void *));
1204 
1205  if(pRval)
1206  {
1207  pRval->nItems = 0;
1208  pRval->nMaxItems = nMax;
1209  pRval->nPos = 0; // current scroll position (initially zero)
1210  pRval->nTop = 0; // index of top item that's visible
1211  pRval->nHeight = 0; // height of viewport in 'items'
1212  pRval->nFlags = nFlags;
1213  pRval->wOwner = wOwner;
1214  pRval->pfnAllocator = pfnAllocator;
1215  pRval->pfnDestructor = pfnDestructor;
1216  if(pfnDisplay)
1217  {
1218  pRval->pfnDisplay = pfnDisplay;
1219  }
1220  else
1221  {
1223  }
1224  if(pfnSort)
1225  {
1226  pRval->pfnSort = pfnSort;
1227  }
1228  else
1229  {
1230  pRval->pfnSort = (int (*)(const void *,const void *))strcmp;
1231  }
1232  }
1233 
1234  return pRval;
1235 }
1236 
1238 {
1239 int i1;
1240 void **paData;
1241 
1242  if(!pListInfo)
1243  {
1244  return;
1245  }
1246 
1247  paData = pListInfo->aItems;
1248 
1249  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
1250  "%s - destroying %d items using %p for %p\n",
1251  __FUNCTION__, pListInfo->nItems, pListInfo->pfnDestructor, pListInfo->aItems);
1252 
1253  for(i1=0; i1 < pListInfo->nItems; i1++)
1254  {
1255  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_DialogCtrl | DebugSubSystem_Dialog,
1256  "%s - destroying item %d, value = %p\n",
1257  __FUNCTION__, i1, paData[i1]);
1258 
1259  if(pListInfo->pfnDestructor)
1260  {
1261  pListInfo->pfnDestructor(paData[i1]);
1262  }
1263  else if(paData[i1])
1264  {
1265  WBFree(paData[i1]);
1266  }
1267  }
1268 
1269  WBFree(pListInfo);
1270 }
1271 
1272 //typedef struct __LISTINFO__
1273 //{
1274 // int nItems, nMaxItems; // size/max size of aItems (must re-alloc to increase nMaxItems)
1275 // int nFlags; // flags (sorted, etc.)
1276 // Window wOwner; // owning window [to be notified on change]
1277 // void *(*pfnAllocator)(void *, int); // copy constructor to call for each item that's added
1278 // // typically this will call 'WBAlloc' followed by 'memcpy'
1279 // // if NULL, the caller-supplied pointer is assigned to 'aItems' as-is
1280 // void (*pfnDestructor)(void *); // destructor to call for each item that's removed
1281 // // typically this will point to 'WBFree'
1282 // // if NULL, the caller-supplied pointer is ignored
1283 //
1284 // void (*pfnDisplay)(WBDialogControl *pControl, void *pData, int iSelected, GC gcPaint, WB_GEOM *pGeom);
1285 // // generic function to display contents of item within 'pGeom' using GC
1286 // // typically one of the listbox 'display item' functions
1287 //
1288 // int (*pfnSort)(const void *, const void *); // sort proc (NULL implies strcmp)
1289 //
1290 // void *aItems[1]; // array of item data (remainder of struct)
1291 //} LISTINFO;
1292 
1293 const char * DLGGetControlListText(WBDialogControl *pCtrl, int iIndex)
1294 {
1295  const LISTINFO *pListInfo;
1297 
1298  if(!pProp || !pProp->pVal)
1299  {
1300  return NULL;
1301  }
1302 
1303  pListInfo = (LISTINFO *)(pProp->pVal);
1304 
1305  if(iIndex == ControlListIndex_LAST)
1306  {
1307  iIndex = pListInfo->nItems - 1;
1308  }
1309 
1310  if(iIndex < 0 || iIndex >= pListInfo->nItems)
1311  {
1312  return NULL;
1313  }
1314 
1315  if(!(pListInfo->aItems[iIndex]))
1316  {
1317  return ""; // always a non-NULL return if the item exists
1318  }
1319 
1320  return (const char *)(pListInfo->aItems[iIndex]);
1321 }
1322 
1323 const void * DLGGetControlListData(WBDialogControl *pCtrl, int iIndex)
1324 {
1325  const LISTINFO *pListInfo;
1327 
1328  if(!pProp || !pProp->pVal)
1329  {
1330  return NULL;
1331  }
1332 
1333  pListInfo = (LISTINFO *)(pProp->pVal);
1334 
1335  if(iIndex == ControlListIndex_LAST)
1336  {
1337  iIndex = pListInfo->nItems - 1;
1338  }
1339 
1340  if(iIndex < 0 || iIndex >= pListInfo->nItems)
1341  {
1342  return NULL;
1343  }
1344 
1345  return pListInfo->aItems[iIndex];
1346 }
1347 
1348 static DECLARE_SORT_FUNCTION(_actual_sort_proc,p0,p1,p2)
1349 //static int _actual_sort_proc(void *p0, const void *p1, const void *p2)
1350 {
1351  const void *p1a = *((const void * const *)p1);
1352  const void *p2a = *((const void * const *)p2);
1353  LISTINFO *pListInfo = (LISTINFO *)p0;
1354 
1355  if(pListInfo->pfnSort)
1356  {
1357  return pListInfo->pfnSort(p1a, p2a);
1358  }
1359 
1360  return strcmp(p1a, p2a);
1361 }
1362 
1363 int DLGAddControlListEntry(WBDialogControl *pCtrl, const char *pData, long cbData, int iIndex)
1364 {
1365  LISTINFO *pListInfo, *pListInfo0;
1367  WB_DIALOG_PROP propTemp;
1368  int i1;
1369  void *pTemp;
1370 
1371  if(!pProp || !pProp->pVal)
1372  {
1373  if(!(pCtrl->ulFlags & CONTROL_SupportListInfo))
1374  {
1375  // check first for the property, then return an error if it's
1376  // not supported (you never know...)
1377 
1378  WB_ERROR_PRINT("%s - control does not support 'LISTINFO'\n", __FUNCTION__);
1379  return -3;
1380  }
1381 
1382  pListInfo0 = NULL;
1383 
1384  // use the default settings to initialize the LISTINFO
1385  propTemp.aProp = aDLGC_LISTINFO;
1386  propTemp.lVal = 0;
1387  propTemp.pVal = DLGCListInfoConstructor(pCtrl->wID, DEFAULT_LISTINFO_MAX, ListInfoFlags_SORTED,
1389  WBFree,
1391  NULL);
1392 
1393  if(!propTemp.pVal)
1394  {
1395  WB_ERROR_PRINT("%s - unable to allocate 'LISTINFO'\n", __FUNCTION__);
1396  return -3; // error (unable to allocate LISTINFO)
1397  }
1398  }
1399  else
1400  {
1401  propTemp.aProp = pProp->aProp;
1402  propTemp.lVal = pProp->lVal;
1403  propTemp.pVal = pProp->pVal;
1404 
1405  pListInfo0 = (LISTINFO *)propTemp.pVal;
1406  }
1407 
1408  pListInfo = (LISTINFO *)propTemp.pVal;
1409 
1410  if(iIndex == ControlListIndex_INSERT_FIRST)
1411  {
1412  iIndex = -1; // note - this should really have no effect at all
1413  }
1414  else if(iIndex == ControlListIndex_INSERT_LAST)
1415  {
1416  iIndex = pListInfo->nItems - 1;
1417  }
1418  else if(iIndex < 0 || iIndex >= pListInfo->nItems)
1419  {
1420  if(!pListInfo0)
1421  {
1422  DLGCListInfoDestructor(propTemp.pVal);
1423  }
1424 
1425  WB_ERROR_PRINT("%s - invalid index %d\n", __FUNCTION__, iIndex);
1426 
1427  return -2;
1428  }
1429 
1430  if((iIndex + 1) >= pListInfo->nMaxItems)
1431  {
1432  int nItems = pListInfo->nMaxItems;
1433  // time to re-allocate
1434 
1435  if(nItems <= 0x40000)
1436  {
1437  nItems *= 2;
1438  }
1439  else
1440  {
1441  nItems += 0x40000;
1442  }
1443 
1444  i1 = sizeof(*pListInfo)
1445  + nItems * sizeof(pListInfo->aItems[0]);
1446 
1447  propTemp.pVal = WBReAlloc(pListInfo, i1);
1448 
1449  if(!propTemp.pVal)
1450  {
1451  if(!pListInfo0) // extremely unlikely, if not impossible, extremely defensive code
1452  {
1453  WB_ERROR_PRINT("%s:%d %s - this should never happen\n", __FILE__, __LINE__, __FUNCTION__);
1454  DLGCListInfoDestructor(pListInfo); // destroy the one I just created
1455  }
1456 
1457  return -4;
1458  }
1459 
1460  pListInfo->nMaxItems = nItems;
1461  // now I must go to the property list entry itself and forcibly assign this new pointer
1462 
1463  if(pProp)
1464  {
1465  pProp->pVal = propTemp.pVal; // this prevents memory leaks in case of an error
1466  }
1467 
1468  pListInfo = (LISTINFO *)propTemp.pVal; // re-assign to new value
1469  }
1470 
1471  if(!cbData)
1472  {
1473 // WB_ERROR_PRINT("TEMPORARY: %s:%s:%d NULL cbData\n", __FILE__, __FUNCTION__, __LINE__);
1474  pTemp = (void *)pData;
1475  }
1476  else if(pListInfo->pfnAllocator)
1477  {
1478  pTemp = pListInfo->pfnAllocator(pData, cbData);
1479 
1481 // if(pTemp == pData)
1482 // {
1483 // WB_ERROR_PRINT("%s:%s:%d pData == pTemp %p\n", __FILE__, __FUNCTION__, __LINE__, pTemp);
1484 // }
1485  }
1486  else
1487  {
1488  pTemp = NULL;
1489  }
1490 
1491  if(pListInfo->nFlags & ListInfoFlags_SORTED) // regardless of index, when sorted, do this
1492  {
1493  // add to the end to simplify the process, then qsort
1494  pListInfo->aItems[pListInfo->nItems] = (void *)pTemp;
1495 
1496  pListInfo->nItems++;
1497 
1498  // note: QSORT_R macro needed because qsort_r differs between linux and BSD
1499  QSORT_R(pListInfo->aItems, pListInfo->nItems, sizeof(void *), pListInfo, _actual_sort_proc);
1500  }
1501  else
1502  {
1503  if(iIndex < pListInfo->nItems)
1504  {
1505  for(i1=pListInfo->nItems; i1 >= iIndex; i1--)
1506  {
1507  pListInfo->aItems[i1 + 1] = pListInfo->aItems[i1];
1508  }
1509  }
1510 
1511  pListInfo->aItems[iIndex] = (void *)pTemp;
1512 
1513  pListInfo->nItems++;
1514  }
1515 
1516  i1 = WBDialogControlSetDialogProp(pCtrl, &propTemp);
1517 
1518  if(i1)
1519  {
1520  if(!pListInfo0) // attempted to add new item and failed?
1521  {
1522  DLGCListInfoDestructor(propTemp.pVal);
1523  }
1524 
1525  return i1;
1526  }
1527 
1528 // WB_ERROR_PRINT("TEMPORARY: %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
1529 // DEBUG_DUMP_LIST(pCtrl);
1530 
1531  return 0; // meaning 'success'
1532 }
1533 
1534 void DLGDelControlListEntry(WBDialogControl *pCtrl, int iIndex)
1535 {
1536  LISTINFO *pListInfo;
1538  int i1;
1539 
1540  if(!pProp || !pProp->pVal)
1541  {
1542  WB_WARN_PRINT("%s - unable to get LISTINFO for window %d (%08xH), pProp=%p\n", __FUNCTION__,
1543  (int)pCtrl->wID, (int)pCtrl->wID, pProp);
1544  return;
1545  }
1546 
1547  pListInfo = (LISTINFO *)pProp->pVal;
1548 
1549  if(iIndex == ControlListIndex_LAST)
1550  {
1551  iIndex = pListInfo->nItems - 1;
1552  }
1553  else if(iIndex == ControlListIndex_DELETE_ALL)
1554  {
1555  if(pListInfo->pfnDestructor)
1556  {
1557  for(i1=0; i1 < pListInfo->nItems; i1++)
1558  {
1559  pListInfo->pfnDestructor(pListInfo->aItems[i1]);
1560  }
1561  }
1562 
1563  pListInfo->aItems[0] = NULL; // do this by convention
1564  pListInfo->nItems = 0;
1565 
1566  return;
1567  }
1568  else if(iIndex < 0 || iIndex >= pListInfo->nItems)
1569  {
1570  WB_ERROR_PRINT("%s - invalid index %d\n", __FUNCTION__, iIndex);
1571  return;
1572  }
1573 
1574  if(pListInfo->pfnDestructor)
1575  {
1576  pListInfo->pfnDestructor(pListInfo->aItems[iIndex]);
1577  }
1578 
1579  pListInfo->nItems--;
1580 
1581  for(i1=iIndex; i1 < pListInfo->nItems; i1++)
1582  {
1583  pListInfo->aItems[i1] = pListInfo->aItems[i1 + 1];
1584  }
1585 
1586  pListInfo->aItems[pListInfo->nItems] = NULL; // by convention
1587 
1588 // WB_ERROR_PRINT("TEMPORARY: %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
1589 // DEBUG_DUMP_LIST(pCtrl);
1590 }
1591 
1592 
1593 //typedef struct _WB_LIST_CURSEL_
1594 //{
1595 // int iCurSel; // current selection
1596 // int iTopIndex; // index of item at top of window
1597 // int iHeight; // calculated height of window in "entries" (see next member)
1598 // int iEntryHeight; // cached display height of each entry (calculated by Expose handler)
1599 //} WBListCurSel; // intended to be member following WBDialogControl for "list" controls
1600 
1601 
1602 // getting "extension" structures from dialog control structure
1603 static WBListCurSel * __GetListCurSel(WBDialogControl *pCtrl)
1604 {
1605 WBListCurSel *pSel = (WBListCurSel *)(pCtrl + 1);
1606 
1607  if(!pCtrl || !(pCtrl->ulFlags & CONTROL_SupportListInfo)
1608  || (unsigned char *)(pSel + 1) > (((unsigned char *)pCtrl) + pCtrl->cbStructSize))
1609  {
1610  return NULL;
1611  }
1612 
1613  return pSel;
1614 }
1615 
1616 
1618 {
1620 WBListCurSel *pSel = __GetListCurSel(pCtrl);
1621 
1622  if(!pSel || !pProp || !pProp->pVal)
1623  {
1624  return ControlListIndex_NONE; // "no selection"
1625  }
1626 
1627  return pSel->iCurSel;
1628 }
1629 
1631 {
1633 WBListCurSel *pSel = __GetListCurSel(pCtrl);
1634 LISTINFO *pListInfo;
1635 int iOldIndex;
1636 
1637  if(!pSel || !pProp || !pProp->pVal)
1638  {
1639  WB_WARN_PRINT("%s - unable to get LISTINFO or 'selection info' for window %d (%08xH), pSel=%p, pProp=%p\n", __FUNCTION__,
1640  (int)pCtrl->wID, (int)pCtrl->wID, pSel, pProp);
1641  return;
1642  }
1643 
1644  pListInfo = (LISTINFO *)(pProp->pVal);
1645 
1646  iOldIndex = pSel->iCurSel;
1647 
1648  if(iIndex == ControlListIndex_LAST)
1649  {
1650  pSel->iCurSel = pListInfo->nItems - 1;
1651  }
1652  else if((iIndex >= 0 && iIndex < pListInfo->nItems)
1653  || iIndex == ControlListIndex_NONE)
1654  {
1655  pSel->iCurSel = iIndex;
1656  }
1657  else
1658  {
1659  WB_WARN_PRINT("%s - invalid index %d (nItems=%d)\n", __FUNCTION__, iIndex, pListInfo->nItems);
1660  return;
1661  }
1662 
1663  if(iOldIndex != pSel->iCurSel) // notify myself that something changed
1664  {
1665  DLGNotifySelf(pCtrl, aLIST_SELCHANGE, pSel->iCurSel, iOldIndex, 0, 0, 0);
1666  }
1667 }
1668 
1669 void DLGSetControlListSelectionValue(WBDialogControl *pCtrl, int iIndex, int iSelState)
1670 {
1671 }
1672 
1673 int DLGGetControlListSelectionBits(WBDialogControl *pCtrl, unsigned int *piBits, int nSize)
1674 {
1675  return 0; // for now (warning avoidance)
1676 }
1677 
1679 {
1680 int iSel = DLGGetControlListSelection(pCtrl);
1681 
1682  if(iSel >= 0)
1683  {
1684  return WBCopyString(DLGGetControlListText(pCtrl, iSel));
1685  }
1686 
1687  // TODO: multiple selections
1688 
1689  return NULL;
1690 }
1691 
1692 
1693 
1695 // the default list control display proc
1697 
1698 void DLGCDefaultListControlDisplayProc(WBDialogControl *pList, void *pData, int iSelected, GC gc, WB_GEOM *pGeom, XFontSet fontSet)
1699 {
1700 int iHPos;
1701 Window wID = pList->wID;
1702 Display *pDisplay = WBGetWindowDisplay(wID);
1703 
1704 
1705  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Event | DebugSubSystem_DialogCtrl,
1706  "%s - Expose %d (%08xH) pData=%p\n", __FUNCTION__, (int)wID, (int)wID, pData);
1707 
1708  if(fontSet == None)
1709  {
1710  fontSet = WBGetWindowFontSet(wID);
1711 
1712  if(fontSet == None)
1713  {
1714  fontSet = WBGetDefaultFontSet(pDisplay);
1715  }
1716  }
1717 
1718  if(fontSet == None)
1719  {
1720  // TODO: get font from dialog info
1721  WB_WARN_PRINT("%s - * BUG * line %d\n", __FUNCTION__, __LINE__);
1722  return;
1723  }
1724 
1725  iHPos = WBFontSetAvgCharWidth(pDisplay, fontSet); // average character width is new horiz pos
1726 
1727  // font setup
1729 // XClearWindow(pDisplay, wID); // TODO: rather than erase background, see if I need to
1730  XSetForeground(pDisplay, gc, iSelected ? pList->clrHBG.pixel : pList->clrBG.pixel);
1731  XFillRectangle(pDisplay, wID, gc, pGeom->x, pGeom->y, pGeom->width, pGeom->height);
1733 
1734  if(iSelected)
1735  {
1736  WBDrawDashedRect(pDisplay, wID, gc, pGeom, pList->clrBD2.pixel);
1737  }
1738 
1739 
1740  // vertically centered text
1741 // iVPos = pFont->max_bounds.ascent + pFont->max_bounds.descent; // font height
1742 // iVPos = (pGeom->height - iVPos) >> 1; // half of the difference - top of text
1743 // iVPos += pFont->max_bounds.ascent;
1744 
1745  // painting the window text
1746 
1747  if(pData)
1748  {
1749  const char *szText = (const char *)pData;
1750  WB_RECT rctBounds;
1751 
1752  rctBounds.left = pGeom->x + iHPos;
1753  rctBounds.right = pGeom->x + pGeom->width - iHPos; // equal border on right side, too
1754  rctBounds.top = pGeom->y;
1755  rctBounds.bottom = pGeom->y + pGeom->height;
1756 
1757 
1758  XSetForeground(pDisplay, gc, iSelected ? pList->clrHFG.pixel : pList->clrFG.pixel);
1759  XSetBackground(pDisplay, gc, iSelected ? pList->clrHBG.pixel : pList->clrBG.pixel);
1760 
1761  if(*szText)
1762  {
1763  DTDrawSingleLineText(fontSet, szText, pDisplay, gc, wID, 0, 0, &rctBounds,
1765  }
1766 
1767  if(iSelected) // selected item
1768  {
1769  XSetForeground(pDisplay, gc, pList->clrFG.pixel);
1770  XSetBackground(pDisplay, gc, pList->clrBG.pixel);
1771  }
1772  }
1773 
1774  // by convention, restore original objects/state
1775 
1777  XSetForeground(pDisplay, gc, WBGetWindowFGColor(wID)); // restore it at the end
1779 }
1780 
1781 
1782 
1783 
1785 // S C R O L L B A R H A N D L E R
1787 
1788 int DLGScrollBarHandler(Window wID, WBDialogControl *pCtrl, XEvent *pEvent)
1789 {
1790 int iX, iY, iDirection, iPosition;
1791 WB_SCROLLINFO *pScrollInfo;
1792 
1793 
1794  if(pEvent->type != ClientMessage)
1795  {
1796  return 0;
1797  }
1798 
1799  // look for the following:
1800  // left-button click inside of scroll bar
1801  // left button click ON the knob
1802  // left button click above/below/right-of/left-of knob
1803  // left button click on top/bottom/left/right arrow
1804 
1805  if(pEvent->xclient.message_type == aWM_POINTER)
1806  {
1807  // pointer messages - cooked mousie clickie
1808  WB_ERROR_PRINT("TEMPORARY: %s mouse message %d (%08xH) %d %d %d %d %d\n",
1809  __FUNCTION__,
1810  (int)pEvent->xclient.window, (int)pEvent->xclient.window,
1811  (int)pEvent->xclient.data.l[0],
1812  (int)pEvent->xclient.data.l[1],
1813  (int)pEvent->xclient.data.l[2],
1814  (int)pEvent->xclient.data.l[3],
1815  (int)pEvent->xclient.data.l[4]);
1816 
1818 
1819  if(pScrollInfo && WBScrollBarEvent(wID, pEvent, pScrollInfo))
1820  {
1821  return 1;
1822  }
1823 
1824 #if 0
1825  if(pEvent->xclient.data.l[0] == WB_POINTER_CLICK)
1826  {
1827  // TODO: handle shift-click, ctrl-click, alt-click
1828 
1829  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1830  !pEvent->xclient.data.l[2])
1831  {
1832  iX = pEvent->xclient.data.l[3];
1833  iY = pEvent->xclient.data.l[4];
1834 
1836 
1837  if(WB_LIKELY(pScrollInfo != NULL))
1838  {
1839  iDirection = WB_SCROLL_NA;
1840  iPosition = 0;
1841 
1842  if(WBPointInGeom(iX, iY, pScrollInfo->geomVBar))
1843  {
1844  if(WBPointInGeom(iX, iY, pScrollInfo->geomVUp))
1845  {
1846  iDirection = WB_SCROLL_BACKWARD;
1847  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (up)\n", __FUNCTION__);
1848  }
1849  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVDown))
1850  {
1851  iDirection = WB_SCROLL_FORWARD;
1852  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (down)\n", __FUNCTION__);
1853  }
1854  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVKnob))
1855  {
1856  // ON THE KNOB - VScroll
1857 
1858  iDirection = WB_SCROLL_KNOB;
1859 // iPosition = pScrollInfo->iVMin; //pListInfo->nTop; // NO!
1860  iPosition = WBCalcVScrollDragPos(pScrollInfo, iY);
1861 
1862  if(iPosition < 0)
1863  {
1864  iPosition = pScrollInfo->iVMin; //pListInfo->nTop;
1865  }
1866 
1867  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (knob)\n", __FUNCTION__);
1868 
1869  // TODO: determine position of knob
1870  }
1871  else if(iY >= pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height &&
1872  iY < pScrollInfo->geomVKnob.y)
1873  {
1874  iDirection = WB_SCROLL_PAGEBACK;
1875  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (page up)\n", __FUNCTION__);
1876  }
1877  else if(iY >= pScrollInfo->geomVKnob.y + pScrollInfo->geomVKnob.height &&
1878  iY < pScrollInfo->geomVDown.y)
1879  {
1880  iDirection = WB_SCROLL_PAGEFWD;
1881  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (page down)\n", __FUNCTION__);
1882  }
1883  else
1884  {
1885  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (unknown)\n", __FUNCTION__);
1886  }
1887 
1888  DLGNotifySelf(pCtrl, aSCROLL_NOTIFY, WB_SCROLL_VERTICAL, iDirection, iPosition, 0, 0);
1889 
1890  return 1; // handled
1891  }
1892  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHBar))
1893  {
1894  if(WBPointInGeom(iX, iY, pScrollInfo->geomHLeft))
1895  {
1896  iDirection = WB_SCROLL_BACKWARD;
1897  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (left)\n", __FUNCTION__);
1898  }
1899  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHRight))
1900  {
1901  iDirection = WB_SCROLL_FORWARD;
1902  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (right)\n", __FUNCTION__);
1903  }
1904  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHKnob))
1905  {
1906  // ON THE KNOB - HScroll
1907 
1908  iDirection = WB_SCROLL_KNOB;
1909 // iPosition = pScrollInfo->iHMin; // NO!
1910  iPosition = WBCalcHScrollDragPos(pScrollInfo, iY);
1911 
1912  if(iPosition < 0)
1913  {
1914  iPosition = pScrollInfo->iHMin; //pListInfo->nTop;
1915  }
1916 
1917  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (knob)\n", __FUNCTION__);
1918 
1919  // TODO: determine position of knob
1920  }
1921  else if(iX >= pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width &&
1922  iX < pScrollInfo->geomHKnob.x)
1923  {
1924  iDirection = WB_SCROLL_PAGEBACK;
1925  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (page left)\n", __FUNCTION__);
1926  }
1927  else if(iX >= pScrollInfo->geomHKnob.x + pScrollInfo->geomHKnob.width &&
1928  iX < pScrollInfo->geomHRight.x)
1929  {
1930  iDirection = WB_SCROLL_PAGEFWD;
1931  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (page right)\n", __FUNCTION__);
1932  }
1933  else
1934  {
1935  WB_ERROR_PRINT("TEMPORARY - %s Mouse click in scroll bar (unknown)\n", __FUNCTION__);
1936  }
1937 
1938  DLGNotifySelf(pCtrl, aSCROLL_NOTIFY, WB_SCROLL_HORIZONTAL, iDirection, iPosition, 0, 0);
1939 
1940  return 1; // handled
1941  }
1942  }
1943  }
1944  }
1945  else if(pEvent->xclient.data.l[0] == WB_POINTER_DBLCLICK)
1946  {
1947  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1948  !pEvent->xclient.data.l[2])
1949  {
1950  iX = pEvent->xclient.data.l[3];
1951  iY = pEvent->xclient.data.l[4];
1952  // assume selection already done, so notify owner
1953 
1955 
1956  if(WB_LIKELY(pScrollInfo != NULL))
1957  {
1958  if(WBPointInGeom(iX, iY, pScrollInfo->geomVBar))
1959  {
1960  // if not within knob, re-post to self as single-click
1961  if(!WBPointInGeom(iX, iY, pScrollInfo->geomVKnob))
1962  {
1963  XClientMessageEvent evt;
1964  memcpy(&evt, pEvent, sizeof(evt));
1965  evt.data.l[0] = WB_POINTER_CLICK;
1966 
1967  return DLGScrollBarHandler(wID, pCtrl, (XEvent *)&evt);
1968  }
1969  }
1970  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHBar))
1971  {
1972  // if not within knob, re-post to self as single-click
1973  if(!WBPointInGeom(iX, iY, pScrollInfo->geomHKnob))
1974  {
1975  XClientMessageEvent evt;
1976  memcpy(&evt, pEvent, sizeof(evt));
1977  evt.data.l[0] = WB_POINTER_CLICK;
1978 
1979  return DLGScrollBarHandler(wID, pCtrl, (XEvent *)&evt);
1980  }
1981  }
1982  }
1983  }
1984  }
1985  else if(pEvent->xclient.data.l[0] == WB_POINTER_CANCEL)
1986  {
1987  // canceling drag (as appropriate)
1988 
1990 
1991 // if(pScrollInfo &&
1992 // pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1993 // !pEvent->xclient.data.l[2])
1994 // {
1995 // pScrollInfo->iScrollState &= ~WBScrollState_LDRAG;
1996 // }
1997  if((pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
1998  (pScrollInfo->iScrollState & WBScrollState_MDRAG) ||
1999  (pScrollInfo->iScrollState & WBScrollState_RDRAG))
2000  {
2002 
2003  return 1; // "handled"
2004  }
2005  }
2006  else if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG ||
2007  pEvent->xclient.data.l[0] == WB_POINTER_MOVE)
2008  {
2009  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
2010  !pEvent->xclient.data.l[2])
2011  {
2012  iX = pEvent->xclient.data.l[3];
2013  iY = pEvent->xclient.data.l[4];
2014 
2016 
2017  if(WB_LIKELY(pScrollInfo != NULL))
2018  {
2019  if(!WBPointInGeom(iX, iY, pScrollInfo->geomVBar) &&
2020  !WBPointInGeom(iX, iY, pScrollInfo->geomHBar) &&
2021  (!(pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
2022  pEvent->xclient.data.l[0] == WB_POINTER_DRAG))
2023  {
2024  // TODO: this is for multi-select listboxes, doing a drag-select
2025 
2026  pScrollInfo->iScrollState &= ~WBScrollState_LDRAG; // make sure
2027 
2028  return 0; // "not handled" (allow drag-select to be handled by scrollbar owner)
2029  }
2030  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVKnob) ||
2031  WB_LIKELY(pEvent->xclient.data.l[0] == WB_POINTER_MOVE &&
2032  (pScrollInfo->iScrollState & WBScrollState_LDRAG)))
2033  {
2034  if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG) // begin drag, return window ID
2035  {
2036  WB_ERROR_PRINT("TEMPORARY - %s Mouse drag in scroll bar (knob)\n", __FUNCTION__);
2037 
2038  pScrollInfo->iScrollState |= WBScrollState_LDRAG; // set the state bit for left-drag
2039  return((int)wID); // enabling the drag
2040  }
2041 
2042  iPosition = WBCalcVScrollDragPos(pScrollInfo, iY);
2043 
2044  if(iPosition < 0)
2045  {
2046  iPosition = pScrollInfo->iVMin; //pListInfo->nTop;
2047  }
2048 
2049  // track the mouse position along the center of the knob, if possible
2050 
2051  WB_ERROR_PRINT("TEMPORARY - %s Mouse motion in scroll bar (knob)\n", __FUNCTION__);
2052 
2054  WB_SCROLL_KNOB, iPosition, 0, 0);
2055  }
2056  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHKnob) ||
2057  WB_LIKELY(pEvent->xclient.data.l[0] == WB_POINTER_MOVE &&
2058  (pScrollInfo->iScrollState & WBScrollState_HLDRAG)))
2059  {
2060  if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG) // begin drag, return window ID
2061  {
2062  WB_ERROR_PRINT("TEMPORARY - %s Mouse drag in scroll bar (knob)\n", __FUNCTION__);
2063 
2064  pScrollInfo->iScrollState |= WBScrollState_HLDRAG; // set the state bit for left-drag
2065  return((int)wID); // enabling the drag
2066  }
2067 
2068  iPosition = WBCalcHScrollDragPos(pScrollInfo, iX);
2069 
2070  if(iPosition < 0)
2071  {
2072  iPosition = pScrollInfo->iHMin; // pListInfo->nTop;
2073  }
2074 
2075  // track the mouse position along the center of the knob, if possible
2076 
2077  WB_ERROR_PRINT("TEMPORARY - %s Mouse motion in scroll bar (knob)\n", __FUNCTION__);
2078 
2080  WB_SCROLL_KNOB, iPosition, 0, 0);
2081  }
2082  else
2083  {
2084  WB_ERROR_PRINT("TEMPORARY - %s mouse motion in scroll bar outside of knob\n", __FUNCTION__);
2085  }
2086  }
2087  }
2088  }
2089  else if(pEvent->xclient.data.l[0] == WB_POINTER_DROP)
2090  {
2092 
2093  if(WB_LIKELY(pScrollInfo != NULL))
2094  {
2095  if((pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
2096  (pScrollInfo->iScrollState & WBScrollState_MDRAG) ||
2097  (pScrollInfo->iScrollState & WBScrollState_RDRAG))
2098  {
2100 
2101  return 1; // "handled" (just a notification anyway)
2102  }
2103  }
2104  }
2105  else if(pEvent->xclient.data.l[0] == WB_POINTER_SCROLLUP)
2106  {
2108  }
2109  else if(pEvent->xclient.data.l[0] == WB_POINTER_SCROLLDOWN)
2110  {
2112  }
2113 #endif // 0
2114  }
2115  else if(pEvent->xclient.message_type == aWM_CHAR)
2116  {
2117  // handle cursors only - up, down, left, right, home, end, page up, page down, etc.
2118 
2119  long lKey = pEvent->xclient.data.l[0]; // return from WBKeyEventProcessKey
2120  long lAltCtrlShift = pEvent->xclient.data.l[1]; // *piAltCtrlShift from WBKeyEventProcessKey
2121 #ifndef NO_DEBUG
2122  int nChar = (int)pEvent->xclient.data.l[2]; // # of characters decoded into pBuf (below)
2123  char *pBuf = (char *)&(pEvent->xclient.data.l[3]); // decode buffer (at least 8 chars in length)
2124 #endif // !NO_DEBUG
2125 
2126 
2127  WB_ERROR_PRINT("TEMPORARY: %s char message %lx %ld %d %s\n", __FUNCTION__, lAltCtrlShift, lKey, nChar, pBuf);
2128 
2129  if(lAltCtrlShift & WB_KEYEVENT_KEYSYM) // symbol keys only for this part
2130  {
2132 
2133  if(WB_LIKELY(pScrollInfo != NULL))
2134  {
2135  int iShift = lAltCtrlShift & WB_KEYEVENT_SHIFT;
2136  int iCtrl = lAltCtrlShift & WB_KEYEVENT_CTRL;
2137  int iAlt = lAltCtrlShift & WB_KEYEVENT_ALT;
2138  int iBar = WB_SCROLL_NA;
2139  int iDirection = WB_SCROLL_NA;
2140 
2141  switch(lKey)
2142  {
2143  case XK_Up:
2144  if(iShift || iCtrl || iAlt)
2145  {
2146  return 0;
2147  }
2148 
2149  iBar = WB_SCROLL_VERTICAL;
2150  iDirection = WB_SCROLL_BACKWARD;
2151  break;
2152 
2153  case XK_Down:
2154  if(iShift || iCtrl || iAlt)
2155  {
2156  return 0;
2157  }
2158 
2159  iBar = WB_SCROLL_VERTICAL;
2160  iDirection = WB_SCROLL_FORWARD;
2161  break;
2162 
2163  case XK_Left:
2164  if(iShift || iCtrl || iAlt)
2165  {
2166  return 0;
2167  }
2168 
2169  iBar = WB_SCROLL_HORIZONTAL;
2170  iDirection = WB_SCROLL_BACKWARD;
2171  break;
2172 
2173  case XK_Right:
2174  if(iShift || iCtrl || iAlt)
2175  {
2176  return 0;
2177  }
2178 
2179  iBar = WB_SCROLL_HORIZONTAL;
2180  iDirection = WB_SCROLL_FORWARD;
2181  break;
2182 
2183  case XK_Home:
2184 
2185  if(iShift || iAlt)
2186  {
2187  return 0;
2188  }
2189 
2190  if(iCtrl)
2191  {
2192  iBar = WB_SCROLL_VERTICAL;
2193  }
2194  else
2195  {
2196  iBar = WB_SCROLL_HORIZONTAL;
2197  }
2198 
2199  iDirection = WB_SCROLL_FIRST;
2200  break;
2201 
2202  case XK_End:
2203 
2204  if(iShift || iAlt)
2205  {
2206  return 0;
2207  }
2208 
2209  if(iCtrl)
2210  {
2211  iBar = WB_SCROLL_VERTICAL;
2212  }
2213  else
2214  {
2215  iBar = WB_SCROLL_HORIZONTAL;
2216  }
2217 
2218  iDirection = WB_SCROLL_LAST;
2219  break;
2220 
2221  case XK_Page_Up:
2222 
2223  if(iShift || iAlt)
2224  {
2225  return 0;
2226  }
2227 
2228  if(!iCtrl)
2229  {
2230  iBar = WB_SCROLL_VERTICAL;
2231  }
2232  else
2233  {
2234  iBar = WB_SCROLL_HORIZONTAL;
2235  }
2236 
2237  iDirection = WB_SCROLL_PAGEBACK;
2238  break;
2239 
2240  case XK_Page_Down:
2241 
2242  if(iShift || iAlt)
2243  {
2244  return 0;
2245  }
2246 
2247  if(!iCtrl)
2248  {
2249  iBar = WB_SCROLL_VERTICAL;
2250  }
2251  else
2252  {
2253  iBar = WB_SCROLL_HORIZONTAL;
2254  }
2255 
2256  iDirection = WB_SCROLL_PAGEFWD;
2257  break;
2258 
2259  default:
2260  return 0;
2261  }
2262 
2263  // see if the bar is actually visible first
2264  if(iBar == WB_SCROLL_HORIZONTAL)
2265  {
2266  if(pScrollInfo->geomHBar.width <= 0 || pScrollInfo->geomHBar.height <= 0)
2267  {
2268  return 0; // no vertical scroll bar
2269  }
2270  }
2271  else // vertical
2272  {
2273  if(pScrollInfo->geomVBar.width <= 0 || pScrollInfo->geomVBar.height <= 0)
2274  {
2275  return 0; // no vertical scroll bar
2276  }
2277  }
2278 
2279  DLGNotifySelf(pCtrl, aSCROLL_NOTIFY, iBar, iDirection, 0, 0, 0);
2280  return 1; // keystroke eaten
2281  }
2282  }
2283  }
2284 
2285  return 0; // NOT handled
2286 }
2287 
2288 
2289 #ifndef NO_DEBUG
2290 void DEBUG_DUMP_LIST(WBDialogControl *pCtrl)
2291 {
2292  LISTINFO *pListInfo;
2293  WB_DIALOG_PROP *pProp;
2294  int i1;
2295  const char *p1;
2296 
2297 
2298  if(WB_LIKELY((WBGetDebugLevel() & DebugLevel_MASK) < (DebugLevel_Light & DebugLevel_MASK)) ||
2299  ((WBGetDebugLevel() & DebugSubSystem_MASK) && !(DebugSubSystem_DialogCtrl & WBGetDebugLevel())))
2300  {
2301  return;
2302  }
2303 
2305 
2306  if(!pProp || !pProp->pVal)
2307  {
2308  if(!(pCtrl->ulFlags & CONTROL_SupportListInfo))
2309  {
2310  WBDebugPrint("%s - control does not support 'LISTINFO'\n", __FUNCTION__);
2311  }
2312  else
2313  {
2314  WBDebugPrint("%s - 'LISTINFO' is empty\n", __FUNCTION__);
2315  }
2316 
2317  return;
2318  }
2319 
2320  pListInfo = (LISTINFO *)pProp->pVal;
2321 
2322  if(pListInfo->nFlags & ListInfoFlags_SORTED) // regardless of index, when sorted, do this
2323  {
2324  WBDebugPrint("%s - 'LISTINFO' is sorted\n", __FUNCTION__);
2325  }
2326 
2327  WBDebugPrint("%s - 'LISTINFO' %d items\n", __FUNCTION__, pListInfo->nItems);
2328 
2329  for(i1=0; i1 < pListInfo->nItems; i1++)
2330  {
2331  // for now assume string data
2332  WBDebugPrint(" %6d: %p %s\n", i1, pListInfo->aItems[i1], (char *)(pListInfo->aItems[i1]));
2333  }
2334 }
2335 #endif // NO_DEBUG
2336 
2337 
WB_GEOM geomVKnob
geometry for the vertical scroll bar &#39;knob&#39; (empty if not visible)
Atom aLOSTFOCUS
CONTROL_NOTIFY ClientMessage for LOSTFOCUS event.
int nMaxProps
maximum number of available WB_DIALOG_PROP structures in aDlgProp
int cbStructSize
assigned at allocation time, the total size of this structure
Atom aDLGC_CAPTION
dialog control CAPTION property - see WBDialogControlGetCaption()
#define WB_POINTER_DBLCLICK
WM_POINTER &#39;double-click&#39; event, send in lieu of WB_POINTER_CLICK for double-click.
&#39;window helper&#39; main header file for the X11workbench Toolkit API
void DLGCListInfoDestructor(LISTINFO *pListInfo)
Destroy a LISTINFO structure.
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
int iHMin
minimum horizontal range (0 if no bar)
#define WB_POINTER_CLICK
Mouse &#39;click&#39; event.
Atom aGOTFOCUS
CONTROL_NOTIFY ClientMessage for GOTFOCUS event.
int nProps
current number of (contiguous) properties in &#39;aDlgProp&#39;
struct __WB_DIALOG_PROPLIST__ WBDialogPropList
Dialog Property List, container for WB_DIALOG_PROP.
static __inline__ unsigned int WBGetDebugLevel(void)
Returns the current debug level assigned by WBSetDebugLevel.
Definition: debug_helper.h:68
WB_DIALOG_PROP aDlgProp[1]
Pre-allocated array of (contiguous) structures for property storage.
2nd parameter (direction) - bottom, end
1st parameter (bar) - The horizontal scroll bar for the control or window
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:196
2nd parameter (direction) - down, right
#define WB_POINTER_DROP
WM_POINTER &#39;drop&#39; event, only sent if drag/drop supported AND was not &#39;canceled&#39;; see WB_POINTER_CANC...
Pixmap pixmap
foreground pixmap
void DLGDelControlListEntry(WBDialogControl *pCtrl, int iIndex)
Delete a list entry from a control&#39;s list info at a specified index (or deletes ALL entries) ...
Utilities for copying and drawing text, determining text extents, and so on.
Atom aPATH_TREE_CONTROL
Standard Dialog Control - path tree - directory hierarchy - see PATH_TREE_CONTROL_STR.
Pixmap pixmap2
background (transparency) pixmap
int nTop
scroll position of the top item currently displayed
1st parameter (bar) - The vertical scroll bar for the control or window.
Atom aDLGC_TEXT
dialog control TEXT property - see WBDialogControlGetText()
void DTDrawSingleLineText(XFontSet fontSet, const char *szText, Display *pDisplay, GC gc, Drawable dw, int iTabWidth, int iTabOrigin, const WB_RECT *prcBounds, int iAlignment)
draw single-line text
Definition: draw_text.c:1282
#define WB_POINTER_SCROLLDOWN
WM_POINTER &#39;scroll down&#39; event, caused by mouse button 5.
XColor clrHFG
highlighted state-based foreground color
int iCurSel
current selection
int WBScrollBarEvent(Window wID, XEvent *pEvent, WB_SCROLLINFO *pScrollInfo)
Event handler for scroll bars.
Atom aLIST_NOTIFY
CONTROL_NOTIFY ClientMessage for LIST_NOTIFY event.
XColor clrBG
background color
#define WB_KEYEVENT_ALT
&#39;AltCtrlShift&#39; bit flag for ALT modifier for WBKeyEventProcessKey()
Atom aMOUSE_UP
CONTROL_NOTIFY ClientMessage for MOUSE_UP event.
WB_GEOM geomVBar
geometry for the vertical scroll bar excluding border (empty if not visible)
void DLGSetControlListSelection(WBDialogControl *pCtrl, int iIndex)
Assign the current selection index for a single-selection list.
Atom aKEY_DOWN
CONTROL_NOTIFY ClientMessage for KEY_DOWN event.
last list index
int DLGAddControlListEntry(WBDialogControl *pCtrl, const char *pData, long cbData, int iIndex)
Add a list entry to a control&#39;s list info.
int WBCalcHScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iX)
Calculate and assign the correct horizontal scroll bar position from mouse coordinates.
WB_GEOM geomVUp
geometry for the vertical scroll bar &#39;up&#39; button (empty if not visible)
Atom aDEFPUSHBUTTON_CONTROL
Standard Dialog Control - default Pushbutton control (has dark border, accepts <ENTER> as hotkey) - s...
#define DECLARE_SORT_FUNCTION(fn_name, p0, p1, p2)
Wrapper to declare a sort function for QSORT_R.
this control supports a LISTINFO property.
Atom aLIST_SELCHANGE
LIST_SELCHANGE ClientMessage, notify self of list selection change.
Pixmap pixmap2
background (transparency) pixmap
unsigned long ulFlags
generic flag bits
Atom aWM_CHAR
keystroke/character notifications generated by API
const void * DLGGetControlListData(WBDialogControl *pCtrl, int iIndex)
Retrieve the data pointer for a single list entry (listbox, combo, and tree controls only) ...
2nd parameter (direction) - pgup, pgleft
&#39;configuration helper&#39; main header file for the X11 Work Bench Toolkit API
int iScrollState
scroll state flags - see enumeration WBScrollState_ENUM
int nMaxItems
max size of aItems (must re-alloc to increase nMaxItems)
unsigned long lVal
&#39;long&#39; data value, assigned as needed
void * WBReAlloc(void *pBuf, int nNewSize)
High performance memory sub-allocator &#39;re-allocate&#39;.
int DLGInitControlListInfo(WBDialogControl *pCtrl, int nFlags, void *(*pfnAllocator)(const void *, int), void(*pfnDestructor)(void *), void(*pfnDisplay)(WBDialogControl *, void *, int, GC, WB_GEOM *, XFontSet), int(*pfnSort)(const void *, const void *))
Initialize the &#39;List Entry&#39; for a control, specifying various callbacks and flags.
XColor clrBD2
3D border color 2 (light)
int nHeight
height (in items) of display area, recalculated on resize/expose
WBDialogPropList * pPropList
pointer to the property list (may be NULL)
2nd parameter (direction) - up, left
Atom aLIST_CONTROL
Standard Dialog Control - list - single, multi, extended select (h, v, multicol) - see LIST_CONTROL_S...
void WBDialogControlDelDialogProp(WBDialogControl *pCtrl, Atom aProp)
Low-level dialog control property removal.
Atom aRADIOBUTTON_CONTROL
Standard Dialog Control - radio button - see RADIOBUTTON_CONTROL_STR.
const char * WBDialogControlGetProperty(WBDialogControl *pCtrl, Atom aPropName)
Mid-level dialog control property retrieval (character string)
Atom aClass
basic control class atom
Atom aSLIDER_CONTROL
Standard Dialog Control - volume control (slider bar) (h or v depending on geometry) - see SLIDER_CON...
void WBInvalidateGeom(Window wID, const WB_GEOM *pGeom, int bPaintNow)
&#39;Paint&#39; helper, invalidates a geometry for asynchronous Expose event generation
XColor clrHBG
highlighted state-based background color
Structure that defines scroll bar info for both horizontal and vertical scroll bars.
void WBDialogControlSetIconPixmap(WBDialogControl *pCtrl, Pixmap pixmap, Pixmap pixmap2)
Assign the ICON (image) property for a control, which consists of 2 pixmaps.
Window wID
Window ID of the dialog control window.
Atom aDIALOG_INIT
DIALOG_INIT ClientMessage, sent to dialog window callback on frame create.
void(* pfnDisplay)(WBDialogControl *pControl, void *pData, int iSelected, GC gcPaint, WB_GEOM *pGeom, XFontSet fontSet)
display callback function to paint the entry on the display surface
Window wOwner
owning window [to be notified on change]
left button in &#39;drag&#39; state on vertical scroll bar (relies on drag cancel)
unsigned long WBGetWindowFGColor(Window wID)
Returns the currently assigned foreground color.
center using entire text height (ascent + descent for single line)
Definition: draw_text.h:86
void(* pfnDestructor)(void *)
destructor to call for each item that&#39;s removed
Atom aTAB_CONTROL
Standard Dialog Control -&#39;tab&#39; container (auto enable/disable contents) - see TAB_CONTROL_STR.
Atom aTEXT_CONTROL
Standard Dialog Control - static text (single or multi-line) - see TEXT_CONTROL_STR.
LISTINFO * DLGCListInfoConstructor(Window wOwner, int nMax, int nFlags, void *(*pfnAllocator)(const void *, int), void(*pfnDestructor)(void *), void(*pfnDisplay)(WBDialogControl *, void *, int, GC, WB_GEOM *, XFontSet), int(*pfnSort)(const void *, const void *))
Create LISTINFO structure for a list type control.
void * WBAlloc(int nSize)
High performance memory sub-allocator &#39;allocate&#39;.
unsigned int width
#define END_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro follows the call(s)
#define WB_POINTER_SCROLLUP
WM_POINTER &#39;scroll up&#39; event, caused by mouse button 4.
Pixmap WBDialogControlGetPixmap(WBDialogControl *pCtrl)
Obtain the assigned PIXMAP (image) property for a control.
int WBDialogControlSetDialogProp(WBDialogControl *pCtrl, WB_DIALOG_PROP *pPropVal)
Low-level dialog control property assignment.
unsigned int height
Atom aMOUSE_DOWN
CONTROL_NOTIFY ClientMessage for MOUSE_DOWN event.
Button &#39;pushbutton&#39; control structure.
Atom aCOMBO_CONTROL
Standard Dialog Control - classic &#39;combo box&#39; control - see COMBO_CONTROL_STR.
int DLGGetControlListSelectionBits(WBDialogControl *pCtrl, unsigned int *piBits, int nSize)
Query the selection state for multiple items within a control&#39;s list info.
Dialog property storage structure.
int WBFontSetAvgCharWidth(Display *pDisplay, XFontSet fontSet)
Get the average character width for a font set.
Definition: font_helper.c:1227
#define WB_ERROR_PRINT(...)
Preferred method of implementing an &#39;error level&#39; debug message for all subsystems.
Definition: debug_helper.h:268
char * DLGGetControlListSelectionText(WBDialogControl *pCtrl)
Query the selection text as multiple strings in an allocated buffer.
Atom aFILE_COMBO_CONTROL
Standard Dialog Control - file combo control - see FILE_COMBO_CONTROL_STR.
int WBDialogControlSetPropList(WBDialogControl *pCtrl, const char *szPropList)
Mid-level dialog control property list assignment.
Atom aVSCROLL_CONTROL
Standard Dialog Control - vertical scroll - see VSCROLL_CONTROL_STR.
void WBFree(void *pBuf)
High performance memory sub-allocator &#39;free&#39;.
#define WB_POINTER_CANCEL
WM_POINTER &#39;cancel&#39; event, cancels an ongoing operation, such as drag/drop (useful for resource clean...
#define WB_KEYEVENT_SHIFT
&#39;AltCtrlShift&#39; bit flag for Shift modifier for WBKeyEventProcessKey()
Atom aCOMBOTREE_CONTROL
Standard Dialog Control - &#39;combo tree&#39; (tree with interlocked edit/text box like combo box) - see COM...
int nItems
current number of valid entries in &#39;aItems&#39;
Atom aDLGC_SCROLLINFO
dialog control SCROLLINFO property - see WB_SCROLLINFO structure
Atom aDLGC_PROP_NOTIFY
DLGC_PROP_NOTIFY ClientMessage, notify control of property change.
Atom aDLGC_PATH
dialog control PATH property, for file and directory controls
int nPos
current scroll position
middle button in &#39;drag&#39; state on vertical scroll bar
2nd parameter (direction) - &#39;knob track&#39; - pos in data.l[2]
void WBUpdateWindow(Window wID)
&#39;Paint&#39; helper, generates an asynchronous Expose event for non-empty &#39;invalid&#39; region ...
Atom aSCROLL_NOTIFY
#define WB_POINTER_MOVE
WM_POINTER &#39;move&#39; event, for motion notification during drag/drop.
#define WB_POINTER_DRAG
WM_POINTER &#39;drag&#39; event, window proc MUST return the window ID to auto-support drag/drop.
WB_GEOM geomHLeft
geometry for the horizontal scroll bar &#39;left&#39; button (empty if not visible)
Atom aEDIT_CONTROL
Standard Dialog Control - editable text (single or multi-line, scrollable, clipboard) - see EDIT_CONT...
Atom aProp
Atom identifying the property.
Dialog Property List, container for WB_DIALOG_PROP.
#define WB_POINTER_BUTTON1
WM_POINTER button bitmask indicating that button 1 is pressed.
int nFlags
flags (sorted, etc.)
A &#39;C++&#39;-like object for managing text, can be overridden.
Atom aKEYSTROKE
CONTROL_NOTIFY ClientMessage for KEYSTROKE event.
internal wrapper struct for &#39;rectangle&#39; definition
void DLGCDefaultListControlDisplayProc(WBDialogControl *pList, void *pData, int iSelected, GC gc, WB_GEOM *pGeom, XFontSet fontSet)
The default &#39;display proc&#39; for displaying a list item from a LISTINFO structure.
2nd parameter (direction) - home, top
int WBCalcVScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iY)
Calculate and assign the correct vertical scroll bar position from mouse coordinates.
WB_GEOM geomHBar
geometry for the horizontal scroll bar excluding border (empty if not visible)
#define QSORT_R(base, nmemb, size, thunk, compar)
Local implementation of qsort_r() for operating systems that do not have it.
void DLGCDestroyProperties(WBDialogPropList *pPropList)
Destroy Properties for a dialog control.
void * WBDialogControlGetProperty2(WBDialogControl *pCtrl, Atom aPropName)
Mid-level dialog control property list retrieval (generic pointer)
Atom aCANCELBUTTON_CONTROL
Standard Dialog Control - cancel pushbutton control (accepts <ESC> as hotkey) - see CANCELBUTTON_CONT...
2nd parameter (direction) - pgdn, pgright
Atom aWM_POINTER
pointer click/double-click/drag notifications generated by API
Structure identifying the properties of a dialog box control.
Atom aHSCROLL_CONTROL
Standard Dialog Control - horizontal scroll - see HSCROLL_CONTROL_STR.
Atom aCHECKBUTTON_CONTROL
Standard Dialog Control - check[box] button - push-on/push-off with &#39;check mark&#39; (or whatever) - see ...
Atom aKEY_UP
CONTROL_NOTIFY ClientMessage for KEY_UP event.
generic &#39;NA&#39; or &#39;UNDEFINED&#39; value
XColor clrFG
foreground color
Atom aMOUSE_DRAG
CONTROL_NOTIFY ClientMessage for MOUSE_DRAG event.
const char * WBDialogControlGetCaption(WBDialogControl *pCtrl)
Obtain a pointer to the assigned text for the &#39;CAPTION&#39; property of a dialog control.
const WB_DIALOG_PROP * WBDialogControlGetDialogProp(WBDialogControl *pCtrl, Atom aProp)
Low-level dialog control property retrieval.
Static &#39;Image&#39; control structure.
Atom aIMAGE_CONTROL
Standard Dialog Control - generic image/pixmap holder - see IMAGE_CONTROL_STR.
Atom aTEXTSELECT_CHANGE
CONTROL_NOTIFY ClientMessage for TEXTSELECT_CHANGE event.
char * pCaption
allocated pointer to caption, in lieu of using a WM_NAME property (may be NULL)
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
int DLGGetControlListSelection(WBDialogControl *pCtrl)
Obtain the current selection index for a single-selection list.
void DLGSetControlListSelectionValue(WBDialogControl *pCtrl, int iIndex, int iSelState)
Assign the selection state for a specific index within a control&#39;s list info.
Atom aKNOB_CONTROL
Standard Dialog Control - "volume knob" (270 degrees of rotation, left to right) - see KNOB_CONTROL_S...
Atom aFIRSTRADIOBUTTON_CONTROL
Standard Dialog Control - &#39;first&#39; radio button - defines start of radio button &#39;group&#39; - see FIRSTRAD...
Atom aTREE_CONTROL
Standard Dialog Control - class &#39;tree&#39; control - see TREE_CONTROL_STR.
int(* pfnSort)(const void *, const void *)
Optional sort comparison function. NULL implies &#39;strcmp&#39;.
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)
always insert at end
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, GC, WB_GEOM *, XFontSet), int bSort, int(*pfnSort)(const void *, const void *))
Modify the &#39;List Entry&#39; for a control, specifying various callbacks and flags.
Structure containing information about the current selection in a list.
WB_GEOM geomHKnob
geometry for the horizontal scroll bar &#39;knob&#39; (empty if not visible)
int DLGScrollBarHandler(Window wID, WBDialogControl *pCtrl, XEvent *pEvent)
Scroll bar event filter for dialog control callback function. Generates scroll events.
int iVMin
minimum vertical range (0 if no bar)
Atom aBUTTON_PRESS
CONTROL_NOTIFY ClientMessage for BUTTON_PRESS event.
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
#define WB_KEYEVENT_CTRL
&#39;AltCtrlShift&#39; bit flag for Control modifier for WBKeyEventProcessKey()
Atom aICON_CONTROL
Standard Dialog Control - icon container (has a nice 3D border) - see ICON_CONTROL_STR.
#define WB_LIKELY(x)
left-justified text
Definition: draw_text.h:77
Atom aTRISTATEBUTTON_CONTROL
Standard Dialog Control - tristate - like check, but with a third state - see TRISTATEBUTTON_CONTROL_...
static __inline__ void DLGNotifySelf(WBDialogControl *pDialogControl, Atom aNotify, long lData0, long lData1, long lData2, long lData3, long lData4)
Notify &#39;self&#39; by calling the window&#39;s own callback function directly with an event.
char * WBCopyString(const char *pSrc)
A simple utility that returns a WBAlloc() copy of a 0-byte terminated string.
Atom aFRAME_CONTROL
Standard Dialog Control - transparent frame with optional text - see FRAME_CONTROL_STR.
WB_GEOM geomHRight
geometry for the horizontal scroll bar &#39;right&#39; button (empty if not visible)
void *(* pfnAllocator)(const void *, int)
pointer to the copy constructor to call for each item that&#39;s added
XFontSet WBGetWindowFontSet(Window wID)
Returns the current XFontSet assigned to the window (may be None)
int WBDialogControlSetProperty(WBDialogControl *pCtrl, Atom aPropName, const char *szPropVal)
Mid-level dialog control property assignment (character string)
#define WBPointInGeom(X, Y, G)
Returns logical TRUE if the point (X,Y) is within the borders of the geometry &#39;G&#39;.
Atom aFILE_LIST_CONTROL
Standard Dialog Control - File List - see FILE_LIST_CONTROL_STR.
Pixmap WBDialogControlGetIconPixmap(WBDialogControl *pCtrl, Pixmap *pPixmap2)
Obtain the assigned ICON (image) property for a control, which consists of 2 pixmaps.
void * DLGCDefaultListInfoAllocator(const void *pData, int cbData)
The default &#39;List Info&#39; data allocator for a control&#39;s list info.
WB_GEOM geomVDown
geometry for the vertical scroll bar &#39;down&#39; button (empty if not visible)
Atom aDLGC_FONT
dialog control FONT property - reserved
Atom aPUSHBUTTON_CONTROL
Standard Dialog Control - Pushbutton control - see PUSHBUTTON_CONTROL_STR.
Atom aDLGC_LISTINFO
dialog control LISTINFO property - see DLGInitControlListInfo() etc.
void WBDialogControlsInit(void)
Initialization function for dialog controls.
void WBDialogControlSetPixmap(WBDialogControl *pCtrl, Pixmap pixmap)
Assign the PIXMAP (image) property for a control.
internal wrapper struct for X11 &#39;geometry&#39; definition
left button in &#39;drag&#39; state on horizontal scroll bar (relies on drag cancel)
always insert at beginning
const char * DLGGetControlListText(WBDialogControl *pCtrl, int iIndex)
Retrieve the text poiner for a single list entry (listbox, combo, and tree controls only) ...
void WBDialogControlSetCaption(WBDialogControl *pCtrl, const char *szCaption)
Assign text to the &#39;CAPTION&#39; property of a dialog control.
#define WB_WARN_PRINT(...)
Preferred method of implementing a &#39;warning level&#39; debug message for all subsystems.
Definition: debug_helper.h:261
void * pVal
pointer to data, as needed (may be allocated, some property types auto-free the data) ...
void * aItems[1]
The array of item data, integrated into the memory block containing this structure.
right button in &#39;drag&#39; state on vertical scroll bar
XFontSet WBGetDefaultFontSet(Display *pDisplay)
Returns an XFontSet for the default font.
void WBDialogControlSetProperty2(WBDialogControl *pCtrl, Atom aPropName, void *pPropVal)
Mid-level dialog control property list assignment (generic pointer)
Atom aTEXT_CHANGED
CONTROL_NOTIFY ClientMessage for TEXT_CHANGED event.
Pixmap pixmap
foreground pixmap
void WBDrawDashedRect(Display *pDisplay, Drawable wID, GC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw a &#39;dashed&#39; rectangle.
#define WB_KEYEVENT_KEYSYM
&#39;AltCtrlShift&#39; bit flag for &#39;VK_&#39; keys for WBKeyEventProcessKey()