2  * ComboBox.c - Das schon lange schmerzlich vermisste Combo-Box- 
   3  *              Widget -- nun endlich auf fuer Motif! 
   5  * Version 1.32a -- 04.10.95 
   8  * 04.10.1995    Layoutfehler behoben, der bei angezeigter horizontaler Liste 
   9  *               dazu fuehrt, dass das Listenfeld schrumpft. Daneben wird 
  10  *               jetzt auch der Fall beruecksichtigt, dass das Listenfeld am 
  11  *               unteren Bildschirmrand abgeschnitten wuerde. In diesem Fall 
  12  *               erscheint das Listenfeld oberhalb des Eingabefeldes. 
  13  * 20.03.1995    XmNscrollbarDisplayPolicy,... koennen nun immer vom Pro- 
  14  *               grammierer gesetzt werden, statische Liste hin und her. 
  15  * 21.10.1994    Fehler in SetValues behoben, der auftritt, wenn man versucht, 
  16  *               XmNitems und XmNitemCount zu setzen. 
  17  * 01.10.1994    Externe Sortierung wird nun unterstuetzt sowie seitenweises 
  18  *               Rollen in der Liste mittels PgUp und PgDn. 
  19  * 25.09.1994    Unterstuetzung fuer XmNautomaticSelection implementiert. 
  20  *               Damit wird die Sache noch ein bischen runder in der Bedienung. 
  21  *               Des weiteren sind etliche Callbacks neu hinzugekommen. 
  22  * 04.09.1994    Erweiterungen fuer XmSINGLE_SELECT eingebaut. Ausserdem 
  23  *               kann die Liste jetzt auch statisch unterhalb des Eingabe- 
  24  *               felds erscheinen. Damit sind wir nun noch kompatibler ge- 
  25  *               worden -- fragt sich nur, zu was?! 
  26  * 29.08.1994    Alle Mirror-Ressourcen tauchen nun auch in der Ressourcen- 
  27  *               liste der ComboBox-Klasse auf. Allerdings stehen keine 
  28  *               sinnvollen Werte fuer die Initialisierung 'drin. Weiterhin 
  29  *               den GeometryManager so veraendert, dass ab sofort das 
  30  *               Label in der Breite wachsen oder schrumpfen darf. 
  31  * 07.06.1994    XmNmnemonic und XmNmnemonicCharSet implementiert. 
  32  * 29.05.1994    XmNsensitive angepasst. XmNcursorPositionVisible ist nun 
  33  *               False, falls die ComboBox nicht editierbar ist. 
  34  * 07.05.1994    Drag'n'Drop funktioniert endlich!!! Zudem Anpassung an 
  35  *               den fvwm ausgefuehrt ('st vom Focus-Verhalten ja ein halber 
  36  *               twm). Hach', so'ne Linux-Box mit Motif 1.2 macht doch 
  37  *               einfach Spass... vor allem geht hier so richtig die Post ab. 
  38  *               Das kann man ja von M$ Windoze (Windoze for Mondays) nicht 
  40  * 14.04.1994    Ein paar Speicherlecks korrigiert. 
  41  * 21.02.1994    Die Resourcen XmNitems und XmNitemCount lassen sich nun  
  42  *               auch von einer Resourcendatei aus initialisieren. ACHTUNG:  
  43  *               diese beiden Resourcen mussen immer beide beim Aufruf von  
  44  *               XtSetValues zugleich angegeben werden, ansonsten werden 
  45  *               diese Angaben ignoriert. 
  46  * 03.02.1994    Convenience-Funktionen auf Vordermann gebracht und noch 
  47  *               einen Callback eingebaut, der immer dann aufgerufen wird,  
  48  *               wenn die List angezeigt oder wieder versteckt wird. 
  49  * 01.02.1994    Motif 1.2-fest!!! Das wird aber heute abend gefeiert!! 
  50  *               Endlich EIN Alptraum weniger! Naja, Drag'n'Drop bleibt 
  51  *               noch zu loesen. Spaeter... 
  52  * 31.01.1994    VAX-fest (mit Hilfe von Vincenct Li) 
  53  *               owlm sollte man abschaffen! Aber es scheint so, als ob 
  54  *               ich jetzt doch noch das FocusOut-Problem geknackt habe. 
  55  *               Ebenso die OSF...mit viel Arbeit habe ich nun auch noch 
  56  *               eine anstaendige Initialisierung der Fontliste des Label- 
  58  * 12.01.1994    Revisionsstand: 1.10a 
  59  *               nun wirklich voll ANSI-faehiger C-Code 
  60  *               Pixmaps werden ggf. aufgeraeumt; Druckrichtung 
  61  *               wird vom Vater erfragt und an das Label weiter- 
  63  *               ESC-Behandlung implementiert. 
  64  *               Spiegel-Ressourcen-Initialisierung aus Ressourcen-Daten- 
  66  *               Weitergabe von neu gesetzten Farben an die Kinder 
  68  *               Combo-Box kann jetzt wahlweise auch links neben dem 
  69  *               Eingabefeld ein Label anzeigen. 
  70  * 09.12.1993    Revisionsstand: 1.00 
  71  *               erste oeffentlich zugaengliche Version der Combo-Box 
  73  * (c) 1993, 1994, 1995 Harald Albrecht 
  74  * Institut fuer Geometrie und Praktische Mathematik 
  75  * RWTH Aachen, Germany 
  76  * albrecht@igpm.rwth-aachen.de 
  78  * This program is free software; you can redistribute it and/or modify 
  79  * it under the terms of the GNU General Public License as published by 
  80  * the Free Software Foundation; either version 2 of the License, or 
  81  * (at your option) any later version. 
  83  * This program is distributed in the hope that it will be useful, 
  84  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  85  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  86  * GNU General Public License for more details. 
  88  * You should have received a copy of the GNU General Public License 
  89  * along with this program (see the file COPYING for more details); 
  90  * if not, write to the Free Software Foundation, Inc., 675 Mass Ave,  
  91  * Cambridge, MA 02139, USA. 
  95 /* vms_x_fix.h should be included before any of the X11/Motif headers */ 
  96 #include <wx/vms_x_fix.h> 
 105 /* get XmVersion definition */ 
 108 #if (XmVersion < 2000) 
 110 #include <X11/IntrinsicP.h> 
 111 #include <X11/StringDefs.h> 
 112 #include <X11/cursorfont.h> 
 113 #include <X11/Shell.h> 
 114 #ifdef VMS /* Huch, wo gibt's denn noch sowas ... ?! */ 
 115            /* Bitte keine Mail bzgl. dieser Bemerkung schicken... 
 116             * Ich weiss, das ist ein Vorurteil...aber es gibt 
 117             * ja auch wahre Vorurteile.... 
 119 #include <Xmu/Converters.h> 
 121 #include <X11/Xmu/Converters.h> 
 123 #include <Xm/ArrowB.h> 
 124 #include <Xm/TextF.h> 
 126 #include <Xm/LabelP.h> 
 129 #include <ctype.h> /* define toupper */ 
 134 /* --- Systemspezifische Definitionen */ 
 136 #define strcasecmp(s1, s2) strcmp(s1, s2) 
 137 #elif defined(__EMX__) 
 138 #define strcasecmp stricmp 
 141 /* --- sonstiger Quark */ 
 144 #define LOG(p1)          fprintf(stderr, p1); 
 145 #define LOG2(p1, p2)     fprintf(stderr, p1, p2); 
 146 #define LOG3(p1, p2, p3) fprintf(stderr, p1, p2, p3); 
 150 #define LOG3(p1, p2, p3) 
 153 /* --------------------------------------------------------------------------- 
 155  * Hier werden diejenigen Resourcen definiert, die von "aussen" - also  fuer 
 156  * den Programmierer oder Anwender - benutzbar und veraenderbar sind. 
 158  * Der Aufbau der einzelnen Eintraege ist immer wieder gleich: 
 159  * Resourcen-Name       XmN... oder XtN 
 160  * Resourcen-Klasse     XmC... oder XtC 
 161  * Resourcen-Type       XmR... oder XtR (Datentyp der Variable in der 
 162  *                      struct der jeweiligen Widgetinstanz) 
 163  * Resourcen-Groesse    aktuelle Groesse dieses Datentyps 
 164  * Resourcen-Offset     Lage der Variable innerhalb der struct der 
 166  * Defaultwert-Type     Typ des Defaultwertes 
 167  * Defaultwert          (normalerweise) Zeiger auf den Defaultwert 
 169 #define offset(field) XtOffsetOf(XmComboBoxRec, field) 
 170 static XtResource resources
[] = { 
 171     { /* Eingabefeld kann veraendert werden, oder aber es sind nur 
 172        * die Vorgaben aus der Liste auswaehlbar. 
 174         XmNeditable
, XmCEditable
, XmRBoolean
, sizeof(Boolean
),  
 175         offset(combobox
.Editable
), XmRString
, "False" 
 177     { /* Liste wird automatisch sortiert -- wie konnten die bei 
 178        * der OSF denn SOETWAS nur vergessen ?? 
 180         XmNsorted
, XmCSorted
, XmRBoolean
, sizeof(Boolean
), 
 181         offset(combobox
.Sorted
), XmRString
, "False" 
 183     { /* externe Sortierreihenfolge */ 
 184         XmNsortingCallback
, XmCSortingCallback
, XmRCallback
,  
 185         sizeof(XtCallbackList
),  
 186         offset(combobox
.SortingCBL
), XmRCallback
, NULL
 
 188     { /* Anzahl auf einmal sichtbarer Eintraege in der Liste (ent- 
 189        * spricht damit der Listenhoehe. 
 191         XmNvisibleItemCount
, XmCVisibleItemCount
, XmRInt
, sizeof(int),  
 192         offset(combobox
.VisibleItemCount
), XmRImmediate
, (caddr_t
) 8 
 194     { /* Fuer das Eingabefeld sowie die Liste verwandte Fonts */ 
 195         XmNfontList
, XmCFontList
, XmRFontList
, sizeof(XmFontList
),  
 196         offset(combobox
.Font
), XmRImmediate
, NULL
 
 198     { /* Rueckruf bei Anwahl */ 
 199         XmNselectionCallback
, XmCSelectionCallback
, XmRCallback
,  
 200         sizeof(XtCallbackList
),  
 201         offset(combobox
.SelectionCBL
), XmRCallback
, NULL
 
 203     { /* Gegenteil zum vorherigen Callback! */ 
 204         XmNunselectionCallback
, XmCUnselectionCallback
, XmRCallback
,  
 205         sizeof(XtCallbackList
),  
 206         offset(combobox
.UnselectionCBL
), XmRCallback
, NULL
 
 208     { /* Doppelklick in der Liste */ 
 209         XmNdefaultActionCallback
, XmCCallback
, XmRCallback
,  
 210         sizeof(XtCallbackList
),  
 211         offset(combobox
.DefaultActionCBL
), XmRCallback
, NULL
 
 213     { /* Rueckruf bei Liste ausklappen/verstecken */ 
 214         XmNdropDownCallback
, XmCDropDownCallback
, XmRCallback
,  
 215         sizeof(XtCallbackList
),  
 216         offset(combobox
.DropDownCBL
), XmRCallback
, NULL
 
 218     { /* Eingabe abchecken... */ 
 219         XmNmodifyVerifyCallback
, XmCCallback
, XmRCallback
,  
 220         sizeof(XtCallbackList
),  
 221         offset(combobox
.ModifyVerifyCBL
), XmRCallback
, NULL
 
 224         XmNvalueChangedCallback
, XmCCallback
, XmRCallback
,  
 225         sizeof(XtCallbackList
),  
 226         offset(combobox
.ValueChangedCBL
), XmRCallback
, NULL
 
 229         XmNactivateCallback
, XmCCallback
, XmRCallback
,  
 230         sizeof(XtCallbackList
),  
 231         offset(combobox
.ActivateCBL
), XmRCallback
, NULL
 
 234         XmNmotionVerifyCallback
, XmCCallback
, XmRCallback
,  
 235         sizeof(XtCallbackList
),  
 236         offset(combobox
.MotionVerifyCBL
), XmRCallback
, NULL
 
 238     { /* Verhalten der ausgeklappten Liste bei Focus-Out */ 
 239         XmNpersistentDropDown
, XmCPersistentDropDown
, XmRBoolean
,  
 241         offset(combobox
.Persistent
), XmRString
, "False" 
 243     { /* Wie verhaelt sich der Window-Manager? */ 
 244         XmNtwmHandlingOn
, XmCTwmHandlingOn
, XmRBoolean
, sizeof(Boolean
),  
 245         offset(combobox
.TwmHandlingOn
), XmRString
, "False" 
 247     { /* Label anzeigen oder nicht? */ 
 248         XmNshowLabel
, XmCShowLabel
, XmRBoolean
, sizeof(Boolean
),  
 249         offset(combobox
.ShowLabel
), XmRString
, "False" 
 251     { /* Abstand zw. linkem Rand Eingabefeld und linkem Rand Liste */ 
 252         XmNdropDownOffset
, XmCDropDownOffset
, XmRPosition
,  
 253         sizeof(Position
), offset(combobox
.DropDownOffset
),  
 254         XmRImmediate
, (caddr_t
) -1 
 256     { /* Neue Voreinstellung bzgl. des Randes */ 
 257         XmNborderWidth
, XmCBorderWidth
, XmRDimension
, sizeof(Dimension
),  
 258         offset(core
.border_width
), XmRImmediate
, (caddr_t
) 0 
 260     { /* welcher Cursor soll in der Dropdown-Liste benutzt werden? */ 
 261         XmNdropDownCursor
, XmCDropDownCursor
, XmRCursor
, sizeof(Cursor
), 
 262         offset(combobox
.ArrowCursor
), XmRString
, "center_ptr" 
 264     { /* wie lassen sich Eintraege auswaehlen? */ 
 265         XmNselectionPolicy
, XmCSelectionPolicy
, XmRSelectionPolicy
, sizeof(unsigned char),  
 266         offset(combobox
.SelectionPolicy
), XmRImmediate
, (caddr_t
) XmBROWSE_SELECT
 
 268     { /* Wann werden die Callbacks aufgerufen? */ 
 269         XmNautomaticSelection
, XmCAutomaticSelection
, XmRBoolean
, sizeof(Boolean
),  
 270         offset(combobox
.AutomaticSelection
), XmRString
, "False" 
 272     { /* erscheint die Liste staendig? */ 
 273         XmNstaticList
, XmCStaticList
, XmRBoolean
, sizeof(Boolean
),  
 274         offset(combobox
.StaticList
), XmRString
, "False" 
 277         XmNscrollBarDisplayPolicy
, XmCScrollBarDisplayPolicy
, XmRScrollBarDisplayPolicy
, sizeof(unsigned char), 
 278         offset(combobox
.ScrollBarDisplayPolicy
), XmRImmediate
, (caddr_t
) XmAS_NEEDED
 
 281         XmNlistSizePolicy
, XmCListSizePolicy
, XmRListSizePolicy
, sizeof(unsigned char), 
 282         offset(combobox
.ListSizePolicy
), XmRImmediate
, (caddr_t
) XmVARIABLE
 
 285         XmNsquareArrow
, XmCSquareArrow
, XmRBoolean
, sizeof(Boolean
), 
 286         offset(combobox
.SquareArrow
), XmRString
, "False" 
 289         XmNarrowSpacingOn
, XmCArrowSpacingOn
, XmRBoolean
, sizeof(Boolean
), 
 290         offset(combobox
.ArrowSpacingOn
), XmRString
, "True" 
 292 #ifndef DONT_LOOK_IN_THE_MIRROR 
 293     /* Mirror-Ressourcen, Adressen sind ungueltig!!!! */ 
 295         XmNalignment
, XmCAlignment
, XmRAlignment
, sizeof(unsigned char),  
 296         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 299         XmNblinkRate
, XmCBlinkRate
, XmRInt
, sizeof(int),  
 300         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 303         XmNcolumns
, XmCColumns
, XmRShort
, sizeof(short),  
 304         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 307         XmNcursorPosition
, XmCCursorPosition
, XmRTextPosition
, sizeof(XmTextPosition
), 
 308         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 311         XmNitemCount
, XmCItemCount
, XmRInt
, sizeof(int),  
 312         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 315         XmNitems
, XmCItems
, XmRXmStringTable
, sizeof(XmStringTable
),  
 316         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 319         XmNlabelFontList
, XmCLabelFontList
, XmRFontList
, sizeof(XmFontList
),  
 320         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 323         XmNlabelInsensitivePixmap
, XmCLabelInsensitivePixmap
, XmRPixmap
, sizeof(Pixmap
),  
 324         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 327         XmNlabelMarginBottom
, XmCLabelMarginBottom
, XmRDimension
, sizeof(Dimension
),  
 328         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 331         XmNlabelMarginHeight
, XmCLabelMarginHeight
, XmRDimension
, sizeof(Dimension
),  
 332         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 335         XmNlabelMarginLeft
, XmCLabelMarginLeft
, XmRDimension
, sizeof(Dimension
),  
 336         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 339         XmNlabelMarginRight
, XmCLabelMarginRight
, XmRDimension
, sizeof(Dimension
),  
 340         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 343         XmNlabelMarginTop
, XmCLabelMarginTop
, XmRDimension
, sizeof(Dimension
),  
 344         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 347         XmNlabelMarginWidth
, XmCLabelMarginWidth
, XmRDimension
, sizeof(Dimension
),  
 348         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 351         XmNlabelPixmap
, XmCLabelPixmap
, XmRPixmap
, sizeof(Pixmap
),  
 352         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 355         XmNlabelString
, XmCLabelString
, XmRString
, sizeof(XmString
),  
 356         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 359         XmNlabelType
, XmCLabelType
, XmRLabelType
, sizeof(unsigned char),  
 360         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 363         XmNlistMarginHeight
, XmCListMarginHeight
, XmRDimension
, sizeof(Dimension
),  
 364         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 367         XmNlistMarginWidth
, XmCListMarginWidth
, XmRDimension
, sizeof(Dimension
),  
 368         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 371         XmNlistSpacing
, XmCListSpacing
, XmRDimension
, sizeof(Dimension
),  
 372         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 375         XmNmarginHeight
, XmCMarginHeight
, XmRDimension
, sizeof(Dimension
),  
 376         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 379         XmNmarginWidth
, XmCMarginWidth
, XmRDimension
, sizeof(Dimension
),  
 380         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 383         XmNmaxLength
, XmCMaxLength
, XmRInt
, sizeof(int),  
 384         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 387         XmNselectThreshold
, XmCSelectThreshold
, XmRInt
, sizeof(int),  
 388         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 391         XmNstringDirection
, XmCStringDirection
, XmRStringDirection
, sizeof(XmStringDirection
),  
 392         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 395         XmNtopItemPosition
, XmCTopItemPosition
, XmRInt
, sizeof(int),  
 396         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 399         XmNvalue
, XmCValue
, XmRString
, sizeof(String
),  
 400         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 403         XmNvalue
, XmCValue
, XmRInt
, sizeof(int),  
 404         offset(combobox
.Dummy
), XmRImmediate
, (caddr_t
) 0 
 409 /* --------------------------------------------------------------------------- 
 410  * Funktions-Prototypen fuer die 'Methoden' des ComboBox-Widgets. Diese 
 411  * 'Methoden' werden vom Xt-Toolkit aufgerufen und sorgen dafuer, dass eine 
 412  * ComboBox sich wie ein anstaendiges Widget verhaelt. 
 414 static void             Initialize     (Widget
, XmComboBoxWidget
, ArgList
,  
 416 static void             Destroy        (XmComboBoxWidget
); 
 417 static void             Resize         (XmComboBoxWidget
); 
 418 static Boolean          
SetValues      (XmComboBoxWidget
, XmComboBoxWidget
,  
 419                                         XmComboBoxWidget
, ArgList
, Cardinal 
*); 
 420 static void             GetValuesAlmost(XmComboBoxWidget
, ArgList
, Cardinal 
*); 
 421 static XtGeometryResult 
QueryGeometry  (XmComboBoxWidget
, XtWidgetGeometry 
*,  
 423 static XtGeometryResult 
GeometryManager(Widget
, XtWidgetGeometry 
*,  
 425 static void             ClassInit      (); 
 426 static void             Realize        (XmComboBoxWidget
, Mask 
*,  
 427                                         XSetWindowAttributes 
*); 
 428 /* --------------------------------------------------------------------------- 
 429  * diverse restliche Prototypen... naja, hier halt etwas mager! Hierbei 
 431 static void ShowHideDropDownList       (XmComboBoxWidget w
, XEvent 
*event
,  
 433 static void ShellCallback              (Widget w
, XtPointer cbw
,  
 434                                         XEvent 
*event
, Boolean 
*ContDispatch
); 
 435 static void DoLayout                   (XmComboBoxWidget w
); 
 436 /* -------------------------------------------------------------------- 
 439 XmComboBoxClassRec xmComboBoxClassRec 
= { 
 440     { /*** core-Klasse ***/ 
 441     /* superclass                   */  (WidgetClass
) &xmManagerClassRec
,  
 442     /* class_name                   */  "XmComboBox", 
 443     /* widget_size                  */  sizeof(XmComboBoxRec
), 
 444     /* class_initialize             */  (XtProc
) ClassInit
, 
 445     /* class_part_initialize        */  NULL
, 
 446     /* class_inited                 */  False
, /* IMMER mit FALSE initialisieren !! */ 
 447     /* initialize                   */  (XtInitProc
) Initialize
, 
 448     /* initialize_hook              */  NULL
, 
 449     /* realize                      */  (XtRealizeProc
) Realize
, 
 452     /* resources                    */  resources
, 
 453     /* num_resources                */  XtNumber(resources
), 
 454     /* xrm_class                    */  NULLQUARK
, 
 455     /* compress_motion              */  True
, 
 456     /* compress_exposure            */  XtExposeCompressMultiple
, 
 457     /* compress_enterleave          */  True
, 
 458     /* visible_interest             */  False
, 
 459     /* destroy                      */  (XtWidgetProc
) Destroy
, 
 460     /* resize                       */  (XtWidgetProc
) Resize
, 
 462     /* set_values                   */  (XtSetValuesFunc
) SetValues
, 
 463     /* set_values_hook              */  NULL
, 
 464     /* set_values_almost            */  XtInheritSetValuesAlmost
, 
 465     /* get_values_hook              */  (XtArgsProc
) GetValuesAlmost
, 
 466     /* accept_focus                 */  NULL
, 
 467     /* version                      */  XtVersion
, 
 468     /* callback_private             */  NULL
, 
 469     /* tm_table                     */  XtInheritTranslations
, /* Changed from NULL: Bug #406153 */ 
 470     /* query_geometry               */  (XtGeometryHandler
) QueryGeometry
, 
 471     /* display_accelerator          */  XtInheritDisplayAccelerator
, 
 474     { /*** composite-Klasse ***/ 
 475     /* geometry_manager             */  (XtGeometryHandler
) GeometryManager
, 
 476     /* change_managed               */  XtInheritChangeManaged
, 
 477     /* insert_child                 */  XtInheritInsertChild
, 
 478     /* delete_child                 */  XtInheritDeleteChild
, 
 481     { /*** constraint-Klasse ***/ 
 482     /* resources                    */  NULL
, 
 483     /* num_resources                */  0, 
 484     /* constraint_size              */  sizeof(XmManagerConstraintPart
), 
 485     /* initialize                   */  NULL
, 
 487     /* set_values                   */  NULL
, 
 490     { /*** xmManager-Klasse ***/ 
 491     /* translations                 */  XtInheritTranslations
, 
 492     /* syn_resources                */  NULL
, 
 493     /* num_syn_resources            */  0, 
 494     /* syn_constraint_resources     */  NULL
, 
 495     /* num_syn_constraint_resources */  0, 
 496     /* parent_process               */  XmInheritParentProcess
, 
 499     { /*** combobox-Klasse ***/ 
 502 }; /* xmComboBoxClassRec */ 
 503 WidgetClass xmComboBoxWidgetClass 
= (WidgetClass
) &xmComboBoxClassRec
; 
 505 /* -------------------------------------------------------------------- 
 506  * -------------------------------------------------------------------- 
 507  * Translation-Tabelle (hier allerdings fuer das Eingabefeld!) 
 508  * Tjaja....mit der Reihenfolge von Translations ist das schon so eine 
 509  * ziemlich boese Sache! 
 511 static char newEditTranslations
[] = 
 512     "Alt<Key>osfDown:       ComboBox-Manager(show-hide-list)    \n\ 
 513      Meta<Key>osfDown:      ComboBox-Manager(show-hide-list)    \n\ 
 514      Alt<Key>osfUp:         ComboBox-Manager(hide-list)         \n\ 
 515      Meta<Key>osfUp:        ComboBox-Manager(hide-list)         \n\ 
 516      <Key>osfUp:            ComboBox-Manager(up)                \n\ 
 517      <Key>osfDown:          ComboBox-Manager(down)              \n\ 
 518      <Key>osfPageUp:        ComboBox-Manager(page-up)           \n\ 
 519      <Key>osfPageDown:      ComboBox-Manager(page-down)         \n\ 
 520      <Key>osfCancel:        ComboBox-Manager(cancel)            \n\ 
 521      <Key>Return:           ComboBox-Manager(activate) activate()" 
 523 /* speziell bei der nicht editierbaren Combo-Box sind noch einige 
 524  * andere Tasten belegt, die sonst dem Eingabefeld alleine gehoeren. 
 525  * Die dazugehoerigen neuen Translations befinden sich in dieser 
 526  * zusaetzlichen Tabelle, das Anhaengsel ...NE ist dabei die Ab- 
 527  * kuerzung fuer "non editable". 
 529 static char newEditTranslationsNE
[] =  
 530     "<Key>osfDelete:        ComboBox-Manager(wipe-out)          \n\ 
 531      <Key>osfBeginLine:     ComboBox-Manager(top)               \n\ 
 532      <Key>osfEndLine:       ComboBox-Manager(bottom)              " 
 534 /* Momentan gibt es noch Aerger mit dem Drag'n'Drop-Mechanismus 
 535  * von Motif 1.2. Legen wir ihn deshalb erst einmal still, solange 
 536  * bis ich weiss, warum, und eine Loesung parat habe. NEU: Nur wenn 
 537  * Sie mit einer libXm geschlagen sind, die partout nicht funktionieren 
 538  * will, muessen Sie Drag'n'Drop stillegen, ansonsten klappts doch! 
 541 static char newListTranslations
[] = 
 542     "<Btn2Down>:            ComboBox-Manager(no-operation)      "; 
 544 static char newListTranslationsE
[] = 
 545     "<Key>osfPageUp:        ComboBox-Manager(page-up)           \n\ 
 546      <Key>osfPageDown:      ComboBox-Manager(page-down)         "; 
 548 /* --------------------------------------------------------------------------- 
 549  * --------------------------------------------------------------------------- 
 550  * Aktionen-Tabelle: Hierdurch werden den einzelnen Translations die dazuge- 
 551  * hoerigen C-Routinen zugeordnet. Da wir hier ein anstaendiges ANSI-C be- 
 552  * nutzen, werden hier zuerst einmal die Prototypen faellig... Ach ja, noch 
 553  * ein Hinweis in eigener Sache... der ComboBox-Manager muss applikationsweit 
 554  * registriert werden, da er auch von Translationen in den Kindern der Combo- 
 555  * Box aktiviert wird. Bei diesem Namen der 'Aktion' steht aber nicht zu be- 
 556  * fuerchten, dass er anderweitig bereits in Anwendung ist. 
 558 static void CBoxManager(Widget w
, XEvent 
*event
, String 
*params
,  
 559                         Cardinal 
*num_params
); 
 561 static XtActionsRec actions
[] = { 
 562     { "ComboBox-Manager", CBoxManager 
}, 
 567 /* -------------------------------------------------------------------- 
 568  * Eine Instanz dieser Widget-Klasse wird erstmalig in Betrieb ge- 
 569  * nommen, daher sind noch Vorbereitungen notwendig, die nun hier 
 570  * durchgefuehrt werden. 
 572 static XtTranslations NewEditTranslations
, NewEditTranslationsNE
,  
 576                       NewListTranslationsE
; 
 578 static XtConvertArgRec ConverterScreenConvertArg
[] = { 
 579     { XtBaseOffset
, (XtPointer
) XtOffset(Widget
, core
.screen
),  
 583 static void ClassInit() 
 585     NewEditTranslations 
= 
 586             XtParseTranslationTable(newEditTranslations
); 
 587     NewEditTranslationsNE 
= 
 588             XtParseTranslationTable(newEditTranslationsNE
); 
 590     NewListTranslations 
= 
 591             XtParseTranslationTable(newListTranslations
); 
 593     NewListTranslationsE 
= 
 594             XtParseTranslationTable(newListTranslationsE
); 
 595     XtAddConverter(XtRString
, XtRBitmap
,  
 596                    XmuCvtStringToBitmap
,  
 597                    ConverterScreenConvertArg
,  
 598                    XtNumber(ConverterScreenConvertArg
)); 
 601 /* --------------------------------------------------------------------------- 
 602  * Weil es sich bei diesem Widget um ein etwas komplizierteres zusammengesetz- 
 603  * tes Widget handelt, muessen wir hier - wo eigentlich nur das die Combobox 
 604  * bildende Fenster auf dem X-Server erzeugt wird - noch einmal das Layout 
 605  * auf Vordermann bringen. Den Aerger loest dabei das Listenfeld der OSF aus, 
 606  * das einfach keine Geometrie-Nachfragen verschickt, solange es nicht  
 607  * 'realized' ist!!! Nicht, dass ich mich ueber so einen Sauhaufen aufregen  
 608  * wuerde...ich doch nicht! ABER MACHT IHR DENN NUR SO'N MIST...? WARUM KOENNT 
 609  * IHR DENN NICHT EINMAL DIESES ****(BIEP)**** MOTIF TOOLKIT ANSTAENDIG 
 610  * DOKUMENTIEREN! Ich glaub', ich kann mich nach dem Chaos eigentlich nur noch 
 611  * hemmungslos besaufen... Die Suche nach der Ursache (bzw. Urheber = OSF) hat 
 612  * mich doch einige Tage gekostet (jaja...die Mannstunden!). 
 614 static void Realize(XmComboBoxWidget w
, Mask 
*ValueMask
,  
 615                     XSetWindowAttributes 
*Attributes
) 
 618      * Also: wenn die Liste staendig sichtbar ist, dann zuerst noch einmal 
 619      * das Layout berechnen. Sonst wird vorne und hinten 'was abgeschnitten. 
 621     if ( w
->combobox
.StaticList 
) 
 623     (*w
->core
.widget_class
->core_class
.superclass
->core_class
.realize
) 
 624         ((Widget
) w
, ValueMask
, Attributes
); 
 627 /* --------------------------------------------------------------------------- 
 628  * Suche dasjenige Fenster, in dem unsere Shell liegt, in der wiederum die  
 629  * Combo-Box steckt. Diese Information wird benoetigt, um die Drop-Down-Liste 
 630  * innerhalb des Fensterstacks immer direkt oberhalb der Shell mit der Combo- 
 631  * Box zu halten. Jajaja -- ich muss halt davon ausgehen, dass der Fenster- 
 632  * manager ein sog. "reparenting wm" ist; also die Dekorationen in einem 
 633  * Fenster dargestellt werden und unsere Shell in dieses Fenster hineingepackt 
 634  * ist. Die Dekoration ist damit ein Kind des 'root window' - wie die Shell, 
 635  * in der die Drop-Down-Liste steckt. Und da nur Geschwisterfenster (sibling 
 636  * windows) im gleichen Stapel stecken, reicht das Shellfenster nicht aus. 
 637  * Alle gaengigen Fenstermanager sind solche "reparenting wm's", so dass ich 
 638  * hier zu diesem Trick greifen kann, um die Drop-Down-Liste immer ueber der 
 639  * ComboBox zu halten. 
 642  *   w                  Diejenige Combo-Box, fuer die wir dasjenige 
 643  *                      Fenster des Window-Managers ermitteln sollen, 
 644  *                      dass direkt unterhalb des Root-Fensters liegt. 
 646  *   besagtes zu suchendes Fenster, dass die Dekoration enthaelt (hoffentlich 
 647  *   nur echte Bruesseler Spitze!) 
 649 static Window 
GetDecorationWindow(XmComboBoxWidget w
) 
 651     Window       Root
, Parent
, AWindow
; 
 653     unsigned int NumChildren
; 
 655     Parent 
= XtWindow((Widget
) w
); 
 656     /* Suche nach dem Dekorationsfenster des Window-Managers */ 
 659         XQueryTree(XtDisplay((Widget
) w
), AWindow
,  
 660                    &Root
, &Parent
, &Children
, &NumChildren
); 
 661         XFree((char *) Children
); 
 662     } while ( Parent 
!= Root 
); 
 664 } /* GetDecorationWindow */ 
 666 /* -------------------------------------------------------------------- 
 667  * Eine Combo-Box aus dem Wege raeumen... 
 668  * Momentan muessen wir hier nur den Cursor wieder los werden sowie 
 669  * eventuell reservierte Pixmaps. 
 670  * Ups -- natuerlich muss auch wieder der Callback entfernt werden,  
 671  * der noch an der Shell haengt. 
 673 static void Destroy(XmComboBoxWidget w
) 
 675 /*    fprintf(stderr, "Destroy: %08X\n", w->core.window);*/ 
 676     if ( w
->combobox
.ConvertBitmapToPixmap 
) 
 677         XFreePixmap(XtDisplay((Widget
) w
),  
 678                     w
->combobox
.LabelPixmap
); 
 679     if ( w
->combobox
.ConvertBitmapToPixmapInsensitive 
) 
 680         XFreePixmap(XtDisplay((Widget
) w
),  
 681                     w
->combobox
.LabelInsensitivePixmap
); 
 682     if ( w
->combobox
.PendingFocusOut 
) 
 683         XtRemoveWorkProc(w
->combobox
.WorkProcID
); 
 684     XtRemoveEventHandler(w
->combobox
.MyNextShell
,  
 685                       StructureNotifyMask 
| FocusChangeMask
,  
 686                       True
, (XtEventHandler
) ShellCallback
,  
 690 /* --------------------------------------------------------------------------- 
 691  * Ueberpruefe, ob fuer die Ressource "DropDownOffset" ein gueltiger Wert vom 
 692  * Benutzer angegeben wurde. Diese Ressource gibt an, wie weit die Drop-Down- 
 693  * Liste nach rechts gegenueber dem Eingabefeld eingerueckt sein soll. Wenn 
 694  * hierfuer ein negativer Wert angegeben ist, so berechne statt dessen einen 
 695  * Standardwert: dieser entspricht der Breite der Pfeilschaltflaeche, was  
 696  * optisch ganz gut wirkt (jedenfall nach meinem Dafuerhalten). 
 698 static void CheckDropDownOffset(XmComboBoxWidget w
) 
 700     if ( w
->combobox
.DropDownOffset 
< 0 ) { 
 701         XtWidgetGeometry ArrowGeom
; 
 703         XtQueryGeometry(w
->combobox
.ArrowCtrl
, NULL
, &ArrowGeom
); 
 704         w
->combobox
.DropDownOffset 
= ArrowGeom
.width
; 
 706 } /* CheckDropDownOffset */ 
 708 /* -------------------------------------------------------------------- 
 709  * Berechne die voreinzustellende Groesse, die diese Combo-Box be- 
 710  * sitzen muss, um ausreichenden Raum fuer das Eingabefeld und den 
 711  * Pfeil rechts daneben zur Verfuegung zu stellen. Bei einer 
 712  * editierbaren Combo-Box ist zwischen dem Eingabefeld und dem Pfeil 
 713  * noch ein Angst-Rasen von der halben Breite eines Pfeiles vorhanden. 
 714  * Wird das Listenfeld staendig dargestellt, so entfallen sowohl Pfeil 
 715  * als auch der Angstrasen, dafuer muss aber die Hoehe des Listenfelds 
 716  * beruecksichtigt werden. 
 718 static void DefaultGeometry(XmComboBoxWidget w
,  
 719                             Dimension 
*TotalWidth
,  
 720                             Dimension 
*TotalHeight
,  
 721                             Dimension 
*EditCtrlWidth
,  
 722                             Dimension 
*LabelCtrlWidth
) 
 724     XtWidgetGeometry EditGeom
, ArrowGeom
, LabelGeom
, ListGeom
; 
 726     XtQueryGeometry(w
->combobox
.EditCtrl
,  NULL
, &EditGeom
); 
 727     XtQueryGeometry(w
->combobox
.ArrowCtrl
, NULL
, &ArrowGeom
); 
 728     XtQueryGeometry(w
->combobox
.LabelCtrl
, NULL
, &LabelGeom
); 
 731      * Soll die Pfeilschaltflaeche quadratisch, praktisch, gut sein? 
 733     if ( w
->combobox
.SquareArrow 
) 
 734         ArrowGeom
.width 
= ArrowGeom
.height
; 
 736         ArrowGeom
.width 
= (ArrowGeom
.height 
* 4) / 5; 
 739      * Zuerst einmal ein paar einfache Werte ermitteln und zurueckgeben... 
 741     *TotalHeight    
= EditGeom
.height
; 
 742     *EditCtrlWidth  
= EditGeom
.width
; 
 743     *LabelCtrlWidth 
= LabelGeom
.width
; 
 746      * Ermittele nun die Breite, welche die Combobox benoetigt. Je nach- 
 747      * dem, ob das Eingabefeld oder die Liste breiter sind, wird der 
 748      * entsprechende Wert genommen. Diese Auswahl zwischen der Breite von 
 749      * Eingabefeld und Liste findet aber nur statt, wenn die Liste auch 
 750      * wirklich staendig sichtbar ist. Waehrend der Initialisierung hat 
 751      * allerdings XmNcolumns, so dass in diesem Moment die List nicht 
 752      * mehr die Breite kontrollieren kann! 
 754     if ( w
->combobox
.StaticList 
) { 
 756          * Beachte: Frage nicht die Listbox, sondern das ScrolledWindow,  
 757          * in welchem die Liste eingebettet ist. 
 759         CheckDropDownOffset(w
); 
 760         XtQueryGeometry(XtParent(w
->combobox
.ListCtrl
), NULL
, &ListGeom
); 
 761         if ( w
->combobox
.InInit 
) { 
 762             *TotalWidth 
= EditGeom
.width
; 
 764             if ( EditGeom
.width 
< (Dimension
) 
 765                                    (ListGeom
.width 
+ w
->combobox
.DropDownOffset
) ) 
 766                 *TotalWidth 
= ListGeom
.width 
+ w
->combobox
.DropDownOffset
; 
 768                 *TotalWidth 
= EditGeom
.width
; 
 770         *TotalHeight 
+= ListGeom
.height
; 
 773          * Das Listenfeld interessiert uns hier nicht. Degegen sollte noch 
 774          * die Breite fuer den Pfeil und ein evtl. Angstrasen beachtet 
 777         *TotalWidth  
= EditGeom
.width 
+ ArrowGeom
.width
; 
 778         if ( w
->combobox
.Editable 
&& w
->combobox
.ArrowSpacingOn 
) 
 779             *TotalWidth 
+= ArrowGeom
.width
/2; 
 783      * Vergiss nicht, auch noch ein evtl. sichtbares Schriftfeld zu berueck- 
 786     if ( w
->combobox
.ShowLabel 
) 
 787         *TotalWidth 
+= LabelGeom
.width
; 
 789 } /* DefaultGeometry */ 
 791 /* -------------------------------------------------------------------- 
 792  * Anhand eines Widgets ermittele darueber die Screennummer desjenigen 
 793  * Screens, auf dem das Widget erscheint. 
 795  *   w                  betroffenes Widget. 
 797  *   Nummer desjenigen Screens, auf dem das Widget angezeigt wird. 
 799 static int WidgetToScreen(Widget w
) 
 805     screen 
= XtScreen(w
); NumScreens 
= ScreenCount(XtDisplay(w
)); 
 806     display 
= DisplayOfScreen(screen
); 
 807     for ( i 
= 0; i 
< NumScreens
; ++i 
) 
 808         if ( ScreenOfDisplay(display
, i
) == screen 
) 
 810     XtError("WidgetToScreen: data structures are destroyed."); 
 811     return 0; /* to avoid a compiler warning */ 
 812 } /* WidgetToScreen */ 
 814 /* -------------------------------------------------------------------- 
 815  * Positioniere die DropDown-Liste (soweit sie natuerlich auch momentan 
 816  * sichtbar ist) so auf dem Bildschirm, dass sie sich unterhalb des 
 817  * Eingabefeldes anschliesst. 
 819 static void DoDropDownLayout(XmComboBoxWidget w
) 
 821     Position       abs_x
, abs_y
; 
 822     Dimension      ArrowWidth
, ListWidth
, ListHeight
; 
 823     Dimension      ScreenHeight
, LabelWidth
; 
 824     XWindowChanges WindowChanges
; 
 827      * etwa nicht sichtbar ?!! Oder etwa immer sichtbar ?!! 
 828      * Dann sind wir jetzt sofort fertig.  
 830     if ( !w
->combobox
.ListVisible 
|| w
->combobox
.StaticList 
) return; 
 832      * Finde zuerst einmal heraus, wo wir uns denn auf dem Bildschirm be- 
 833      * finden sollen... Beachte dabei auch, dass eventuell die Liste zu schmal 
 834      * werden koennte und gib' ihr dann ggf. eine Mindestbreite, damit es 
 835      * keinen core-Dump gibt. 
 837     XtVaGetValues(w
->combobox
.ArrowCtrl
, XmNwidth
,  &ArrowWidth
, NULL
); 
 838     XtTranslateCoords((Widget
) w
, 0, w
->core
.height
, &abs_x
, &abs_y
); 
 839     CheckDropDownOffset(w
); 
 840     ListWidth  
= w
->core
.width 
- w
->combobox
.DropDownOffset 
- 2; 
 841     abs_x     
+= w
->combobox
.DropDownOffset
; 
 842     if ( w
->combobox
.ShowLabel 
) { 
 843         XtVaGetValues(w
->combobox
.LabelCtrl
, XmNwidth
, &LabelWidth
, NULL
); 
 844         ListWidth 
-= LabelWidth
; 
 847     if ( ListWidth 
< 20 ) ListWidth 
= 20; 
 848     XtVaGetValues(XtParent(w
->combobox
.ListCtrl
), XmNheight
, &ListHeight
, NULL
); 
 850      * Hier ueberpruefen wir noch, ob die Liste unten aus dem Bildschirm  
 851      * herausfallen wuerde. In dem Fall klappen wir die Liste oberhalb des 
 854     ScreenHeight 
= DisplayHeight(XtDisplay((Widget
) w
),  
 855                                  WidgetToScreen((Widget
) w
)); 
 856     if ( abs_y 
+ ListHeight 
+ 2 > ScreenHeight 
) { 
 859         y 
= ((int) abs_y
) - ListHeight 
- w
->core
.height 
- 1; 
 861         abs_y 
= (Position
) y
; 
 863     XtConfigureWidget(w
->combobox
.PopupShell
,  
 864                       abs_x
, abs_y
, ListWidth
, ListHeight
, 1); 
 866      * So...das hier dient der Kosmetik: hier sorgen wir dafuer, dass die 
 867      * Liste auch wirklich immer direkt ueber der ComboBox innerhalb des 
 868      * Fensterstapels schwebt. Siehe dazu auch die Erlaeuterungen und An- 
 869      * merkungen in GetDecorationWindow(). 
 871     if ( XtIsRealized((Widget
) w
) ) { 
 872         WindowChanges
.sibling    
= GetDecorationWindow(w
); 
 873         WindowChanges
.stack_mode 
= Above
; 
 874         XReconfigureWMWindow(XtDisplay((Widget
) w
),  
 875             XtWindow(w
->combobox
.PopupShell
),  
 876             WidgetToScreen(w
->combobox
.PopupShell
),  
 877             CWSibling 
| CWStackMode
, &WindowChanges
); 
 879 } /* DoDropDownLayout */ 
 881 /* -------------------------------------------------------------------- 
 882  * Naja... diese Routine scheint ja bereits zu einer Institution beim 
 883  * Schreiben von Composite-Widgets geworden zu sein. 
 885  * Hier beim ComboBox-Widget ist die Aufgabe ziemlich einfach: es 
 886  * genuegt, die Eingabezeile und den Pfeil-Button entsprechend inner- 
 887  * halb des ComboBox-Widgets zu plazieren. Seit allerdings noch das 
 888  * Textlabel hinzukommt, wird's langsam aufwendiger. Nun ja - da sich 
 889  * das Listenfeld wahlweise auch statisch einblenden laesst, ist nun 
 890  * noch mehr zu beruecksichtigen, wenn die Kinder-Widgets an ihre 
 891  * Plaetze geschoben werden. 
 893 static void DoLayout(XmComboBoxWidget w
) 
 895     Dimension        EditCtrlWidth
, ArrowCtrlWidth
, LabelCtrlWidth
; 
 896     Dimension        ComboBoxHeight
; 
 897     Dimension        BorderWidth
; 
 898     Dimension        HighlightThickness
; 
 901     XtVaGetValues(w
->combobox
.ArrowCtrl
, 
 902                   XmNheight
, &ArrowCtrlWidth
, NULL
); 
 903     if ( !w
->combobox
.SquareArrow 
) 
 904         ArrowCtrlWidth 
= (ArrowCtrlWidth 
* 4) / 5; 
 905     XtVaGetValues(w
->combobox
.LabelCtrl
,  
 906                   XmNwidth
, &LabelCtrlWidth
, NULL
); 
 909      * In Abhaengigkeit davon, ob die ComboBox editierbar ist und ob das 
 910      * Listenfeld staendig sichtbar sein soll, hier die Breite einzelner 
 913     if ( w
->combobox
.StaticList 
) { 
 914         ComboBoxHeight 
= w
->combobox
.EditCtrl
->core
.height
; 
 915         EditCtrlWidth  
= w
->core
.width
; 
 917         ComboBoxHeight 
= w
->core
.height
; 
 918         EditCtrlWidth  
= w
->core
.width 
- ArrowCtrlWidth
; 
 919         if ( w
->combobox
.Editable 
&& w
->combobox
.ArrowSpacingOn 
) 
 920             EditCtrlWidth 
-= ArrowCtrlWidth
/2; 
 922     /* Beruecksichtige noch ein evtl. ebenfalls anzuzeigendes Schriftfeld 
 923      * neben dem Eingabefeld. 
 925     if ( w
->combobox
.ShowLabel 
) { 
 926         EditX          
= LabelCtrlWidth
; 
 927         EditCtrlWidth 
-= LabelCtrlWidth
; 
 930     if ( EditCtrlWidth 
< 20 ) EditCtrlWidth 
= 20; 
 931 /* Plaziere nun das Eingabefeld... */ 
 932     XtVaGetValues(w
->combobox
.EditCtrl
,  
 933                   XmNborderWidth
,        &BorderWidth
,  
 934                   XmNhighlightThickness
, &HighlightThickness
,  
 936     XtConfigureWidget(w
->combobox
.EditCtrl
,  
 938                       EditCtrlWidth
, ComboBoxHeight
, BorderWidth
); 
 939 /* ...und nun den Pfeil... */ 
 940     XtVaGetValues(w
->combobox
.ArrowCtrl
,  
 941                   XtNborderWidth
, &BorderWidth
, NULL
); 
 942     XtConfigureWidget(w
->combobox
.ArrowCtrl
,  
 943                       w
->core
.width
-ArrowCtrlWidth
, HighlightThickness
,  
 945                       ComboBoxHeight 
- 2 * HighlightThickness
,  
 947 /* ...und ggf. das Textlabel. */ 
 948     if ( w
->combobox
.ShowLabel 
) { 
 949         XtVaGetValues(w
->combobox
.LabelCtrl
,  
 950                       XmNborderWidth
, &BorderWidth
,  
 952         XtConfigureWidget(w
->combobox
.LabelCtrl
,  
 954                           LabelCtrlWidth
, ComboBoxHeight
,  
 957 /* Falls da noch die Liste herumgurkt... */ 
 958     if ( w
->combobox
.StaticList 
) { 
 959         Dimension Width
, Height
; 
 961         if ( w
->core
.height 
> ComboBoxHeight 
)  
 962             Height 
= w
->core
.height 
- ComboBoxHeight
; 
 966         if ( w
->core
.width 
> (Dimension
)(ArrowCtrlWidth 
+ EditX
) ) 
 967             Width 
= w
->core
.width 
- ArrowCtrlWidth 
- EditX
; 
 971         XtConfigureWidget(XtParent(w
->combobox
.ListCtrl
), 
 972             EditX 
+ ArrowCtrlWidth
, ComboBoxHeight
, Width
, Height
, 0); 
 973     } else if ( w
->combobox
.ListVisible 
) 
 977 /* -------------------------------------------------------------------- 
 978  * Pappi fragt nach, wie gross wir denn sein wollen. 
 979  * Die hier benutzte Vorgehensweise zur Ermittlung der Groesse: 
 980  *   Sobald der Vater uns eine Breite (oder aber Hoehe) vorschlaegt,  
 981  *   die fuer uns eigentlich zu klein ist, meckern wir und schlagen 
 982  *   die von uns benoetigte Breite (Hoehe) vor. 
 983  * Soweit also zur Theorie... leider sieht es beispielsweise das 
 984  * Motif Form-Widget ueberhaupt nicht ein, uns auch nur ein einziges 
 985  * Mal nach unseren Wuenschen zu fragen! Damit es bei derart unum- 
 986  * gaenglichen Widgets dann doch noch geht, muss ChangedManaged die 
 987  * Kohlen wieder aus dem Feuer holen mit einer Sondertour. 
 989  *   *Request       Vom Vater vorgeschlagene Geometrie 
 991  *   *Reply         Unsere Antwort auf die vorgeschlagene Geometrie 
 992  *   sowie XtGeometryYes oder XtGeometryAlmost, je nachdem, wie gut 
 993  *   uns Pappis Vorschlag in den Kram passt. 
 995 static XtGeometryResult 
QueryGeometry(XmComboBoxWidget w
,  
 996                                       XtWidgetGeometry 
*Request
,  
 997                                       XtWidgetGeometry 
*Reply
) 
 999     XtGeometryResult result 
= XtGeometryYes
; 
1000     Dimension        minW
, minH
, editW
, labelW
; 
1002 /* Elternteil will nichts weiter aendern, also ist uns das 
1005     Request
->request_mode 
&= CWWidth 
| CWHeight
; 
1006     if ( Request
->request_mode 
== 0 ) return result
; 
1008     DefaultGeometry(w
, &minW
, &minH
, &editW
, &labelW
); 
1010 /* Ueberpruefe, ob uns das in der Breite passt, was Pappi moechte... */ 
1011     if ( Request
->request_mode 
& CWWidth 
) { 
1012         if ( Request
->width 
< minW 
) { 
1013 /* Wenn Pappi uns etwas vorschlaegt, was im wahrsten Sinne des Wortes  
1014  * vorn und hinten nicht reicht, dann versuchen wir ihn entsprechend 
1015  * zu korrigieren. ("Versuchen" deshalb, weil er diesen Vorschlag auch 
1016  * voellig ignorieren kann.) 
1018             result               
= XtGeometryAlmost
; 
1019             Reply
->width         
= minW
; 
1020             Reply
->request_mode 
|= CWWidth
; 
1023 /* Die ganze Chose nun noch vertikal */ 
1024     if ( Request
->request_mode 
& CWHeight 
) { 
1025         if ( Request
->height 
< minH 
) { 
1026             result               
= XtGeometryAlmost
; 
1027             Reply
->height        
= minH
; 
1028             Reply
->request_mode 
|= CWHeight
; 
1032 } /* QueryGeometry */ 
1034 /* -------------------------------------------------------------------- 
1035  * Die Groesse des ComboBox-Widgets hat sich veraendert und deshalb 
1036  * mussen alle Kinder neu positioniert werden. 
1037  * Letzten Endes laeuft hier alles auf ein ordinaeres DoLayout() 
1038  * hinaus, um die Kinder umher zu schieben. 
1040  *   w              Die bereits hinlaenglich bekannte Instanz dieses 
1043 static void Resize(XmComboBoxWidget w
) 
1048 /* -------------------------------------------------------------------- 
1049  * Dieses Widget hat sich in irgendeiner Form bewegt (und das nicht 
1050  * nur relativ zum Vater, sondern moeglicherweise auch der Vater 
1051  * selbst!) bzw. die Shell, in der sich irgendwo unsere Combo-Box 
1052  * befindet, hat soeben den Fokus verschusselt und kann ihn nicht 
1053  * mehr wiederfinden. Daneben kann es auch sein, dass die Shell 
1054  * ikonisiert wurde. (Welch' Vielfalt! Dieses ist hier halt eine 
1055  * multifunktionale Routine.) 
1058  *   w              Die naechste Shell in Reichweite ueber unserer 
1060  *   cbw            Diese Combo-Box. 
1061  *   event          ^ auf den Event, enthaelt genauerere Informationen 
1062  *                  (naja... sieht so aus, als ob Motif hier auch  
1063  *                  schon 'mal Schrott 'reinpackt...) 
1064  *   ContDispatch   Auf True setzen, damit dieser Event noch weiter- 
1065  *                  gereicht wird an all' die anderen, die auch noch 
1068 static void ShellCallback(Widget w
, XtPointer pClientData
,  
1069                           XEvent 
*event
, Boolean 
*ContDispatch
) 
1071     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
1073     switch ( event
->type 
) { 
1074         case ConfigureNotify
: 
1075         case CirculateNotify
: 
1076             DoDropDownLayout((XmComboBoxWidget
) cbw
); 
1079             LOG3("ShellCallback: FocusOut, mode: %i, detail: %i\n", 
1080                  (int)event
->xfocus
.mode
, (int)event
->xfocus
.detail
); 
1081             if ( cbw
->combobox
.Persistent 
) 
1082                 cbw
->combobox
.IgnoreFocusOut 
= True
; 
1083             else if ( (event
->xfocus
.mode 
== NotifyGrab
) && 
1084                       cbw
->combobox
.ListVisible 
) 
1085                 cbw
->combobox
.IgnoreFocusOut 
= True
; 
1088             ShowHideDropDownList((XmComboBoxWidget
) cbw
,  
1092     *ContDispatch 
= True
; 
1093 } /* ShellCallback */ 
1095 /* -------------------------------------------------------------------- 
1096  * Diese Routine sorgt dafuer, dass die Liste nicht irrtuemlich bei 
1097  * manchen Window Managern vom Bildschirm genommen wird, bloss weil 
1098  * diese der OverrideShell den Tastaturfocus schenken bzw. diesen 
1099  * dem Combo-Box-Widget wegnehmen, sobald der Mauszeiger in die Liste 
1102 static void OverrideShellCallback(Widget w
, XtPointer pClientData
, 
1103                                   XEvent 
*event
, Boolean 
*ContDispatch
) 
1106     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
1107     switch ( event
->type 
) { 
1109             LOG2("OverrideShellCallback: EnterNotify, PendingFO: %s\n",  
1110                  cbw
->combobox
.PendingFocusOut 
? "True" : "False"); 
1111             if ( cbw
->combobox
.PendingFocusOut 
) 
1112                 cbw
->combobox
.IgnoreFocusOut 
= True
; 
1113             if ( cbw
->combobox
.TwmHandlingOn 
) 
1114                 cbw
->combobox
.PendingOverrideInOut 
= True
; 
1117             LOG("OverrideShellCallback: LeaveNotify\n"); 
1118             if ( cbw
->combobox
.TwmHandlingOn 
) 
1119               cbw
->combobox
.PendingOverrideInOut 
= True
; 
1122 } /* OverrideShellCallback */ 
1124 /* -------------------------------------------------------------------- 
1125  * Ha! Anscheinend kann man das Problem mit der einklappenden Liste, 
1126  * sobald man den Arrow-Button anklickt, doch loesen! Allerdings geht 
1127  * das auch nur von hinten durch die Brust in's Auge. Hier war die 
1128  * Reihenfolge der Events bislang das Problem: Klickt man den Arrow- 
1129  * Button an, so verliert das Eingabefeld den Focus, dann wird leider 
1130  * schon die WorkProc aktiviert und laesst die Liste verschwinden. 
1131  * Danach erst kommt der Arrow-Button-Callback an die Reihe. Um dieses 
1132  * Dilemma doch noch zu loesen, wird hier darauf gelauert, wann und 
1133  * welcher LeaveNotify kommt. Klickt der Benutzer den Pfeil an, so 
1134  * kommt hier noch rechtzeitig ein LeaveNotify vorbei, der aber durch 
1135  * einen Grab ausgeloest wurde. Und das ist eben nur beim Anklicken 
1136  * der Fall. Damit wissen wir, das der FocusOut getrost ignoriert 
1138  * Puhhh -- ist das ein kompliziertes Chaos. 
1139  * Uebrigends...auch wenn manche Befehle zuerst ueberfluessig er- 
1140  * scheinen...sie sind erforderlich, damit die ComboBox auch mit unter- 
1141  * schiedlichen Window Managern zurechtkommt! 
1143 static void ArrowCrossingCallback(Widget w
, XtPointer pClientData
, 
1144                                XEvent 
*event
, Boolean 
*ContDispatch
) 
1147     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
1148     switch ( event
->type 
) { 
1150             LOG2("ArrowCrossingCallback: LeaveNotify, mode: %i\n",  
1151                  event
->xcrossing
.mode
); 
1152             if ( event
->xcrossing
.mode 
== NotifyGrab 
) 
1153                 cbw
->combobox
.IgnoreFocusOut 
= True
; 
1155                 cbw
->combobox
.IgnoreFocusOut 
= False
; 
1158 } /* ArrowCrossingCallback */ 
1160 /* -------------------------------------------------------------------- 
1161  * Alle Hilfeaufrufe innerhalb der Kinder gehen an das eigentliche 
1162  * Combo-Box-Widget weiter, so dass auch hier nach aussen hin die 
1163  * Kinder-Widgets nicht in Erscheinung treten. 
1165 static void HelpCallback(Widget w
, XtPointer cbw
, XtPointer CallData
) 
1167     XtCallCallbacks((Widget
) cbw
, XmNhelpCallback
, CallData
); 
1168 } /* HelpCallback */ 
1170 /* -------------------------------------------------------------------- 
1171  * Wenn der Benutzer im Eingabefeld osfActivate drueckt, dann dieses 
1172  * Ereignis offiziell bekanntgeben. 
1174 static void ActivateCallback(Widget w
, XtPointer cbw
, XtPointer CallData
) 
1176     XtCallCallbacks((Widget
) cbw
, XmNactivateCallback
, CallData
); 
1177 } /* ActivateCallback */ 
1179 /* -------------------------------------------------------------------- 
1180  * Ein Kind moechte sein Groesse veraendern und fragt deshalb hier bei 
1184  *   *Request       Vorschlag des Kindes 
1186  *   *Reply         Unsere Antwort darauf 
1187  *   XtGeometryNo, da es uns bislang grundsaetzlich nie passt, es sei 
1188  *   denn, es ist das Label... Naja, jetzt darf auch schon einmal das 
1189  *   Listenfeld quengeln (aber nur, wenn es staendig sichtbar ist,  
1190  *   ansonsten wird es nicht beruecksichtigt!). 
1192 static XtGeometryResult 
GeometryManager(Widget w
,  
1193                                         XtWidgetGeometry 
*Request
,  
1194                                         XtWidgetGeometry 
*Reply
) 
1196     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
1197     XtGeometryResult Result 
= XtGeometryNo
; 
1200      * Falls das Listenfeld statisch dargestellt wird, muessen wir seine 
1201      * Wuensche doch beruecksichtigen. Was fuer ein Aufwand... 
1203     if ( (w 
== XtParent(cbw
->combobox
.ListCtrl
)) && cbw
->combobox
.StaticList 
) { 
1204         Dimension TotalWidth
, TotalHeight
, EditWidth
, LabelWidth
; 
1205         XtWidgetGeometry MyRequest
, YourReply
, EditGeom
; 
1207         XtQueryGeometry(cbw
->combobox
.EditCtrl
, NULL
, &EditGeom
); 
1208         DefaultGeometry(cbw
, &TotalWidth
, &TotalHeight
, 
1209                              &EditWidth
, &LabelWidth
); 
1210         CheckDropDownOffset(cbw
); 
1212         if ( Request
->request_mode 
&& CWWidth 
) 
1213             if ( (Dimension
)(LabelWidth 
+ cbw
->combobox
.DropDownOffset 
+  
1214                              Request
->width
) > TotalWidth 
) 
1215                 TotalWidth 
= LabelWidth 
+ cbw
->combobox
.DropDownOffset 
+  
1218         if ( Request
->request_mode 
&& CWHeight 
) 
1219             TotalHeight 
= EditGeom
.height 
+ Request
->height
; 
1221      * Bastele nun eine Anfrage an Pappi zusammen und geh' ihm damit auf den 
1222      * Keks. Wenn er zustimmt, ist sofort alles gut, wir muessen dann nur 
1223      * noch das Layout aufpolieren, damit das Listenfeld die neue Groesse 
1224      * bekommt. Wenn Pappi nur halb zustimmt, akzeptieren wir das und fragen 
1225      * ihn damit noch einmal.... 
1227         MyRequest
.request_mode 
= CWWidth 
| CWHeight
; 
1228         MyRequest
.width        
= TotalWidth
; 
1229         MyRequest
.height       
= TotalHeight
; 
1230         Result 
= XtMakeGeometryRequest((Widget
) cbw
, &MyRequest
, &YourReply
); 
1231         if ( Result 
== XtGeometryAlmost 
) { 
1232             MyRequest
.width  
= YourReply
.width
; 
1233             MyRequest
.height 
= YourReply
.height
; 
1234             Result 
= XtMakeGeometryRequest((Widget
) cbw
, &MyRequest
, &YourReply
); 
1236         if ( Result 
== XtGeometryYes 
) 
1240      * Ansonsten darf nur noch das Schriftfeld Ansprueche anmelden. 
1242     if ( w 
!= cbw
->combobox
.LabelCtrl 
) 
1243         return XtGeometryNo
; /* Was ICH hier vorgegeben habe, gilt! */ 
1244     else if ( cbw
->combobox
.ShowLabel 
) { /* Naja, 'mal schauen! */ 
1245         Dimension TotalWidth
, TotalHeight
, EditWidth
, LabelWidth
; 
1246         XtWidgetGeometry MyRequest
; 
1248         if ( Request
->request_mode 
& CWWidth 
) { 
1249             DefaultGeometry(cbw
, &TotalWidth
, &TotalHeight
, 
1250                                  &EditWidth
, &LabelWidth
); 
1251             TotalWidth 
= TotalWidth 
- LabelWidth 
+  
1254             MyRequest
.request_mode 
= CWWidth
; 
1255             MyRequest
.width        
= TotalWidth
; 
1256             Result 
= XtMakeGeometryRequest((Widget
) cbw
, &MyRequest
, NULL
); 
1258             if ( Result 
== XtGeometryYes 
) 
1263 } /* GeometryManager */ 
1265 /* -------------------------------------------------------------------- 
1266  * Hier werden auf Wunsch diejenigen Farben, die bei der Combo-Box neu 
1267  * gesetzt wurden, an alle Kinder weitergegeben. 
1269 #define BOTTOMSHADOWCOLOR   0x0001 
1270 #define TOPSHADOWCOLOR      0x0002 
1271 #define FOREGROUND          0x0004 
1272 #define BACKGROUND          0x0008 
1274 static struct { String Resource
; int Flag
; } 
1275        ColorResources
[] = { 
1276            { XmNbottomShadowColor
, BOTTOMSHADOWCOLOR 
},  
1277            { XmNtopShadowColor
,    TOPSHADOWCOLOR    
},  
1278            { XmNforeground
,        FOREGROUND        
},  
1279            { XmNbackground
,        BACKGROUND        
} 
1282 static int UpdateColors(XmComboBoxWidget w
, int flags
) 
1284     Pixel  Color
, White
, Black
, EditCol
; 
1285     int    i
, size 
= XtNumber(ColorResources
); 
1286     Widget ScrolledWin
, ScrollBar
; 
1288     ScrolledWin 
= XtParent(w
->combobox
.ListCtrl
); 
1289     XtVaGetValues(ScrolledWin
, XmNverticalScrollBar
, &ScrollBar
, NULL
); 
1290     White 
= WhitePixel(XtDisplay(w
), WidgetToScreen((Widget
) w
)); 
1291     Black 
= BlackPixel(XtDisplay(w
), WidgetToScreen((Widget
) w
)); 
1292     for ( i
=0; i
<size
; i
++ ) 
1293         if ( flags 
& ColorResources
[i
].Flag 
) { 
1294             if ( ColorResources
[i
].Flag 
== BACKGROUND 
) 
1296             else if ( ColorResources
[i
].Flag 
== FOREGROUND 
) 
1300             XtVaGetValues((Widget
) w
, ColorResources
[i
].Resource
, &Color
, 
1302             XtVaSetValues(ScrollBar
,  
1303                           ColorResources
[i
].Resource
, Color
, NULL
); 
1304             XtVaSetValues(w
->combobox
.ListCtrl
,  
1305                           ColorResources
[i
].Resource
, EditCol
, NULL
); 
1306             XtVaSetValues(w
->combobox
.EditCtrl
,  
1307                           ColorResources
[i
].Resource
, EditCol
, NULL
); 
1308             XtVaSetValues(ScrolledWin
,  
1309                           ColorResources
[i
].Resource
, Color
, NULL
); 
1310             XtVaSetValues(w
->combobox
.LabelCtrl
,  
1311                           ColorResources
[i
].Resource
, Color
, NULL
); 
1312             XtVaSetValues(w
->combobox
.ArrowCtrl
,  
1313                           ColorResources
[i
].Resource
, Color
, NULL
); 
1314             if ( ColorResources
[i
].Flag 
& BACKGROUND 
) 
1315                 XtVaSetValues(ScrollBar
, XmNtroughColor
, Color
, NULL
); 
1319 } /* UpdateColors */ 
1321 /* -------------------------------------------------------------------- 
1322  * Liste aller vorgespiegelten Resourcen, die automatisch verarbeitet 
1323  * werden koennen, ohne weiter darueber nachdenken zu muessen... 
1325 typedef enum  { EDITCTRL
, LISTCTRL
, LABELCTRL 
} CHILDCTRL
; 
1326 typedef enum { RO
, RW
, RWS
, RWL
, RWI
, RWIGNORE 
} aUniqueName
; 
1330 /*    enum { RO, RW, RWS, RWL, RWI, RWIGNORE } dir; */ 
1332     /* nur lesen, lesen&schreiben, lesen&schreiben spezial, 
1333        lesen&schreiben label, lesen&schreiben items */ 
1336 /* Alle mit !!! gekennzeichneten Eintraege werden auf die richtigen 
1337  * Namen des entsprechenden Widgets umgesetzt. 
1339 static MIRROR MirroredResources
[] = { 
1340     { XmNitems
,                     LISTCTRL
,  RWI 
}, /* Urgs! */ 
1341     { XmNitemCount
,                 LISTCTRL
,  RWIGNORE  
}, /* dto.  */ 
1342     { XmNlistMarginHeight
,          LISTCTRL
,  RW  
},  
1343     { XmNlistMarginWidth
,           LISTCTRL
,  RW  
},  
1344     { XmNlistSpacing
,               LISTCTRL
,  RW  
},  
1345     { XmNstringDirection
,           LISTCTRL
,  RO  
}, /* Naja? */ 
1346     { XmNtopItemPosition
,           LISTCTRL
,  RO  
},  
1348     { XmNblinkRate
,                 EDITCTRL
,  RW  
},  
1349     { XmNcolumns
,                   EDITCTRL
,  RW  
},  
1350     { XmNcursorPosition
,            EDITCTRL
,  RW  
},  
1351     { XmNcursorPositionVisible
,     EDITCTRL
,  RW  
},  
1352     { XmNmarginHeight
,              EDITCTRL
,  RW  
},  
1353     { XmNmarginWidth
,               EDITCTRL
,  RW  
},  
1354     { XmNmaxLength
,                 EDITCTRL
,  RW  
},  
1355     { XmNselectThreshold
,           EDITCTRL
,  RW  
},  
1356     { XmNvalue
,                     EDITCTRL
,  RWS 
},  
1358     { XmNalignment
,                 LABELCTRL
, RW  
},  
1359     { XmNmnemonic
,                  LABELCTRL
, RW  
},  
1360     { XmNmnemonicCharSet
,           LABELCTRL
, RW  
},  
1361     { XmNlabelPixmap
,               LABELCTRL
, RW  
},  
1362     { XmNlabelInsensitivePixmap
,    LABELCTRL
, RW  
},  
1363     { XmNlabelString
,               LABELCTRL
, RW  
},  
1364     { XmNlabelType
,                 LABELCTRL
, RW  
},  
1365     { XmNlabelMarginBottom
,         LABELCTRL
, RWL 
}, /* !!! */ 
1366     { XmNlabelMarginHeight
,         LABELCTRL
, RWL 
}, /* !!! */ 
1367     { XmNlabelMarginLeft
,           LABELCTRL
, RWL 
}, /* !!! */ 
1368     { XmNlabelMarginRight
,          LABELCTRL
, RWL 
}, /* !!! */ 
1369     { XmNlabelMarginTop
,            LABELCTRL
, RWL 
}, /* !!! */ 
1370     { XmNlabelMarginWidth
,          LABELCTRL
, RWL 
}, /* !!! */ 
1371     { XmNlabelFontList
,             LABELCTRL
, RWL 
}, /* !!! */ 
1377 static TRANSFORMATION Transformations
[] = { 
1378     { XmNlabelMarginBottom
, XmNmarginBottom 
},  
1379     { XmNlabelMarginHeight
, XmNmarginHeight 
},  
1380     { XmNlabelMarginLeft
,   XmNmarginLeft   
},  
1381     { XmNlabelMarginRight
,  XmNmarginRight  
},  
1382     { XmNlabelMarginTop
,    XmNmarginTop    
},  
1383     { XmNlabelMarginWidth
,  XmNmarginWidth  
},  
1384     { XmNlabelFontList
,     XmNfontList     
}, 
1387 /* -------------------------------------------------------------------- 
1388  * Sobald irgendeine Resource veraendert wird, erfolgt der Aufruf 
1389  * hierin als Benachrichtigung, einmal nach dem rechten zu sehen. 
1391  *   current        Kopie der Widget-Instanz, bevor irgendwelche 
1392  *                  Resourcen veraendert oder set_values()-Methoden 
1393  *                  aufgerufen wurden. 
1394  *   req            Kopie der Widget-Instanz, aber bereits mit den 
1395  *                  durch XtSetValues veraenderten Werten 
1396  *   new            aktuellster Zustand der Widget-Instanz mit 
1397  *                  veraenderten Werten (entweder durch XtSetValues 
1398  *                  oder set_values()-Methoden der Superklasse) 
1399  *   args           Argumentenliste beim Aufruf von XtSetValues() 
1400  *   NumArgs        Anzahl der Argumente in der Liste 
1402  *   True, falls Widget neu gezeichnet werden soll. 
1404 static Boolean 
SetValues(XmComboBoxWidget current
, XmComboBoxWidget req
,  
1405                          XmComboBoxWidget newW
,  
1406                          ArgList args
, Cardinal 
*NumArgs
) 
1408     Boolean Update 
= False
; 
1409     int i
, j
, MirrorSize 
= XtNumber(MirroredResources
); 
1410     int k
, TransformationSize 
= XtNumber(Transformations
); 
1415  * Alle Resourcen, die nicht mehr nach dem Erstellen der Widget-Instanz 
1416  * veraendert werden koennen. 
1418     newW
->combobox
.Editable        
= current
->combobox
.Editable
; 
1419     newW
->combobox
.ListCtrl        
= current
->combobox
.ListCtrl
; 
1420     newW
->combobox
.EditCtrl        
= current
->combobox
.EditCtrl
; 
1421     newW
->combobox
.LabelCtrl       
= current
->combobox
.LabelCtrl
; 
1422     newW
->combobox
.SelectionPolicy 
= current
->combobox
.SelectionPolicy
; 
1423     newW
->combobox
.ListSizePolicy  
= current
->combobox
.ListSizePolicy
; 
1424     newW
->combobox
.StaticList      
= current
->combobox
.StaticList
; 
1427  * Kontrolliere nun alle Resourcen, die sich veraendert haben koennten 
1428  * und gebe die neuen Einstellungen entsprechend weiter... 
1430  * Hat sich der Sensitive-Zustand veraendert? Dann muessen wir hier dafuer 
1431  * sorgen, dass alle Kinder ebenfalls den neuen Zustand annehmen. 
1433     if ( current
->core
.sensitive 
!= newW
->core
.sensitive 
) { 
1434         XtSetSensitive(newW
->combobox
.ListCtrl
, newW
->core
.sensitive
); 
1435         XtSetSensitive(newW
->combobox
.EditCtrl
, newW
->core
.sensitive
); 
1436         XtSetSensitive(newW
->combobox
.ArrowCtrl
, newW
->core
.sensitive
); 
1437         XtSetSensitive(newW
->combobox
.ListCtrl
, newW
->core
.sensitive
); 
1438         if ( !newW
->core
.sensitive 
) 
1439             ShowHideDropDownList(newW
, NULL
, False
); 
1442  * Die ScrollBarPolicy kann nur dann geaendert werden, wenn das Listenfeld 
1443  * dauerhaft dargestellt wird. 
1445     if ( newW
->combobox
.ScrollBarDisplayPolicy 
!=  
1446          current
->combobox
.ScrollBarDisplayPolicy 
) { 
1447         if ( newW
->combobox
.StaticList 
) 
1448             XtVaSetValues(newW
->combobox
.ListCtrl
, 
1449                           XmNscrollBarDisplayPolicy
, newW
->combobox
.ScrollBarDisplayPolicy
, 
1453 "XmComboBox: ScrollBarDisplayPolicy can not be changed when StaticList == False." 
1456 /* Anzahl der in der Liste gleichzeitig darstellbaren Eintraege */ 
1457     if ( current
->combobox
.VisibleItemCount 
!=  
1458            newW
->combobox
.VisibleItemCount 
) { 
1459         XtVaSetValues(newW
->combobox
.ListCtrl
,  
1460                       XmNvisibleItemCount
, newW
->combobox
.VisibleItemCount
,  
1464     if ( current
->combobox
.AutomaticSelection 
!=  
1465          newW
->combobox
.AutomaticSelection 
) { 
1466         XtVaSetValues(newW
->combobox
.ListCtrl
,  
1467                       XmNautomaticSelection
, newW
->combobox
.AutomaticSelection
,  
1471  * benutzter Font: hier erhalten Liste und Eingabefeld jeweils die 
1472  * gleiche Fontliste, wohingegen das Label getrennt behandelt wird. 
1473  * Das macht auch Sinn, denn Liste und Eingabefeld beinhalten gleich- 
1474  * artigen Text, so dass hier auch tunlichst der gleiche Font zu 
1477     if ( current
->combobox
.Font 
!= newW
->combobox
.Font 
) { 
1478         XtVaSetValues(newW
->combobox
.ListCtrl
,  
1479                       XmNfontList
, newW
->combobox
.Font
, NULL
); 
1480         XtVaSetValues(newW
->combobox
.EditCtrl
,  
1481                       XmNfontList
, newW
->combobox
.Font
, NULL
); 
1486     if ( newW
->manager
.top_shadow_color 
!=  
1487          current
->manager
.top_shadow_color    
) Flags 
|= TOPSHADOWCOLOR
; 
1488     if ( newW
->manager
.bottom_shadow_color 
!=  
1489          current
->manager
.bottom_shadow_color 
) Flags 
|= BOTTOMSHADOWCOLOR
; 
1490     if ( newW
->manager
.foreground 
!=  
1491          current
->manager
.foreground          
) Flags 
|= FOREGROUND
; 
1492     if ( newW
->core
.background_pixel 
!=  
1493          current
->core
.background_pixel       
) Flags 
|= BACKGROUND
; 
1494     if ( Flags 
) { UpdateColors(newW
, Flags
); Update 
= True
; } 
1497     if ( newW
->combobox
.ArrowCursor 
!= current
->combobox
.ArrowCursor 
) { 
1498         if ( newW
->combobox
.ListVisible 
) 
1499             XDefineCursor(XtDisplay(newW
->combobox
.PopupShell
),  
1500                             XtWindow(newW
->combobox
.PopupShell
),  
1501                             newW
->combobox
.ArrowCursor
);  
1503 /* Hier werden die vorgespiegelten Resourcen verwaltet, die in 
1504  * Wirklichkeit zu einem unserer Kinder gehoeren. 
1506      for ( i 
= 0; i 
< *NumArgs
; i
++ ) { 
1507 /* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die 
1508  * Anfrage an das entsprechende Kind-Widget weiter. 
1510         for ( j 
= 0; j 
< MirrorSize
; j
++ ) { 
1511             if ( (strcmp(args
[i
].name
, MirroredResources
[j
].rsc
) == 0) ) { 
1512                 switch ( MirroredResources
[j
].dir 
) { 
1513                 case RW
:   /* schreibender Zugriff erlaubt */ 
1514                     XtSetValues(MirroredResources
[j
].ctrl 
== LISTCTRL 
? 
1515                                   newW
->combobox
.ListCtrl 
:   
1516                                 (MirroredResources
[j
].ctrl 
== EDITCTRL 
? 
1517                                   newW
->combobox
.EditCtrl 
: 
1518                                   newW
->combobox
.LabelCtrl
),  
1521                 case RWS
:  /* schreibender Zugriff unter Kontrolle */ 
1522                     if ( strcmp(args
[i
].name
, XmNvalue
) == 0 ) { 
1523                         if ( newW
->combobox
.Editable 
) 
1524                             XtSetValues(newW
->combobox
.EditCtrl
,  
1528                 case RWL
: /* Transformation in andere Resource beim 
1530                     for ( k 
= 0; k 
< TransformationSize
; k
++ ) 
1531                         if ( strcmp(args
[i
].name
, Transformations
[k
].from
) == 0 ) { 
1532                             arg
.value 
= args
[i
].value
; 
1533                             arg
.name 
= Transformations
[k
].to
; 
1534                             XtSetValues(newW
->combobox
.LabelCtrl
,  
1539                 case RWIGNORE
: /* Zugriff auf XmNitemCount */ 
1540                                /* Wird von XmNitems erledigt! */ 
1542                 case RWI
: /* Zugriff auf XmNitems */ 
1543                     for ( k 
= 0; k 
< *NumArgs
; k
++ ) 
1544                         if ( strcmp(args
[k
].name
, XmNitemCount
) == 0 ) { 
1547                             MyArgs
[0].name  
= XmNitems
; 
1548                             MyArgs
[0].value 
= args
[i
].value
; 
1549                             MyArgs
[1].name  
= XmNitemCount
; 
1550                             MyArgs
[1].value 
= args
[k
].value
; 
1551                             XtSetValues(newW
->combobox
.ListCtrl
, 
1553                             /*XtVaSetValues(newW->combobox.ListCtrl,  
1554                                           XmNitems,     args[i].value,  
1555                                           XmNitemCount, args[k].value,  
1562                 } /* case write mode */ 
1563                 goto ScanForNextResource
; 
1564             } /* if entry found */ 
1565         } /* for every mirrored entry */ 
1566         ScanForNextResource
: ; 
1567     } /* for every Arg */ 
1569     if ( (newW
->combobox
.SquareArrow 
!= current
->combobox
.SquareArrow
) || 
1570          (newW
->combobox
.ArrowSpacingOn 
!= current
->combobox
.ArrowSpacingOn
) ) { 
1578 /* -------------------------------------------------------------------- 
1579  * Werden irgendwelche Resourcen abgefragt, so muessen wir hier erst 
1580  * noch vor der Rueckkehr zum Frager klaeren, ob davon eine Resource 
1581  * betroffen ist, die nur vorgespiegelt ist, da sie eigentlich einem 
1582  * der Widgets gehoert, die von uns hier verwaltet werden, um daraus 
1583  * eine ordentliche Combo-Box zu machen. 
1586  *   args           Abgefragte Resourcen 
1587  *   NumArgs        Anzahl der abgefragten Resourcen 
1589 static void GetValuesAlmost(XmComboBoxWidget w
, ArgList args
,  
1592     int i
, j
, MirrorSize 
= XtNumber(MirroredResources
); 
1593     int k
, TransformationSize 
= XtNumber(Transformations
); 
1596     for ( i 
= 0; i 
< *NumArgs
; i
++ ) { 
1597 /* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die 
1598  * Anfrage an das entsprechende Kind-Widget weiter. 
1600         for ( j 
= 0; j 
< MirrorSize
; j
++ ) { 
1601             if ( strcmp(args
[i
].name
, MirroredResources
[j
].rsc
) == 0 ) { 
1602                 switch ( MirroredResources
[j
].dir 
) { 
1607                     XtGetValues(MirroredResources
[j
].ctrl 
== LISTCTRL 
? 
1608                                   w
->combobox
.ListCtrl 
:  
1609                                 MirroredResources
[j
].ctrl 
== EDITCTRL 
? 
1610                                   w
->combobox
.EditCtrl 
: 
1611                                   w
->combobox
.LabelCtrl
,  
1614                 case RWL
: /* Umzuleitende Resource bei Label-Widget */ 
1615                     for ( k 
= 0; k 
< TransformationSize
; k
++ ) 
1616                         if ( strcmp(args
[i
].name
, Transformations
[k
].from
) == 0 ) { 
1617                             arg
.value 
= args
[i
].value
; 
1618                             arg
.name 
= Transformations
[k
].to
; 
1619                             XtGetValues(w
->combobox
.LabelCtrl
,  
1626                 } /* case read mode */ 
1627             } /* if entry found */ 
1628         } /* for every mirrored entry */ 
1629     } /* for every Arg */ 
1630 } /* GetValuesAlmost */ 
1632 /* -------------------------------------------------------------------- 
1633  * Zeige beziehungsweise verstecke die Drop-Down-Liste der Combo-Box. 
1634  * Falls die Liste bereits den entsprechenden Zustand hat, geht's 
1635  * sofort zum Aufrufer zurueck. 
1637  *   w              Her Royal Majesty ComboBox 
1638  *   Show           True, falls anzuzeigen, andernfalls False 
1640 static void ShowHideDropDownList(XmComboBoxWidget w
, XEvent 
*event
,  
1643     XmComboBoxDropDownCallbackStruct info
; 
1645     if ( w
->combobox
.StaticList 
||  
1646          (Show 
== w
->combobox
.ListVisible
) ) return; 
1647     w
->combobox
.ListVisible 
= Show
; 
1648     if ( Show 
) { /* Klapp' die Liste aus! */ 
1649         DoDropDownLayout(w
); 
1650         info
.reason 
= XmCR_SHOW_LIST
; 
1652         XtCallCallbacks((Widget
) w
, XmNdropDownCallback
,  
1654         XDefineCursor(XtDisplay(w
->combobox
.PopupShell
),  
1655                         XtWindow(w
->combobox
.PopupShell
),  
1656                         w
->combobox
.ArrowCursor
);  
1657         XtPopup(w
->combobox
.PopupShell
, XtGrabNone
); 
1658         XtVaSetValues(w
->combobox
.ArrowCtrl
,  
1659                       XmNarrowDirection
, XmARROW_UP
, NULL
); 
1660     } else {      /* Klapp' die Liste wieder ein... */ 
1661         XtPopdown(w
->combobox
.PopupShell
); 
1662         XtVaSetValues(w
->combobox
.ArrowCtrl
,  
1663                       XmNarrowDirection
, XmARROW_DOWN
, NULL
); 
1664         info
.reason 
= XmCR_HIDE_LIST
; 
1666         XtCallCallbacks((Widget
) w
, XmNdropDownCallback
,  
1669 } /* ShowHideDropDownList */ 
1671 /* -------------------------------------------------------------------- 
1672  * Hier laeuft die Nachricht auf, dass der Pfeil ausgeloest wurde... 
1673  * (Daraufhin sollte die Liste aus- oder eingeklappt werden) 
1674  * ...oder dass der Benutzer da draussen auf der anderen Seite der 
1675  * Mattscheibe den Pfeil bereits anklickte ohne aber bereits losge- 
1676  * gelassen zu haben. Bereits hier bekommt das Eingabefeld den Fokus 
1677  * vor den Latz geknallt, denn sonst kann es passieren, dass zwar die 
1678  * Liste ausgeklappt ist, aber das Eingabefeld noch keinen Tastatur- 
1679  * fokus erhalten hat. Das sollte aber nicht so sein, denn es ist dann 
1680  * keine konsequente Tastaturbedienung. 
1682 static void ArrowCallback(Widget w
, XtPointer pClientData
,  
1683                           XmAnyCallbackStruct 
*info
) 
1685     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
1687     switch ( info
->reason 
) { 
1689             LOG("ArrowCallback: XmCR_ARM\n"); 
1690             XmProcessTraversal(cbw
->combobox
.EditCtrl
, XmTRAVERSE_CURRENT
); 
1691             if ( cbw
->combobox
.TwmHandlingOn 
&& cbw
->combobox
.ListVisible 
) 
1692                 cbw
->combobox
.IgnoreFocusOut 
= True
; 
1695             XmProcessTraversal(cbw
->combobox
.EditCtrl
, XmTRAVERSE_CURRENT
); 
1696             ShowHideDropDownList(cbw
, info
->event
,  
1697                                  (Boolean
)(!cbw
->combobox
.ListVisible
)); 
1700 } /* ArrowCallback */ 
1702 /* -------------------------------------------------------------------- 
1703  * Diese Benachrichtigung moechte uns nur mitteilen, dass wir soeben 
1704  * den Fokus verloren haben (Ohhhh!) Sollte allerdings der Fokus nur 
1705  * aus dem Grunde perdue sein, dass der Anwender den Mauszeiger ausser- 
1706  * halb des Applikationsfensters plaziert hat, so koennen wir diese 
1707  * Nachricht uebergehen. Erst wenn der Fokus an ein anderes Widget in 
1708  * unserer Applikation verlorenging, muessen wir auf diese Information 
1710  * Und jetzt zu noch einem total beknackten Problem - alles nur wegen 
1711  * Motif und den diversen Window-Managern (bspw. olwm)... Leider kommt 
1712  * beim FocusOut kein richtiger Hinweis auf den tatsaechlichen Event, 
1713  * der dieses Callback ausloeste -- warum liefert denn dann Motif ueber- 
1714  * haupt noch den Event???? Und ueberhauupt, die Geschichte mit dem 
1715  * Fokus ist schon der reinste Horror. Aktueller Ausweg: wenn wir die 
1716  * Benachrichtigung ueber den Focusabgang bekommen, registrieren wir 
1717  * eine Work-Prozedur, die, sobald der Rechner wieder Luft hat, auf- 
1718  * gerufen wird. Sie kann dann nachschauen, ob nicht inzwischen die 
1719  * OverrideShell den Focus bekahm. Wenn ja, koennen wir den FocusOut 
1720  * uebergehen, ansonsten muessen wir ihn beruecksichtigen. 
1721  * -- Ist das eine ^@#$^*(#$^&! (Meine gute Erziehung hindert mich 
1722  * daran, diesen Begriff hier zu nennen.) 
1724 static Boolean 
DelayedFocusOutWorkProc(XtPointer pClientData
) 
1726     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
1727     LOG2("DelayedFocusOutWorkProc: IgnoreFocusOut: %s\n",  
1728          cbw
->combobox
.IgnoreFocusOut 
? "True" : "False"); 
1729     if ( !cbw
->combobox
.IgnoreFocusOut 
) 
1730         ShowHideDropDownList(cbw
, &(cbw
->combobox
.xevent
), False
); 
1731     cbw
->combobox
.IgnoreFocusOut  
= False
; 
1732     cbw
->combobox
.PendingFocusOut 
= False
; 
1733     return True
; /* diese Routine wird nicht mehr benoetigt. */ 
1734 } /* DelayedFocusOutWorkProc */ 
1736 static void EditFocusCallback(Widget w
, XtPointer pClientData
,  
1737                               XmAnyCallbackStruct 
*info
) 
1739     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
1741     if ( cbw
->combobox
.StaticList 
) return; 
1743     if ( info
->reason 
== XmCR_LOSING_FOCUS 
) { 
1744         LOG2("EditFocusCallback: PendingFocusOut: %s, ",  
1745              cbw
->combobox
.PendingFocusOut 
? "True" : "False"); 
1746         LOG3("mode: %i, detail: %i, ", (int)info
->event
->xcrossing
.mode
, 
1747                                        (int)info
->event
->xcrossing
.detail
); 
1748         LOG2("PendingOverrideInOut: %s\n", 
1749              cbw
->combobox
.PendingOverrideInOut 
? "True" : "False"); 
1750         if ( !cbw
->combobox
.PendingFocusOut 
&& 
1751              !cbw
->combobox
.PendingOverrideInOut 
) { 
1752             /* Normalerweise duerfen aber keine NULL-Events hier 
1753              * vorbeikommen...aber man weiss ja nie so genau und 
1754              * sicher ist sicher. Defensiv programmieren! 
1757                 cbw
->combobox
.xevent 
= *info
->event
; 
1758             cbw
->combobox
.WorkProcID 
= XtAppAddWorkProc( 
1759                              XtWidgetToApplicationContext((Widget
) cbw
), 
1760                              (XtWorkProc
) DelayedFocusOutWorkProc
, 
1762             cbw
->combobox
.PendingFocusOut 
= True
; 
1764         cbw
->combobox
.PendingOverrideInOut 
= False
; 
1766 } /* EditFocusCallback */ 
1768 /* -------------------------------------------------------------------- 
1769  * Hier wird der angegebene Eintrag in der Listbox der Combo-Box 
1770  * markiert und zudem in den sichtbaren Bereich gerollt, sollte er 
1771  * sich ausserhalb des dargestellten Bereichs der Liste befinden. 
1773  *   w              Die Combo-Box (ueblicher Parameter) 
1774  *   Index          Index des neu zu markierenden Eintrages. 
1775  *   Notify         Schickt Mitteilung via Callback 
1777  *   Index des markierten Eintrages oder 0, falls die Listbox leer 
1778  *   war und deshalb auch kein Eintrag markiert werden konnte. 
1780 static int SetSelectionPos(XmComboBoxWidget w
, int Index
, Boolean Notify
) 
1782     Widget ListBox 
= w
->combobox
.ListCtrl
; 
1783     int            ItemCount
;      /* Anzahl Eintraege in Listbox   */ 
1784     int            TopItem
, VisibleItems
; 
1786     XtVaGetValues(ListBox
, XmNitemCount
,        &ItemCount
,  
1787                            XmNtopItemPosition
,  &TopItem
,  
1788                            XmNvisibleItemCount
, &VisibleItems
, 
1790     if ( Index 
< 1         ) Index 
= 1; 
1791     if ( Index 
> ItemCount 
) Index 
= ItemCount
; 
1792     if ( Index 
!= 0 && ItemCount 
!= 0 ) { 
1793         if ( Index 
< TopItem 
) 
1794             XmListSetPos(ListBox
, Index
); 
1795         if ( Index 
>= TopItem 
+ VisibleItems 
) 
1796             XmListSetBottomPos(ListBox
, Index
); 
1797         XmListSelectPos(ListBox
, Index
, Notify
); 
1801 } /* SetSelectionPos */ 
1803 /* -------------------------------------------------------------------- 
1804  * Diese Routine kuemmert sich darum, denjenigen Eintrag aus der List- 
1805  * box mit der angegebenen Nummer herauszufischen und an die Eingabe- 
1806  * zeile zu uebergeben. Dabei wird der Index auf den Eintrag auto- 
1807  * matisch auf den zulaessigen Bereich begrenzt. Zugleich wird auch 
1808  * noch der angegebene Eintrag in der Listbox markiert. 
1810 static void TransferToEditCtrl(XmComboBoxWidget w
, int SelectionIndex
,  
1813     Widget ListBox 
= w
->combobox
.ListCtrl
; 
1814     XmStringTable  Items
; 
1817     XtVaGetValues(ListBox
, XmNitems
, &Items
, NULL
); 
1820          (SelectionIndex 
== w
->combobox
.LastSelection
) && 
1821          (w
->combobox
.SelectionPolicy 
== XmSINGLE_SELECT
) ) { 
1825     if ( (SelectionIndex 
== 0) &&  
1826          (w
->combobox
.SelectionPolicy 
== XmSINGLE_SELECT
) ) { 
1827         XmListDeselectAllItems(w
->combobox
.ListCtrl
); 
1828         w
->combobox
.PassVerification 
= True
; 
1829         XmTextFieldSetString(w
->combobox
.EditCtrl
, ""); 
1831         SelectionIndex 
= SetSelectionPos(w
, SelectionIndex
, False
); 
1832         if ( SelectionIndex 
> 0 ) { 
1833             XmStringGetLtoR(Items
[SelectionIndex
-1],  
1834                             XmSTRING_DEFAULT_CHARSET
, &pItemText
); 
1835             w
->combobox
.PassVerification 
= True
; 
1836             XmTextFieldSetString(w
->combobox
.EditCtrl
, pItemText
); 
1840     w
->combobox
.LastSelection 
= SelectionIndex
; 
1841 } /* TransferToEditCtrl */ 
1843 /* -------------------------------------------------------------------- 
1844  * Alle registrierten Callbacks bei Anwahl eines neuen Eintrages in 
1845  * der Listbox aktivieren. 
1847 static void CallSelectionCBL(XmComboBoxWidget w
, XEvent 
*Event
) 
1851     index  
= XmComboBoxGetSelectedPos((Widget
) w
); 
1853      * Wenn momentan KEIN Eintrag selektiert ist, dann rufe den neuen 
1854      * XmNunselectionCallback auf! 
1857         XmComboBoxUnselectionCallbackStruct info
; 
1859         info
.reason 
= XmCR_UNSELECT
; 
1861         XtCallCallbacks((Widget
) w
, XmNunselectionCallback
, (XtPointer
) &info
); 
1864      * Ansonsten den ueblichen SelectionCallback! 
1866         XmComboBoxSelectionCallbackStruct info
; 
1867         XmStringTable                     Items
; 
1869         info
.reason 
= w
->combobox
.SelectionPolicy 
== XmSINGLE_SELECT 
?  
1870                             XmCR_SINGLE_SELECT 
: XmCR_BROWSE_SELECT
; 
1873         XtVaGetValues(w
->combobox
.ListCtrl
, XmNitems
, &Items
, NULL
); 
1874         info
.value  
= Items
[info
.index
-1]; 
1875         XtCallCallbacks((Widget
) w
, XmNselectionCallback
, (XtPointer
) &info
); 
1877 } /* CallSelectionCBL */ 
1879 /* -------------------------------------------------------------------- 
1880  * Hier laeuft das Tastatur-Management fuer die ComboBox zusammen. 
1881  * ACHTUNG: Der 'w'-Parameter wird nur benoetigt, um das eigentliche 
1882  * ComboBox-Widget zu ermitteln. Er muss daher die ID eines direkten 
1883  * Kinds der ComboBox enthalten! 
1885 static void CBoxManager(Widget w
, XEvent 
*Event
, String 
*params
,  
1886                         Cardinal 
*num_params
) 
1888     XmComboBoxWidget cbw
; 
1892     int              SelectionIndex
; /* Wer denn nun markiert wird... */ 
1893     int              ItemCount
;      /* Anzahl Eintraege in Listbox   */ 
1894     int              VisibleItems
;   /* Hoehe der Liste in Eintraegen */ 
1898      * Nur wenn eine der Translationen page-up und page-down direkt im 
1899      * Listenfeld ausgeloest wurden, wird auch als "w" die Liste ueber- 
1900      * geben. Bei allen anderen Faellen ist dieses zumeist das TextField. 
1902     if ( XtClass(w
) == xmListWidgetClass 
) 
1903         cbw 
= (XmComboBoxWidget
) XtParent(XtParent(w
)); 
1905         cbw 
= (XmComboBoxWidget
) XtParent(w
); 
1906     ListBox 
= cbw
->combobox
.ListCtrl
; 
1908     switch ( *(params
[0]) ) { 
1909 /* -------------------------------------------------------------------- 
1910  * Klappe die Liste auf Wunsch des Benutzers aus oder wieder ein. 
1912     case 's': /* show-hide-list */ 
1913         ShowHideDropDownList(cbw
, Event
,  
1914                              (Boolean
)(!cbw
->combobox
.ListVisible
)); 
1916     case 'h': /* hide-list */ 
1917         ShowHideDropDownList(cbw
, Event
, False
); 
1919 /* -------------------------------------------------------------------- 
1920  * Hier werden die Bewegungen in der Listbox behandelt. 
1923     case 'd': /* down              */ 
1925     case 'b': /* bottom            */ 
1926     case 'p': /* page-up/page-down */ 
1928         XtVaGetValues(ListBox
, XmNitemCount
,        &ItemCount
,  
1929                                XmNvisibleItemCount
, &VisibleItems
, NULL
); 
1930         if ( XmListGetSelectedPos(ListBox
, 
1931                                   &SelectionList
, &SelectionCount
) ) { 
1932             SelectionIndex 
= *SelectionList
; 
1933             XtFree((char *)SelectionList
); 
1935                 case 'u': SelectionIndex
--;               break; 
1936                 case 'd': SelectionIndex
++;               break; 
1937                 case 't': SelectionIndex 
= 1;             break; 
1938                 case 'b': SelectionIndex 
= ItemCount
;     break; 
1939                 case 'p': if ( *(params
[0]+5) == 'u' ) 
1940                               SelectionIndex 
-= VisibleItems
; 
1942                               SelectionIndex 
+= VisibleItems
; 
1945         } else { /* momentan noch kein Eintrag in der Liste ausgewaehlt */ 
1946             if ( opt 
== 'b' ) SelectionIndex 
= ItemCount
; 
1947             else              SelectionIndex 
= 1; /* nun ersten Eintrag nehmen */ 
1949         TransferToEditCtrl(cbw
, SelectionIndex
, False
); 
1950         CallSelectionCBL(cbw
, Event
); 
1952 /* -------------------------------------------------------------------- 
1953  * Der Benutzer hat die Eingabetaste gedrueckt oder einen Eintrag in 
1954  * der Listbox angeklickt. 
1956     case 'a': /* Return = activate */ 
1957     case 'S': /* Selection */ 
1958         if ( !cbw
->combobox
.StaticList 
&& !cbw
->combobox
.ListVisible 
) break; 
1959         XtVaGetValues(ListBox
, XmNitemCount
, &ItemCount
, NULL
); 
1960         if ( ItemCount 
== 0 ) break; 
1961         if ( XmListGetSelectedPos(ListBox
, 
1962                                   &SelectionList
, &SelectionCount
) ) { 
1963             SelectionIndex 
= *SelectionList
; 
1964             XtFree((char *)SelectionList
); 
1966             if ( cbw
->combobox
.SelectionPolicy 
!= XmSINGLE_SELECT 
) 
1972         TransferToEditCtrl(cbw
, SelectionIndex
,  
1973             *(params
[0]) == 'S'); 
1974         CallSelectionCBL(cbw
, Event
); 
1975         ShowHideDropDownList(cbw
, Event
, (Boolean
) 
1976                               (*(params
[0]) == 'S' ? True 
: False
)); 
1978 /* -------------------------------------------------------------------- 
1979  * Der Benutzer hat die ESC-Taste gedrueckt. Ist die Liste zu diesem 
1980  * Zeitpunkt noch ausgeklappt, so wird sie einfach nur eingeklappt und 
1981  * weiter passiert nichts. Ist die Liste jedoch eingeklappt, so wird 
1982  * das ESC an die normale Action-Routine des Eingabefeldes weiter- 
1983  * gegeben, damit damit bspw. Dialog u.a. abgebrochen werden koennen. 
1985     case 'c': /* Cancel */ 
1986         if ( cbw
->combobox
.ListVisible 
) 
1987             ShowHideDropDownList(cbw
, Event
, False
); 
1989             XtCallActionProc(cbw
->combobox
.EditCtrl
,  
1990                              "process-cancel", Event
, NULL
, 0); 
1992 /* -------------------------------------------------------------------- 
1993  * Wenn es erlaubt ist, dass auch einmal kein Eintrag in einer ComboBox 
1994  * mit nicht editierbarem Eingabefeld ausgewaehlt ist, dann darf der 
1995  * Anwender mittels osfDelete den aktuellen Eintrag deselektieren. 
1997     case 'w': /* wipe */ 
1998         if ( cbw
->combobox
.SelectionPolicy 
== XmSINGLE_SELECT 
) { 
1999             TransferToEditCtrl(cbw
, 0, True
); 
2000             CallSelectionCBL(cbw
, Event
); 
2003 /* -------------------------------------------------------------------- 
2006     case 'n': /* no-operation */ 
2011 /* -------------------------------------------------------------------- 
2012  * Der Benutzer hat einen Eintrag in der Listbox angeklickt. Der Ein- 
2013  * fachkeit halber wird einfach nur ein Druecken der Eingabetaste 
2016 static void ListSelectionCallback(Widget w
, XtPointer pClientData
,  
2017                                   XmAnyCallbackStruct 
*info
) 
2019     String           paramsMouse
[1] = { "a" }, paramsKeyboard
[1] = { "S" }; 
2020     Cardinal         NumParams 
= 1; 
2021     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
2023  * Wurde der Event durch die Tastatur oder einen Mausklick 
2024  * ausgeloest? Wenn es ein Mausklick auf das Listenfeld war und es 
2025  * sich um ein staendig angezeigtes Listenfeld einer nicht editierbaren 
2026  * ComboBox handelt, dann gib' dem Eingabefeld den Tastaturfokus. 
2028     if ( info
->event 
== NULL 
) 
2029         CBoxManager(cbw
->combobox
.EditCtrl
, info
->event
,  
2030                     paramsKeyboard
, &NumParams
); 
2032         CBoxManager(cbw
->combobox
.EditCtrl
, info
->event
,  
2033                     paramsMouse
, &NumParams
); 
2034         if ( !cbw
->combobox
.StaticList 
|| 
2035              (cbw
->combobox
.StaticList 
&& !cbw
->combobox
.Editable
) ) 
2036             XmProcessTraversal(cbw
->combobox
.EditCtrl
,  
2037                                XmTRAVERSE_CURRENT
); 
2039 } /* ListSelectionCallback */ 
2041 /* -------------------------------------------------------------------- 
2042  * Nach einem Doppelklick innerhalb des Listenfelds wird diese Routine 
2043  * aufgerufen. Zunaechst einmal wird ganz normal wie bei einem ein- 
2044  * fachen Anklicken vorgegangen, danach aber noch der ein spezieller 
2045  * Callback aufgerufen. 
2047 static void ListDefaultActionCallback(Widget w
, XtPointer pClientData
,  
2048                                       XmAnyCallbackStruct 
*OldInfo
) 
2050     XmComboBoxWidget                      cbw 
= (XmComboBoxWidget
) pClientData
; 
2051     XmComboBoxDefaultActionCallbackStruct info
; 
2052     XmStringTable                         Items
; 
2054     ListSelectionCallback(w
, pClientData
, OldInfo
); 
2055     info
.reason 
= XmCR_DEFAULT_ACTION
; 
2056     info
.event  
= OldInfo
->event
; 
2057     info
.index  
= XmComboBoxGetSelectedPos((Widget
) cbw
); 
2058     XtVaGetValues(cbw
->combobox
.ListCtrl
, XmNitems
, &Items
, NULL
); 
2059     info
.value  
= Items
[info
.index
-1]; 
2060     XtCallCallbacks((Widget
) cbw
, XmNdefaultActionCallback
, (XtPointer
) &info
); 
2061 } /* ListDefaultActionCallback */ 
2064 /* -------------------------------------------------------------------- 
2065  * Ohweh!! Diese Routine wurde erforderlich, um XmNautomaticSelection 
2066  * zu unterstuetzen. Denn wenn der Benutzer in der Liste herumsucht und 
2067  * automaticSelection 'True' ist, kommt kein Callback-Aufruf mehr, wenn 
2068  * die Maustaste losgelassen wird. Und damit wuessten wir sonst nicht,  
2069  * wann die Liste einzuklappen ist! Irgendwie wird das alles mit der 
2070  * Zeit immer konfuser und aufwendiger. Wenn das Chaos gequantelt 
2071  * sein sollte, dann muss das Chaos-Quant (sog. 'Chaotonen') aber jede 
2072  * Menge Chaos transportieren!!! 
2074 static void Button1UpInList(Widget w
, XtPointer pClientData
,  
2075                            XEvent 
*Event
, Boolean 
*ContDispatch
) 
2077     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) pClientData
; 
2079     if ( Event
->xbutton
.button 
== Button1 
) { 
2080         if ( cbw
->combobox
.AutomaticSelection 
) 
2081             ShowHideDropDownList(cbw
, Event
, False
); 
2083 } /* Button1UpInList */ 
2085 /* -------------------------------------------------------------------- 
2086  * Sobald sich irgendetwas im Eingabefeld veraenderte, kommt das 
2087  * TextField-Widget zuerst zu uns gelaufen, um sich unser Okay zu 
2088  * holen. Bei einer nicht editierbaren Combo-Box wird hierueber die 
2089  * Schnellsuche realisiert. 
2091 static void EditVerifyCallback(Widget w
, XtPointer pClientData
,  
2092                                XmTextVerifyCallbackStruct 
*info
) 
2094     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
2097  * Sollte gerade dem Eingabefeld Text aus der Listbox einverleibt 
2098  * werden, so duerfen wir hier darueber natuerlich nicht meckern,  
2099  * sondern unser <<ok>> dazu geben. (D.h. in diesem Fall haben wir 
2100  * kein Recht, zu intervenieren.) 
2102     if ( cbw
->combobox
.PassVerification 
) { 
2103         cbw
->combobox
.PassVerification 
= False
; 
2108  * Ist es eine Combo-Box, in die kein Text vom Benutzer eingegeben 
2109  * werden kann, so wird bei der Eingabe von Zeichen die Schnellsuche 
2112     if ( !cbw
->combobox
.Editable 
) { 
2113         Widget         ListBox 
= cbw
->combobox
.ListCtrl
; 
2114         char           WarpCharLow
, WarpCharHigh
; 
2116         XmStringTable  Items
; 
2119         int            i
, ItemCount
, Start
; 
2124         if ( (info
->text         
== NULL 
) || 
2125              (info
->text
->length 
== 0    ) ) return; /* Hoppala! */ 
2127  * Nun aus dem Zeichen einen String (Motif-like) basteln und 
2128  * in der Listbox danach auf die Suche gehen. 
2130         if ( info
->text
->length 
> 1 ) { 
2131             /* Das ist nun endweder ein normaler Paste, oder aber 
2132              * das Ergebnis einer Drag'n'Drop-Operation. 
2134             Item 
= XmStringCreateSimple(info
->text
->ptr
); 
2135             XmComboBoxSelectItem((Widget
) cbw
, Item
, True
); 
2138             /* Ansonsten soll nur eine Schnellsuche ausgefuehrt 
2139              * werden, der entsprechende Buchstabe ist das einzige  
2140              * Zeichen im dem Callback uebergebenen Text. 
2142             WarpCharLow  
= tolower(*(info
->text
->ptr
)); 
2143             WarpCharHigh 
= toupper(WarpCharLow
); 
2145             XtVaGetValues(ListBox
, XmNitemCount
, &ItemCount
,  
2148             if ( ItemCount 
< 1 ) return; 
2149             /* Ermittele, wo's los geht mit der Suche... */ 
2150             if ( XmListGetSelectedPos(ListBox
,  
2151                                       &SelectionList
, &SelectionCount
) ) { 
2152                 Start 
= *SelectionList
; i 
= Start 
+ 1; 
2153                 XtFree((char *)SelectionList
); 
2154             } else i 
= Start 
= 1; 
2156             if ( i 
> ItemCount 
) i 
= 1; 
2158             while ( i 
!= Start 
|| Ignore 
) { 
2160                 XmStringGetLtoR(Items
[i
-1], XmSTRING_DEFAULT_CHARSET
,  
2162                 if ( (strchr(pItem
, WarpCharLow 
) == pItem
) || 
2163                      (strchr(pItem
, WarpCharHigh
) == pItem
) ) {  
2165                     TransferToEditCtrl(cbw
, i
, False
); 
2166                     CallSelectionCBL(cbw
, info
->event
); 
2170                 if ( ++i 
> ItemCount 
) i 
= 1; 
2175  * Wenn das Eingabefeld editierbar ist, dann fragen wir ueber die Callbacks 
2176  * nach, ob es genehm ist, den neuen Text einzufuegen. 
2178         XtCallCallbacks((Widget
) cbw
, XmNmodifyVerifyCallback
,  
2181 } /* EditVerifyCallback */ 
2183 /* -------------------------------------------------------------------- 
2184  * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox 
2185  * mit einem veraenderlichem Eingabefeld der Eingabetext veraendert 
2186  * wurde. In diesem Fall suchen wir hier nach einem passenden gleich- 
2187  * lautenden Eintrag. Wenn wir einen finden, heben wir ihn in der Liste 
2188  * sogleich hervor, ansonsten ist kein Eintrag hervorgehoben. 
2190 static void EditChangedCallback(Widget w
, XtPointer pClientDate
,  
2191                                 XmAnyCallbackStruct 
*info
) 
2193     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
2194     XmStringTable    Items
; 
2200      * Zuerst nach einem passenden Eintrag zum Eingabefeld in der Liste 
2203     XtVaGetValues(cbw
->combobox
.EditCtrl
, XmNvalue
, &EditLine
, NULL
); 
2204     XtVaGetValues(cbw
->combobox
.ListCtrl
,  
2205                   XmNitemCount
, &ItemCount
,  
2208     EditStr 
= XmStringCreateSimple(EditLine
); 
2209     XtVaSetValues(cbw
->combobox
.ListCtrl
, XmNselectedItemCount
, 0, NULL
); 
2210     if ( ItemCount 
< 1 ) return; 
2211     for ( i 
= 0; i 
< ItemCount
; i
++ ) 
2212         if ( XmStringCompare(Items
[i
], EditStr
) ) { 
2213             SetSelectionPos(cbw
, i
+1, False
); 
2216     XmStringFree(EditStr
); 
2218      * Zum Abschluss noch den Callback aufrufen... 
2220     XtCallCallbacks((Widget
) cbw
, XmNvalueChangedCallback
, (XtPointer
) info
); 
2221 } /* EditChangedCallback */ 
2223 /* -------------------------------------------------------------------- 
2224  * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox 
2225  * mit einem veraenderlichem Eingabefeld der Cursor bewegt wurde. 
2226  * Dieser Callback ist nur fuer echte Fans von Callbacks da... 
2228 static void MotionVerifyCallback(Widget w
, XtPointer pClientDate
,  
2229                                  XmTextVerifyCallbackStruct 
*info
) 
2231     XmComboBoxWidget cbw 
= (XmComboBoxWidget
) XtParent(w
); 
2233     XtCallCallbacks((Widget
) cbw
, XmNmotionVerifyCallback
, (XtPointer
) info
); 
2234 } /* MotionVerifyCallback */ 
2236 /* -------------------------------------------------------------------- 
2237  * Bastele einen vollstaendigen Namens- und Klassenbezeichner anhand 
2238  * des angegebenen Widgets zusammen. 
2240 static void MakeNameAndClass(Widget w
, char *NameBuff
, char *ClassBuff
) 
2242     Widget Parent 
= XtParent(w
); 
2244     if ( Parent 
) MakeNameAndClass(Parent
, NameBuff
, ClassBuff
); 
2245     if ( XtIsSubclass(w
, applicationShellWidgetClass
) ) { 
2246         /* Wenn wir ganz oben angekommen sind, holen wir uns den 
2247          * Namen und die Klasse der Applikation selbst und nicht die 
2250         String AppName
, AppClass
; 
2251         XtGetApplicationNameAndClass( 
2252             XtDisplayOfObject(w
), &AppName
, &AppClass
); 
2253         strcpy(NameBuff
, AppName
); 
2254         strcpy(ClassBuff
, AppClass
); 
2256         /* Ansonsten sind wir noch mitten irgendwo in der Hierarchie 
2257          * und besorgen uns den Namen und die Klasse dieses Widgets 
2259         strcat(NameBuff
,  ".");  
2260         strcat(NameBuff
,  XtName(w
)); 
2261         strcat(ClassBuff
, ".");  
2262         strcat(ClassBuff
, ((CoreClassRec 
*) XtClass(w
))->core_class
.class_name
); 
2264 } /* MakeNameAndClass */ 
2266 /* -------------------------------------------------------------------- 
2267  * Eine einzelne Resource aus der Datenbank herausholen. Diese Resource 
2268  * kommt im Allgemeinen immer als String zurueck und muss daher erst 
2269  * noch in das gewuenschte Zielformat konvertiert werden. 
2271 static Boolean 
FetchResource(Widget w
,  
2272                              char *FullName
, char *FullClass
,  
2273                              char *RscName
, char *RscClass
,  
2275                              String   
*RepresentationType
) 
2278     char *EndOfName  
= FullName  
+ strlen(FullName
); 
2279     char *EndOfClass 
= FullClass 
+ strlen(FullClass
); 
2281     strcat(FullName
,  "."); strcat(FullName
,  RscName
); 
2282     strcat(FullClass
, "."); strcat(FullClass
, RscClass
); 
2283     ok 
= XrmGetResource( 
2284         XtDatabase(XtDisplayOfObject(w
)),  
2285         FullName
, FullClass
, RepresentationType
, RscValue
); 
2286     /* Wieder den alten Namens- und Klassenrumpf herstellen */ 
2287     *EndOfName 
= 0; *EndOfClass 
= 0; 
2289 } /* FetchResource */ 
2291 /* -------------------------------------------------------------------- 
2292  * Nun folgen diejenigen Routinen, mit denen die Konvertierung in das 
2293  * gewuenschte Zielformat einer Resource moeglich ist. 
2297  *   String XmPIXMAP / XmSTRING --> unsigned char 
2298  *   String --> Dimension 
2299  *   String --> XmString 
2300  *   String --> XmStringTable 
2301  *   String --> XmFontList 
2302  *   String --> Pixmap (genauer: Bitmap) 
2306 static Boolean 
FetchIntResource(Widget w
,  
2307                                 char *FullName
, char *FullClass
,  
2308                                 char *RscName
, char *RscClass
,  
2311     XrmValue RscValue
, RscDest
; 
2312     String   RepresentationType
; 
2314     if ( FetchResource(w
, FullName
, FullClass
,  
2316                        &RscValue
, &RepresentationType
) ) { 
2317         RscDest
.size 
= sizeof(int); 
2318         RscDest
.addr 
= (caddr_t
) pInt
; 
2319         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2324 } /* FetchIntResource */ 
2326 static Boolean 
FetchShortResource(Widget w
,  
2327                                 char *FullName
, char *FullClass
,  
2328                                 char *RscName
, char *RscClass
,  
2331     XrmValue RscValue
, RscDest
; 
2332     String   RepresentationType
; 
2334     if ( FetchResource(w
, FullName
, FullClass
,  
2336                        &RscValue
, &RepresentationType
) ) { 
2337         RscDest
.size 
= sizeof(short); 
2338         RscDest
.addr 
= (caddr_t
) pShort
; 
2339         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2340                                XtRShort
, &RscDest
) ) 
2344 } /* FetchShortResource */ 
2346 static Boolean 
FetchLabelTypeResource(Widget w
,  
2347                                 char *FullName
, char *FullClass
,  
2348                                 char *RscName
, char *RscClass
,  
2349                                 unsigned char *pUChar
) 
2352     String   RepresentationType
; 
2354     if ( FetchResource(w
, FullName
, FullClass
,  
2356                        &RscValue
, &RepresentationType
) ) { 
2357         if ( strcasecmp((char *) RscValue
.addr
, "XmPIXMAP") == 0 ) 
2364 } /* FetchLabelTypeResource */ 
2366 static Boolean 
FetchDimensionResource(Widget w
,  
2367                                 char *FullName
, char *FullClass
,  
2368                                 char *RscName
, char *RscClass
,  
2369                                 Dimension 
*pDimension
) 
2371     XrmValue RscValue
, RscDest
; 
2372     String   RepresentationType
; 
2374     if ( FetchResource(w
, FullName
, FullClass
,  
2376                        &RscValue
, &RepresentationType
) ) { 
2377         RscDest
.size 
= sizeof(Dimension
); 
2378         RscDest
.addr 
= (caddr_t
) pDimension
; 
2379         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2380                                XtRDimension
, &RscDest
) ) 
2384 } /* FetchDimensionResource */ 
2386 static Boolean 
FetchStringResource(Widget w
,  
2387                                 char *FullName
, char *FullClass
,  
2388                                 char *RscName
, char *RscClass
,  
2392     String   RepresentationType
; 
2394     if ( FetchResource(w
, FullName
, FullClass
,  
2396                        &RscValue
, &RepresentationType
) ) { 
2397         *pString 
= (char *) RscValue
.addr
; 
2401 } /* FetchStringResource */ 
2403 static Boolean 
FetchKeySymResource(Widget w
,  
2404                                 char *FullName
, char *FullClass
,  
2405                                 char *RscName
, char *RscClass
,  
2408     XrmValue RscValue
, RscDest
; 
2409     String   RepresentationType
; 
2411     if ( FetchResource(w
, FullName
, FullClass
,  
2413                        &RscValue
, &RepresentationType
) ) { 
2414         RscDest
.size 
= sizeof(KeySym
); 
2415         RscDest
.addr 
= (caddr_t
) pKeySym
; 
2416         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2417                                XmRKeySym
, &RscDest
) ) 
2421 } /* FetchKeySymResource */ 
2423 static Boolean 
FetchXmStringResource(Widget w
,  
2424                                 char *FullName
, char *FullClass
,  
2425                                 char *RscName
, char *RscClass
,  
2429     String   RepresentationType
; 
2431     if ( FetchResource(w
, FullName
, FullClass
,  
2433                        &RscValue
, &RepresentationType
) ) { 
2434         *pString 
= XmCvtCTToXmString((char *) RscValue
.addr
); 
2438 } /* FetchXmStringResource */ 
2440 static Boolean 
FetchXmStringTableResource(Widget w
,  
2441                                 char *FullName
, char *FullClass
,  
2442                                 char *RscName
, char *RscClass
,  
2443                                 XmStringTable 
*pStringTable
,  
2447     String   RepresentationType
; 
2448     String   TmpList
, p
, pStart
; 
2451     if ( FetchResource(w
, FullName
, FullClass
,  
2453                        &RscValue
, &RepresentationType
) ) { 
2455          * Zuerst eine Kopie erzeugen und dann daraus die Liste 
2458         TmpList 
= XtNewString((String
)RscValue
.addr
); 
2459         if ( TmpList 
== NULL 
) return False
; 
2460         if ( *TmpList 
== 0 ) { XtFree(TmpList
); return False
; } 
2461         /* Ermittele, wieviele Eintrage in der Liste sind und 
2462          * erstelle dann daraus die Liste. 
2464         Entries 
= 1; p 
= TmpList
; 
2466             if ( *p
++ == ',' ) ++Entries
; 
2467         *pStringTable 
= (XmStringTable
)  
2468             XtMalloc(Entries 
* sizeof(XmString
)); 
2471         for ( Entry 
= 0; Entry 
< Entries
; ++Entry 
) { 
2473             while ( (*p 
!= 0) && (*p 
!= ',') ) ++p
; 
2475             (*pStringTable
)[Entry
] = (XmString
) 
2476                 XmStringCreateSimple(pStart
); 
2478         /* Hier geht ausnahmsweise einmal Rueckgabe vor 
2479          * Entschaedigung... hey, das war doch nur ein 
2480          * (wenn auch ziemlich miserabler) Scherz 
2483         *pTableSize 
= Entries
; 
2487 } /* FetchXmStringTableResource */ 
2489 static Boolean 
FetchXmFontListResource(Widget w
,  
2490                                 char *FullName
, char *FullClass
,  
2491                                 char *RscName
, char *RscClass
,  
2492                                 XmFontList 
*pFontList
) 
2494     XrmValue RscValue
, RscDest
; 
2495     String   RepresentationType
; 
2497     if ( FetchResource(w
, FullName
, FullClass
,  
2499                        &RscValue
, &RepresentationType
) ) { 
2500         RscDest
.size 
= sizeof(XmFontList
); 
2501         RscDest
.addr 
= (caddr_t
) pFontList
; 
2502         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2503                                XmRFontList
, &RscDest
) ) 
2507 } /* FetchXmFontListResource */ 
2509 static Boolean 
FetchPixmapResource(Widget w
,  
2510                                 char *FullName
, char *FullClass
,  
2511                                 char *RscName
, char *RscClass
, 
2514     XrmValue RscValue
, RscDest
; 
2515     String   RepresentationType
; 
2517     if ( FetchResource(w
, FullName
, FullClass
,  
2519                        &RscValue
, &RepresentationType
) ) { 
2520         RscDest
.size 
= sizeof(Pixmap
); 
2521         RscDest
.addr 
= (caddr_t
) pPixmap
; 
2522         if ( XtConvertAndStore(w
, RepresentationType
, &RscValue
,  
2523                                XtRBitmap
, &RscDest
) ) 
2527 } /* FetchPixmapResource */ 
2529 /* -------------------------------------------------------------------- 
2530  * Waehrend der Initialisierung alle gespiegelten Resourcen, fuer die 
2531  * Eintraege in der Resourcen-Datenbank existieren an die passenden 
2532  * Kinder-Widgets weiterleiten. Der Trick an der Sache: wir setzen 
2533  * die betroffenen Resourcen vie XtSetValues mit uns selbst als Ziel. 
2534  * Dadurch bekommt SetValues die Arbeit aufgehalst, die Resourcen den 
2535  * richtigen Kindern zuzuordnen... 
2541 #define RDimension      3        
2544 #define RXmFontList     6 
2547 #define RXmStringTable  9 
2548 #define RXmItemCount    10 
2559 static RESOURCEMIRROR ResourceMirror
[] = { 
2560     { XmNblinkRate
,              XmCBlinkRate
,              RInt
,          },  
2561     { XmNcolumns
,                XmCColumns
,                RShort
,        },  
2562     { XmNmaxLength
,              XmCMaxLength
,              RInt
,          },  
2563     { XmNmarginHeight
,           XmCMarginHeight
,           RDimension     
},  
2564     { XmNmarginWidth
,            XmCMarginWidth
,            RDimension     
}, 
2565     { XmNselectThreshold
,        XmCSelectThreshold
,        RInt           
},  
2567     { XmNlistMarginHeight
,       XmCListMarginHeight
,       RDimension     
},  
2568     { XmNlistMarginWidth
,        XmCListMarginWidth
,        RDimension     
},  
2569     { XmNlistSpacing
,            XmCListSpacing
,            RDimension     
}, 
2570     { XmNitems
,                  XmCItems
,                  RXmStringTable 
}, 
2571     { XmNitemCount
,              XmCItemCount
,              RXmItemCount   
}, 
2573     { XmNmnemonic
,               XmCMnemonic
,               RKeySym        
},  
2574     { XmNmnemonicCharSet
,        XmCMnemonicCharSet
,        RString        
},  
2575     { XmNlabelString
,            XmCLabelString
,            RXmString      
},  
2576     { XmNlabelMarginBottom
,      XmCLabelMarginBottom
,      RDimension     
},  
2577     { XmNlabelMarginHeight
,      XmCLabelMarginHeight
,      RDimension     
},  
2578     { XmNlabelMarginLeft
,        XmCLabelMarginLeft
,        RDimension     
},  
2579     { XmNlabelMarginRight
,       XmCLabelMarginRight
,       RDimension     
},  
2580     { XmNlabelMarginTop
,         XmCLabelMarginTop
,         RDimension     
},  
2581     { XmNlabelMarginWidth
,       XmCLabelMarginWidth
,       RDimension     
},  
2582     { XmNlabelPixmap
,            XmCLabelPixmap
,            RPixmap        
}, 
2583     { XmNlabelInsensitivePixmap
, XmCLabelInsensitivePixmap
, RPixmap        
},  
2584     { XmNlabelType
,              XmCLabelType
,              RLType         
},  
2585     { XmNlabelFontList
,          XmCLabelFontList
,          RXmFontList    
},  
2588 static void InitMirrorResources(XmComboBoxWidget w
) 
2590     char          FullName
[1024], FullClass
[1024]; 
2591     int           AInt
, TableSize
; 
2593     unsigned char AUChar
; 
2594     Dimension     ADimension
; 
2596     XmStringTable AStringTable
; 
2598     XmFontList    AFontList
; 
2601     int           i
, size 
= XtNumber(ResourceMirror
); 
2603     FullName
[0] = 0; FullClass
[0] = 0; 
2604     MakeNameAndClass((Widget
) w
, FullName
, FullClass
); 
2606     for ( i
=0; i 
< size
; i
++ ) { 
2607         switch ( ResourceMirror
[i
].Converter 
) { 
2609                 if ( FetchIntResource((Widget
) w
,  
2610                         FullName
, FullClass
,  
2611                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2613                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2617                 if ( FetchIntResource((Widget
) w
,  
2618                         FullName
, FullClass
,  
2619                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2620                         &AInt
) && ( AInt 
!= 0) ) 
2621                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2625                 if ( FetchShortResource((Widget
) w
,  
2626                         FullName
, FullClass
,  
2627                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2629                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2633                 if ( FetchLabelTypeResource((Widget
) w
,  
2634                         FullName
, FullClass
,  
2635                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2637                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2641                 if ( FetchDimensionResource((Widget
) w
,  
2642                         FullName
, FullClass
,  
2643                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2645                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2649                 if ( FetchXmStringResource((Widget
) w
,  
2650                         FullName
, FullClass
,  
2651                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2653                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2656             case RXmStringTable
: 
2657                 if ( FetchXmStringTableResource((Widget
) w
, 
2658                          FullName
, FullClass
, 
2659                          ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
, 
2660                          &AStringTable
, &TableSize
) ) { 
2661                     XtVaSetValues((Widget
) w
,  
2662                          XmNitems
, (XtPointer
) AStringTable
,  
2663                          XmNitemCount
, TableSize
, NULL
); 
2667                 if ( FetchKeySymResource((Widget
) w
,  
2668                         FullName
, FullClass
,  
2669                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2671                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2675                 if ( FetchStringResource((Widget
) w
,  
2676                         FullName
, FullClass
,  
2677                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2679                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2683                 if ( FetchPixmapResource((Widget
) w
,  
2684                         FullName
, FullClass
,  
2685                         ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
,  
2687                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
,  
2689                     if ( strcmp(ResourceMirror
[i
].Name
, XmNlabelPixmap
) == 0 ) 
2690                         w
->combobox
.ConvertBitmapToPixmap 
= True
; 
2692                         w
->combobox
.ConvertBitmapToPixmapInsensitive 
= True
; 
2696                 if ( FetchXmFontListResource((Widget
) w
, 
2697                        FullName
, FullClass
, 
2698                        ResourceMirror
[i
].Name
, ResourceMirror
[i
].Class
, 
2700                     XtVaSetValues((Widget
) w
, ResourceMirror
[i
].Name
, 
2705 } /* InitMirrorResources */ 
2707 /* -------------------------------------------------------------------- 
2708  * Wandelt ein 1-Bit tiefes Bitmap in ein n-Bit tiefes Pixmap um, dass 
2709  * die gleiche Tiefe besitzt, wie der Bildschirm, auf dem das Pixmap 
2710  * spaeter erscheinen soll. 
2712 static Pixmap 
BitmapToPixmap(XmComboBoxWidget w
,  
2713                            String Resource
, GC ColorGC
) 
2715     Pixmap       LabelPixmap
, LabelBitmap
; 
2716     Display      
*display 
= XtDisplay(w
); 
2719     unsigned int PixW
, PixH
, PixBW
, PixDepth
; 
2721     XtVaGetValues(w
->combobox
.LabelCtrl
, Resource
, &LabelBitmap
, NULL
); 
2722     XGetGeometry(display
, LabelBitmap
, &root
,  
2723                  &PixX
, &PixY
, &PixW
, &PixH
, &PixBW
, &PixDepth
); 
2724     LabelPixmap 
= XCreatePixmap( 
2725                         display
, RootWindowOfScreen(XtScreen(w
)),  
2727                         (w
->combobox
.LabelCtrl
)->core
.depth
); 
2728     XCopyPlane(display
, LabelBitmap
, LabelPixmap
,  
2729                ColorGC
, 0, 0, PixW
, PixH
, 0, 0, 1); 
2730     XtVaSetValues(w
->combobox
.LabelCtrl
, Resource
, LabelPixmap
, NULL
); 
2731     XFreePixmap(display
, LabelBitmap
); 
2733 } /* BitmapToPixmap */ 
2735 /* -------------------------------------------------------------------- 
2736  * Alles initialisieren, sobald das Widget eingerichtet wird. Das sagt 
2737  * sich hier so einfach, ist es aber *definitiv* nicht!!!! 
2739 static void Initialize(Widget request
, XmComboBoxWidget newW
,  
2740                        ArgList wargs
, Cardinal 
*ArgCount
) 
2742     Dimension    width
, height
, dummy
; 
2748  * Da zu allem Ueberfluss die einzelnen Instanzen einer XmComboBox 
2749  * auf verschiedenen Displays auftauchen koennen, wird hier: 
2750  * 1. pro Widget ein eigener Cursor erzeugt (benoetigt fuer die Liste) 
2751  * 2. pro Widget (hier = pro Applikation) die benoetigte Action-Routine 
2752  * registiert. Doppelte Registrierung macht dem Toolkit nichts aus, da es 
2753  * dann eine evtl. aeltere Definition loescht. 
2755     XtAppAddActions(XtWidgetToApplicationContext((Widget
) newW
),  
2756                         actions
, XtNumber(actions
)); 
2758 /* Allgemeine Initialisierungen... */ 
2759     newW
->combobox
.ConvertBitmapToPixmap            
= False
; 
2760     newW
->combobox
.ConvertBitmapToPixmapInsensitive 
= False
; 
2762     newW
->combobox
.LastSelection                    
= 0; 
2764     newW
->combobox
.InInit                           
= True
; 
2767  * Das folgende Problem mit der Kontrolle, ob sich das Widget absolut auf 
2768  * dem Bildschirm verschoben hat, trifft uns nur, wenn die Liste nicht 
2769  * dauernd auf dem Bildschirm erscheint: 
2770  * Lass' dich benachrichtigen, sobald dieses Widget in irgendeiner 
2771  * Form bewegt wird -- und sei es nur, dass das gesamte Applikations- 
2772  * fenster umhergeschoben wurde. Um die Benachrichtigung ueberhaupt 
2773  * zu erreichen, ist es erforderlich, sich benachrichtigen zu lassen,  
2774  * sobald die naechste Shell (oder ein Nachkomme) im Widget-Instanzen- 
2775  * Baum verschoben wurde. 
2777     if ( !newW
->combobox
.StaticList 
) { 
2779         while ( !XtIsSubclass(w
, shellWidgetClass
) ) 
2781         newW
->combobox
.MyNextShell 
= w
; 
2782         XtAddEventHandler(w
,  
2783                           StructureNotifyMask 
| FocusChangeMask
,  
2784                           False
, (XtEventHandler
) ShellCallback
,  
2788 /* Richte nun alle zu diesem Widget gehoerenden Kinder ein, als da 
2790  * 1 x editierbares Eingabefeld 
2791  * 1 x ein Pfeil nach unten 
2792  * 1 x ein Schriftfeld 
2794     newW
->combobox
.EditCtrl 
= XtVaCreateManagedWidget( 
2795         "edit", xmTextFieldWidgetClass
, (Widget
) newW
, 
2796         XmNverifyBell
, False
,  
2798     XtAddCallback(newW
->combobox
.EditCtrl
,  
2799                   XmNlosingFocusCallback
,  
2800                   (XtCallbackProc
) EditFocusCallback
, NULL
); 
2801     XtAddCallback(newW
->combobox
.EditCtrl
,  
2802                   XmNmodifyVerifyCallback
,  
2803                   (XtCallbackProc
) EditVerifyCallback
, NULL
); 
2804     XtAddCallback(newW
->combobox
.EditCtrl
,  
2805                   XmNvalueChangedCallback
,  
2806                   (XtCallbackProc
) EditChangedCallback
, NULL
); 
2807     XtAddCallback(newW
->combobox
.EditCtrl
,  
2809                   (XtCallbackProc
) HelpCallback
,  
2811     XtAddCallback(newW
->combobox
.EditCtrl
,  
2812                   XmNactivateCallback
,  
2813                   (XtCallbackProc
) ActivateCallback
,  
2815     if ( newW
->combobox
.Editable 
) 
2816         XtAddCallback(newW
->combobox
.EditCtrl
,  
2817                       XmNmotionVerifyCallback
,  
2818                       (XtCallbackProc
) MotionVerifyCallback
,  
2820 /* Neue Translations fuer das Eingabefeld aufnehmen */ 
2821     XtOverrideTranslations(newW
->combobox
.EditCtrl
,  
2822                            NewEditTranslations
); 
2823     if ( !newW
->combobox
.Editable 
) { 
2824         XtOverrideTranslations(newW
->combobox
.EditCtrl
,  
2825                                NewEditTranslationsNE
); 
2826         XtVaSetValues(newW
->combobox
.EditCtrl
,  
2827                       XmNcursorPositionVisible
, False
, NULL
); 
2830     XtOverrideTranslations(newW
->combobox
.EditCtrl
,  
2831                            NewListTranslations
); /* Btn2Dwn aus! */ 
2835     newW
->combobox
.ArrowCtrl 
= XtVaCreateManagedWidget( 
2836         "arrow", xmArrowButtonWidgetClass
, (Widget
) newW
,  
2837         XmNarrowDirection
,     XmARROW_DOWN
,  
2838         XmNtraversalOn
,        False
,  
2839         XmNnavigationType
,     XmNONE
, 
2841         XmNhighlightThickness
, 0,  
2843     XmRemoveTabGroup(newW
->combobox
.ArrowCtrl
); 
2844     if ( newW
->combobox
.StaticList 
) { 
2845         XtVaSetValues(newW
->combobox
.ArrowCtrl
,  
2846             XmNmappedWhenManaged
, False
, NULL
); 
2848         XtAddEventHandler(newW
->combobox
.ArrowCtrl
,  
2849                           EnterWindowMask 
| LeaveWindowMask
, 
2850                           False
, (XtEventHandler
) ArrowCrossingCallback
, 
2852         XtAddCallback(newW
->combobox
.ArrowCtrl
,  
2853                       XmNactivateCallback
,  
2854                       (XtCallbackProc
) ArrowCallback
, NULL
); 
2855         XtAddCallback(newW
->combobox
.ArrowCtrl
,  
2857                       (XtCallbackProc
) ArrowCallback
, NULL
); 
2858         XtAddCallback(newW
->combobox
.ArrowCtrl
,  
2860                       (XtCallbackProc
) HelpCallback
,  
2865     newW
->combobox
.LabelCtrl 
= XtVaCreateWidget( 
2866         "label", xmLabelWidgetClass
, (Widget
) newW
,  
2867         XmNstringDirection
, newW
->manager
.string_direction
,  
2869     if ( newW
->combobox
.ShowLabel 
) { 
2870         XtManageChild((Widget
) newW
->combobox
.LabelCtrl
); 
2871         XtAddCallback(newW
->combobox
.LabelCtrl
,  
2873                       (XtCallbackProc
) HelpCallback
,  
2878  * Zuerst noch die Shell erzeugen, die so einfach mir nichts dir nichts 
2879  * frei auf dem Bildschirm herumschweben kann und damit das Ausklappen 
2880  * der Liste erst ermoeglicht -- und uns allerhand Scherereien bereitet! 
2881  * War das ein bloeder Fehler in Motif 1.2! Diese Version vertraegt ab- 
2882  * solut keine ShellWidgetClass noch overrideShellWidgetClass!!!! Naja, 
2883  * mit einer vendorShellWidgetClass laesst sich aber exakt der gleiche 
2884  * Effekt erreichen. NEU: vor allem funktioniert dann endlich auch 
2886  * Noch neuer: Wenn die Liste dauerhaft angezeigt werden muss, entfaellt 
2887  * diese Shell zwangslaeufig. Dann ist das Listenfeld ein direktes Kind 
2890     if ( !newW
->combobox
.StaticList 
) { 
2891         newW
->combobox
.PopupShell 
= XtVaCreateWidget( 
2892             "combobox_shell", vendorShellWidgetClass
, (Widget
) newW
,  
2893             XmNoverrideRedirect
, True
, 
2894             XmNsaveUnder
,        False
, 
2895             XmNallowShellResize
, True
,  
2897         XtAddEventHandler(newW
->combobox
.PopupShell
,  
2898                           EnterWindowMask 
| LeaveWindowMask
,  
2899                           False
, (XtEventHandler
) OverrideShellCallback
,  
2903      * Sieht ja pervers nach einer Rekursion aus...daher: OBACHT! 
2905         newW
->combobox
.PopupShell 
= (Widget
) newW
; 
2909  * Nun kommt die Drop-Down-Liste an die Reihe. Die Liste muss dabei 
2910  * mit einer Convenience-Funktion erstellt werden, damit ein Rollbalken 
2911  * 'dran ist und das Ganze wird dann in eine Override-Shell gepackt. 
2912  * Nicht zu vergessen ist der XtManageChild-Aufruf, damit die Liste 
2913  * sofort nach dem Aufklappen der Shell sichtbar wird. 
2915     XtSetArg(args
[n
], XmNselectionPolicy
, newW
->combobox
.SelectionPolicy
); n
++; 
2917     if ( !newW
->combobox
.StaticList 
) { 
2919      * Es gibt halt so eine ganze Reihe von Einstellungen, die koennen nicht 
2920      * veraendert werden, wenn das Listenfeld nur bei Bedarf ausgeklappt wird. 
2922         XtSetArg(args
[n
], XmNhighlightThickness
, 0); n
++; 
2924     XtSetArg(args
[n
], XmNlistSizePolicy
,  
2925                       newW
->combobox
.ListSizePolicy
); n
++; 
2926     XtSetArg(args
[n
], XmNscrollBarDisplayPolicy
,  
2927                       newW
->combobox
.ScrollBarDisplayPolicy
); n
++; 
2929     XtSetArg(args
[n
], XmNautomaticSelection
,  
2930                       newW
->combobox
.AutomaticSelection
); n
++; 
2931     XtSetArg(args
[n
], XmNvisibleItemCount
,  
2932                       newW
->combobox
.VisibleItemCount
); n
++; 
2933     newW
->combobox
.ListCtrl 
= XmCreateScrolledList( 
2934         newW
->combobox
.PopupShell
, "list",   
2938  * Fuer den Fall, dass die Liste in einer eigenen Shell steckt und daher frei 
2939  * auf dem Bildschirm herumschweben kann, sollten wir sicherheitshalber die 
2940  * Tastaturbedienung (Fokus) abschalten, um Probleme zu vermeiden (jedenfalls 
2943     if ( !newW
->combobox
.StaticList 
) { 
2944         XtVaSetValues(newW
->combobox
.ListCtrl
,  
2945                       XmNtraversalOn
,  False
,  NULL
); 
2946         XtVaSetValues(XtParent(newW
->combobox
.ListCtrl
),  
2947                       XmNtraversalOn
, False
, NULL
); 
2949         if ( !newW
->combobox
.Editable 
) { 
2950             XtVaSetValues(XtParent(newW
->combobox
.ListCtrl
),  
2951                       XmNtraversalOn
, False
, NULL
); 
2952             XmRemoveTabGroup(newW
->combobox
.ListCtrl
); 
2956     XtManageChild(newW
->combobox
.ListCtrl
); 
2957     XtAddCallback(newW
->combobox
.ListCtrl
,  
2958                   XmNsingleSelectionCallback
,  
2959                   (XtCallbackProc
) ListSelectionCallback
,  
2961     XtAddCallback(newW
->combobox
.ListCtrl
,  
2962                   XmNbrowseSelectionCallback
,  
2963                   (XtCallbackProc
) ListSelectionCallback
,  
2965     XtAddCallback(newW
->combobox
.ListCtrl
,  
2966                   XmNdefaultActionCallback
,  
2967                   (XtCallbackProc
) ListDefaultActionCallback
,  
2969     XtAddCallback(newW
->combobox
.ListCtrl
,  
2971                   (XtCallbackProc
) HelpCallback
,  
2974     XtAddEventHandler(newW
->combobox
.ListCtrl
,  
2976                       False
, (XtEventHandler
) Button1UpInList
,  
2980     XtOverrideTranslations(newW
->combobox
.ListCtrl
,  
2981                            NewListTranslations
); 
2983     if ( newW
->combobox
.StaticList 
&& newW
->combobox
.Editable 
) 
2984         XtOverrideTranslations(newW
->combobox
.ListCtrl
,  
2985                                NewListTranslationsE
); 
2987 /* Jetzt wird es dann erst richtig spannend... Zuerst alle evtl. 
2988  * in der Resource-Datenbank abgelegten Resourcen an die Kinder 
2989  * weitergeben. Danach die uebergebenen Parameter ebenfalls an 
2990  * die Kinder weiterreichen und schliesslich das Layout ermitteln. 
2992     InitMirrorResources(newW
); 
2993     UpdateColors(newW
, -1); 
2994     SetValues(newW
, newW
, newW
, wargs
, ArgCount
); 
2996     if ( newW
->combobox
.ConvertBitmapToPixmap 
)  
2997         newW
->combobox
.LabelPixmap 
=  
2998             BitmapToPixmap(newW
, XmNlabelPixmap
,  
2999                        ((XmLabelRec 
*) newW
->combobox
.LabelCtrl
)-> 
3001     if ( newW
->combobox
.ConvertBitmapToPixmapInsensitive 
)  
3002         newW
->combobox
.LabelInsensitivePixmap 
=  
3003             BitmapToPixmap(newW
, XmNlabelInsensitivePixmap
,  
3004                        ((XmLabelRec 
*) newW
->combobox
.LabelCtrl
)-> 
3005                          label
.insensitive_GC
); 
3007     DefaultGeometry(newW
, &width
, &height
, &dummy
, &dummy
); 
3008     if ( newW
->core
.width 
== 0 ) 
3009         newW
->core
.width  
= width
; 
3010     if ( newW
->core
.height 
== 0 ) 
3011         newW
->core
.height 
= height
; 
3014  * Falls wir keine Fontliste besitzen, dann nehmen wir die von 
3015  * dem Eingabefeld... 
3017     if ( newW
->combobox
.Font 
== NULL 
) { 
3018         XtVaGetValues(newW
->combobox
.EditCtrl
,  
3019                       XmNfontList
, &newW
->combobox
.Font
, NULL
); 
3020         XtVaSetValues(newW
->combobox
.ListCtrl
,  
3021                       XmNfontList
, newW
->combobox
.Font
, NULL
); 
3023         XtVaSetValues(newW
->combobox
.ListCtrl
,  
3024                       XmNfontList
, newW
->combobox
.Font
, NULL
); 
3025         XtVaSetValues(newW
->combobox
.EditCtrl
,  
3026                       XmNfontList
, newW
->combobox
.Font
, NULL
); 
3030  * Initialisiere alle Statusflaggen, die mit diesem unseligen Focus- 
3031  * problem zu tun haben... 
3033     newW
->combobox
.ListVisible          
= False
; 
3034     newW
->combobox
.IgnoreFocusOut       
= False
; 
3035     newW
->combobox
.PendingFocusOut      
= False
; 
3036     newW
->combobox
.PendingOverrideInOut 
= False
; 
3038     newW
->combobox
.PassVerification 
= False
; 
3041  * Jooa... bei der OSF pennen die wohl komplett?! Zusammen mit Form- 
3042  * Widgets gibt das wohl immer Aerger...daher hier ein DoLayout() 
3043  * aufrufen, damit Eingabefeld und Pfeil sowie das Listenfeld an der  
3044  * richtigen Stelle sitzen! 
3048  * Endlich fertig mit der Initialisierung. Das hier ist aber auch 
3049  * wirklich viel Arbeit fuer so ein Widget! 
3051     newW
->combobox
.InInit 
= False
; 
3054 /* -------------------------------------------------------------------- 
3055  * Diese Funktionen bitte nur im aeussersten Notfall benutzen, da sie 
3056  * die Abstraktion dieser neuen Klasse umgehen und Informationen ueber 
3057  * den internen Aufbau voraussetzen. 
3059 Widget 
XmComboBoxGetEditWidget(Widget w
) 
3061     return ((XmComboBoxWidget
) w
)->combobox
.EditCtrl
; 
3062 } /* XmComboBoxGetEditWidget */ 
3064 Widget 
XmComboBoxGetListWidget(Widget w
) 
3066     return ((XmComboBoxWidget
) w
)->combobox
.ListCtrl
; 
3067 } /* XmComboBoxGetListWidget */ 
3069 Widget 
XmComboBoxGetLabelWidget(Widget w
) 
3071     return ((XmComboBoxWidget
) w
)->combobox
.LabelCtrl
; 
3072 } /* XmComboBoxGetLabelWidget */ 
3075 /* -------------------------------------------------------------------- 
3076  * Sobald sich im Listenfeld Eintraege veraenderten, sei es, dass sie 
3077  * geloescht wurden, sei es, dass sie veraendert wurden, so muss hier 
3078  * gegebenenfalls auch der Text im Eingabefeld angepasst werden. 
3079  * Letzteres betrifft aber nur Combo-Boxen mit nicht editierbarem 
3080  * Eingabefeld. In jedem Fall wird aber bei jeder Combo-Box-Type in 
3081  * dem Fall, dass ein Eintrag geloescht wird, der darauffolgende 
3082  * Eintrag markiert. Eigentlich ist dieses nur eine nette Geste 
3083  * gegenueber dem Benutzer... 
3086  *   w              Combo-Box-Widget 
3087  *   Index          Index auf denjenigen Eintrag der sich geaendert 
3088  *                  hat, oder der geloescht wurde. 
3089  *   Deleted        Zeigt an, ob der Eintrag geloescht wurde (True) 
3090  *                  oder sich nur veraenderte (False) 
3092 static int UpdateComboBox(XmComboBoxWidget w
, int Index
, Boolean Deleted
) 
3094     int OldIndex
, ItemCount
; 
3096     OldIndex 
= XmComboBoxGetSelectedPos((Widget
) w
); 
3097     if ( OldIndex 
== Index 
) { 
3098 /* Es betrifft den Eintrag, der auch momentan ausgewaehlt ist. 
3099  * Sollte er geloescht werden, so nimm' (soweit vorhanden) den 
3100  * naechsten Eintrag, wurde er ausgetauscht, so lass ihn ausge- 
3104             XtVaGetValues(w
->combobox
.ListCtrl
,  
3105                           XmNitemCount
, &ItemCount
, NULL
); 
3106             if ( ItemCount 
!= 0 ) { 
3107                 if ( Index 
>= ItemCount 
) Index 
= ItemCount
; 
3108                 /* Markieren des Eintrags, ohne jedoch jetzt schon 
3109                  * den Eintrag in die Eingabezeile zu kopieren. 
3111                 SetSelectionPos(w
, Index
, False
); 
3115 /* Das Problem betrifft uns nur bei nicht editierbaren Combo-Boxen 
3116  * im vollen Umfang. Denn dann muss auch der Text im Eingabefeld 
3117  * veraendert werden. 
3119     if ( !w
->combobox
.Editable 
) { 
3120         TransferToEditCtrl(w
, Index
, False
); 
3124 } /* UpdateComboBox */ 
3127 /* -------------------------------------------------------------------- 
3128  * Die Eintragsposition finden, an der der Eintrag sortiert stehen 
3129  * muesste. Naja, es wurde ja 'mal langsam Zeit, diese Routine etwas 
3130  * aufzupolieren, damit sie schneller wird. 
3132 static int FindSortedItemPos(XmComboBoxWidget w
, XmString item
) 
3134     Widget                          ListBox 
= w
->combobox
.ListCtrl
; 
3135     XmStringTable                   Items
; 
3136     int                             ItemCount
, index
, Left
, Right
, Result
; 
3137     char                            *pItemText
, *pCompareText
; 
3139     XmComboBoxSortingCallbackStruct data
; 
3141     XtVaGetValues(ListBox
, XmNitems
,     &Items
,  
3142                            XmNitemCount
, &ItemCount
, NULL
); 
3143     if ( ItemCount 
== 0 ) return 1; 
3146      * Moechte das Programm die Kontrolle ueber den Sortiervorgang 
3147      * uebernehmen? Dann bereite alles vor... 
3149     ExternSort 
= XtHasCallbacks((Widget
) w
, XmNsortingCallback
) ==  
3152         data
.reason    
= XmCR_SORTING
; 
3154         data
.operation 
= XmOP_INIT
; 
3156         XtCallCallbacks((Widget
) w
, XmNsortingCallback
, (XtPointer
) &data
); 
3158         XmStringGetLtoR(item
, XmSTRING_DEFAULT_CHARSET
, &pCompareText
); 
3160     Left 
= 0; Right 
= ItemCount 
- 1;     
3162         index 
= (Left 
+ Right
) / 2; 
3164             data
.operation 
= XmOP_COMPARE
; 
3165             data
.item      
= Items
[index
]; 
3167             XtCallCallbacks((Widget
) w
, XmNsortingCallback
, (XtPointer
) &data
); 
3168             Result 
= data
.result
; 
3170             XmStringGetLtoR(Items
[index
], XmSTRING_DEFAULT_CHARSET
, &pItemText
); 
3171             Result 
= strcmp(pCompareText
, pItemText
); 
3174         if      ( Result 
< 0 ) Right 
= index 
- 1; 
3175         else if ( Result 
> 0 ) Left  
= index 
+ 1; 
3176     } while ( (Result 
!= 0) && (Left 
<= Right
) ); 
3179      * Nach Gebrauch wieder alles aufraeumen (bei einer externen Sortierung 
3180      * muss das das Programm uebernehmen!) 
3183         data
.operation 
= XmOP_DONE
; 
3184         XtCallCallbacks((Widget
) w
, XmNsortingCallback
, (XtPointer
) &data
); 
3186         XtFree(pCompareText
); 
3189         return index 
+ 1; /* Beachte, dass Indizes mit 1 beginnen! */ 
3191         return index 
+ 2; /* Beachte, dass Indizes mit 1 beginnen! */ 
3192 } /* FindSortedItemPos */ 
3194 /* -------------------------------------------------------------------- 
3195  * Kontrolliere, ob es sich ueberhaupt um eine Combo-Box (bzw. einen 
3196  * hypothetischen Nachkommen) handelt -- ansonsten mecker kraeftig 
3199  *   True, falls wir hier ein falsches Widget untergejubelt bekommen! 
3201 static Boolean 
CheckComboBox(Widget w
, char *pFuncName
) 
3206 #if (XmVersion >= 2000) 
3207     return False
; /* temporary workaround */ 
3209     if ( XmIsComboBox(w
) ) return False
; 
3210     pWName 
= XrmQuarkToString(w
->core
.xrm_name
); 
3212 "Warning: %s called on widget named %s beeing \ 
3213 not a descendant of class XmComboBox!",  
3218 } /* CheckComboBox */ 
3220 /* -------------------------------------------------------------------- 
3221  * Saemtliche Interface-Routinen zur Combo-Box 
3223 /* Zunaechst alles fuer die Listbox */ 
3224 #define ListBox (((XmComboBoxWidget) w)->combobox.ListCtrl) 
3225 #define EditBox (((XmComboBoxWidget) w)->combobox.EditCtrl) 
3226 #define ComboBox ((XmComboBoxWidget) w) 
3229  * So angepasst, dass bei doppelt auftretenden Eintraegen, der 
3230  * alte Eintrag weiterhin markiert bleibt. Diese Massnahme soll 
3231  * eigentlich nur verhindern, dass zufaellig zwei Eintraege 
3232  * markiert sind, falls nach der Anwahl eines Eintrages ein zweiter 
3233  * gleichlautender Eintrag hinzugefuegt wurde. 
3234  * Was hier die reine Lehre (oder war das die Leere?) anbetrifft: 
3235  * in einer Combo-Box sollten sich sowieso nie gleichlautende 
3236  * Eintraege befinden, da sie dort unsinnig sind und den Benutzer 
3239 void    XmComboBoxAddItem(Widget w
, XmString item
, int pos
) 
3241     int OldIndex 
= XmComboBoxGetSelectedPos(w
); 
3243     if ( CheckComboBox(w
, "XmComboBoxAddItem") ) return; 
3244     if ( ComboBox
->combobox
.Sorted 
) 
3245         pos 
= FindSortedItemPos(ComboBox
, item
); 
3246     XmListAddItem(ListBox
, item
, pos
); 
3247     if ( OldIndex 
!= XmComboBoxGetSelectedPos(w
) ) 
3248         /* Hier SetSelectionPos() statt XmComboBoxSelectPos(), 
3249          * da der Text nicht in das Eingabefeld uebertragen werden 
3252         SetSelectionPos(ComboBox
, OldIndex
, False
); 
3253 } /* XmComboBoxAddItem */ 
3255  * Hier gilt das bereits oben gesagte (siehe XmComboBoxAddItem). 
3256  * Bei sortierten Listboxen wird die Sortierung beim Gebrauch dieser 
3257  * Funktion zerstoert! 
3259 void    XmComboBoxAddItems(Widget w
, XmString 
*items
, int item_count
, int pos
) 
3261     int OldIndex 
= XmComboBoxGetSelectedPos(w
); 
3263     if ( CheckComboBox(w
, "XmComboBoxAddItems") ) return; 
3264     XmListAddItems(ListBox
, items
, item_count
, pos
); 
3265     if ( OldIndex 
!= XmComboBoxGetSelectedPos(w
) ) 
3266         /* Siehe Anmerkung in XmComboBoxAddItem */ 
3267         SetSelectionPos(ComboBox
, OldIndex
, False
); 
3268 } /* XmComboBoxAddItems */ 
3270 void    XmComboBoxAddItemUnselected(Widget w
, XmString item
, int pos
) 
3271 { XmListAddItemUnselected(ListBox
, item
, pos
); } 
3274  * Da bei den folgenden Routinen jeweils ein oder mehrere Eintraege 
3275  * geloescht oder veraendert werden, muss gegebenefalls das Eingabe- 
3276  * feld bei nicht editierbaren Combo-Boxen auf Vordermann gebracht 
3279 void    XmComboBoxDeleteItem(Widget w
, XmString item
) 
3281     int Index 
= XmListItemPos(ListBox
, item
); 
3283     if ( CheckComboBox(w
, "XmComboBoxDeleteItem") ) return; 
3284     if ( Index 
) XmComboBoxDeletePos(w
, Index
); 
3285 } /* XmComboBoxDeleteItem */ 
3287 void    XmComboBoxDeleteItems(Widget w
, XmString 
*items
, int item_count
) 
3291     if ( CheckComboBox(w
, "XmComboBoxDeleteItems") ) return; 
3292     for ( i 
= 0; i 
< item_count
; i
++ ) 
3293         XmListDeleteItem(w
, items
[i
]); 
3294 } /* XmComboBoxDeleteItems */ 
3296 void    XmComboBoxDeletePos(Widget w
, int pos
) 
3298     int OldIndex 
= XmComboBoxGetSelectedPos(w
); 
3300     if ( CheckComboBox(w
, "XmComboBoxDeletePos") ) return; 
3301     XmListDeletePos(ListBox
, pos
); 
3302     if ( pos 
== OldIndex 
) UpdateComboBox(ComboBox
, pos
, True
); 
3303 } /* XmComboBoxDeletePos */ 
3305 void    XmComboBoxDeleteItemsPos(Widget w
, int item_count
, int pos
) 
3309     if ( CheckComboBox(w
, "XmComboBoxDeleteItemsPos") ) return; 
3310     for ( i 
= 0; i 
< item_count
; i
++ ) 
3311         XmComboBoxDeletePos(w
, pos
++); 
3312 } /* XmComboBoxDeleteItemsPos */ 
3314 void    XmComboBoxDeleteAllItems(Widget w
) 
3316     if ( CheckComboBox(w
, "XmComboBoxAllDeleteItems") ) return; 
3317     XmListDeleteAllItems(ListBox
); 
3318     UpdateComboBox(ComboBox
, 0, True
); 
3319 } /* XmComboBoxDeleteAllItems */ 
3322  * Werden Eintraege ausgetauscht, so heisst es fuer uns, auch hierbei 
3323  * auf der Hut zu sein. 
3325 void    XmComboBoxReplaceItems(Widget w
, XmString 
*old_items
, int item_count
, XmString 
*new_items
) 
3327     if ( CheckComboBox(w
, "XmComboBoxReplaceItems") ) return; 
3328     XmListReplaceItems(ListBox
, old_items
, item_count
, new_items
); 
3329     UpdateComboBox(ComboBox
, XmComboBoxGetSelectedPos(w
), False
); 
3330 } /* XmComboBoxReplaceItems */ 
3332 void    XmComboBoxReplaceItemsPos(Widget w
, XmString 
*new_items
, int item_count
, int position
) 
3334     int OldIndex 
= XmComboBoxGetSelectedPos(w
); 
3336     if ( CheckComboBox(w
, "XmComboBoxReplaceItemsPos") ) return; 
3337     XmListReplaceItemsPos(ListBox
, new_items
, item_count
, position
); 
3338     if ( (OldIndex 
>= position
) && (OldIndex 
< position 
+ item_count
) ) 
3339         UpdateComboBox(ComboBox
, OldIndex
, False
); 
3340 } /* XmComboBoxReplaceItemsPos */ 
3342 Boolean 
XmComboBoxItemExists(Widget w
, XmString item
) 
3344     if ( CheckComboBox(w
, "XmComboBoxItemExists") ) return False
; 
3345     return XmListItemExists(ListBox
, item
); 
3346 } /* XmComboBoxItemExists */ 
3348 int     XmComboBoxItemPos(Widget w
, XmString item
) 
3350     if ( CheckComboBox(w
, "XmComboBoxItemPos") ) return 0; 
3351     return XmListItemPos(ListBox
, item
); 
3352 } /* XmComboBoxItemPos */ 
3354 Boolean 
XmComboBoxGetMatchPos(Widget w
, XmString item
, int **pos_list
, int *pos_count
) 
3356     if ( CheckComboBox(w
, "XmComboBoxGetMatchPos") ) return False
; 
3357     return XmListGetMatchPos(ListBox
, item
, pos_list
, pos_count
); 
3358 } /* XmComboBoxGetMatchPos */ 
3361  * Sobald ein anderer Eintrag in der Listbox ausgewaehlt werden soll, 
3362  * muessen wir hier helfend eingreifen. 
3364 void    XmComboBoxSelectPos(Widget w
, int pos
, Boolean notify
) 
3368     if ( CheckComboBox(w
, "XmComboBoxSelectPos") ) return; 
3369     index 
= SetSelectionPos(ComboBox
, pos
, notify
); 
3370     if ( index 
) TransferToEditCtrl(ComboBox
, index
, False
); 
3371 } /* XmComboBoxSelectPos */ 
3374  * dto. analog zu XmComboBoxSelectPos, nur statt des Index wird der 
3375  * Eintragstext angegeben, um einen Eintrag in der Listbox zu 
3378 void    XmComboBoxSelectItem(Widget w
, XmString item
, Boolean notify
) 
3382     if ( CheckComboBox(w
, "XmComboBoxSelectItem") ) return; 
3383     XmListSelectItem(ListBox
, item
, notify
); 
3384     index 
= SetSelectionPos(ComboBox
, XmComboBoxGetSelectedPos(w
), False
); 
3385     if ( index 
) TransferToEditCtrl(ComboBox
, index
, False
); 
3386 } /* XmComboBoxSelectItem */ 
3389  * Geaendert gegenueber dem ListBox-Pendant! Da in einer Combo-Box die 
3390  * Liste nur maximal einen ausgewaehlten Eintrag besitzt, macht die 
3391  * 'alte' Funktionalitaet von XmListGetSelectedPos ziemlich wenig Sinn. 
3392  * Die neue Routine liefert statt dessen direkt den Index des aus- 
3393  * gewaehlten Eintrages oder 0 zurueck. 
3395 int     XmComboBoxGetSelectedPos(Widget w
) 
3397     int *SelectionList
, SelectionCount
, SelectionIndex
; 
3399     if ( CheckComboBox(w
, "XmComboBoxGetSelectedPos") ) return 0; 
3400     if ( XmListGetSelectedPos(ListBox
, 
3401                               &SelectionList
, &SelectionCount
) ) { 
3402         SelectionIndex 
= *SelectionList
; 
3403         XtFree((char *)SelectionList
); 
3404     } else SelectionIndex 
= 0; 
3405     return SelectionIndex
; 
3406 } /* XmComboBoxGetSelectedPos */ 
3410 void    XmComboBoxClearSelection(Widget w
, Time time
) 
3412     XmTextFieldClearSelection(EditBox
, time
); 
3413 } /* XmComboBoxClearSelection */ 
3415 Boolean 
XmComboBoxCopy(Widget w
, Time time
) 
3417     return XmTextFieldCopy(EditBox
, time
); 
3418 } /* XmComboBoxCopy */ 
3420 Boolean 
XmComboBoxCut(Widget w
, Time time
) 
3422     return XmTextFieldCut(EditBox
, time
); 
3423 } /* XmComboBoxCut */ 
3425 XmTextPosition 
XmComboBoxGetInsertionPosition(Widget w
) 
3427     return XmTextFieldGetInsertionPosition(EditBox
); 
3428 } /* XmComboBoxGetInsertionPosition */ 
3430 XmTextPosition 
XmComboBoxGetLastPosition(Widget w
) 
3432     return XmTextFieldGetLastPosition(EditBox
); 
3433 } /* XmComboBoxGetLastPosition */ 
3435 int     XmComboBoxGetMaxLength(Widget w
) 
3437     return XmTextFieldGetMaxLength(EditBox
); 
3438 } /* XmComboBoxGetMaxLength */ 
3440 char *  XmComboBoxGetSelection(Widget w
) 
3442     return XmTextFieldGetSelection(EditBox
); 
3443 } /* XmComboBoxGetSelection */ 
3445 Boolean 
XmComboBoxGetSelectionPosition(Widget w
, XmTextPosition 
*left
,  
3446                                        XmTextPosition 
*right
) 
3448     return XmTextFieldGetSelectionPosition(EditBox
, left
, right
); 
3449 } /* XmComboBoxGetSelectionPosition */ 
3451 char *  XmComboBoxGetString(Widget w
) 
3453     return XmTextFieldGetString(EditBox
); 
3454 } /* XmComboBoxGetString */ 
3456 void    XmComboBoxInsert(Widget w
, XmTextPosition position
, char *value
) 
3458     XmTextFieldInsert(EditBox
, position
, value
); 
3459 } /* XmComboBoxInsert */ 
3461 Boolean 
XmComboBoxPaste(Widget w
) 
3463     return XmTextFieldPaste(EditBox
); 
3464 } /* XmComboBoxPaste */ 
3466 Boolean 
XmComboBoxRemove(Widget w
) 
3468     return XmTextFieldRemove(EditBox
); 
3469 } /* XmComboBoxRemove */ 
3471 void    XmComboBoxReplace(Widget w
, XmTextPosition from_pos
,  
3472                           XmTextPosition to_pos
, char *value
) 
3474     XmTextFieldReplace(EditBox
, from_pos
, to_pos
, value
); 
3475 } /* XmComboBoxReplace */ 
3477 void    XmComboBoxSetAddMode(Widget w
, Boolean state
) 
3479     XmTextFieldSetAddMode(EditBox
, state
); 
3480 } /* XmComboBoxSetAddMode */ 
3482 void    XmComboBoxSetHighlight(Widget w
, XmTextPosition left
,  
3483                                XmTextPosition right
, XmHighlightMode mode
) 
3485     XmTextFieldSetHighlight(EditBox
, left
, right
, mode
); 
3486 } /* XmComboBoxSetHighlight */ 
3488 void    XmComboBoxSetInsertionPosition(Widget w
, XmTextPosition position
) 
3490     XmTextFieldSetInsertionPosition(EditBox
, position
); 
3491 } /* XmComboBoxSetInsertionPosition */ 
3493 void    XmComboBoxSetMaxLength(Widget w
, int max_length
) 
3495     XmTextFieldSetMaxLength(EditBox
, max_length
); 
3496 } /* XmComboBoxSetMaxLength */ 
3498 void    XmComboBoxSetSelection(Widget w
, XmTextPosition first
,  
3499                                XmTextPosition last
, Time time
) 
3501     XmTextFieldSetSelection(EditBox
, first
, last
, time
); 
3502 } /* XmComboBoxSetSelection */ 
3504 void    XmComboBoxSetString(Widget w
, char *value
) 
3506 /* Liebe OSF...ihr ^&*#%$*&)*(@$(*^(*&%# habt doch einen ziemlich gemeinen 
3507  * Fehler in XmTextFieldSetString() drin... wenn man einen leeren String 
3508  * (also "") angiebt, gibt's nur noch Aerger, wenn man spaeter wieder an 
3509  * den Inhalt des Eingabefeldes heranwill. 
3511     if ( (value 
== NULL
) || (*value 
== 0) ) 
3512         XtVaSetValues(w
, XmNvalue
, "", NULL
); 
3514         XmTextFieldSetString(EditBox
, value
); 
3515 } /* XmComboBoxSetString */ 
3517 void    XmComboBoxShowPosition(Widget w
, XmTextPosition position
) 
3519     XmTextFieldShowPosition(EditBox
, position
); 
3520 } /* XmComboBoxShowPosition */ 
3523  * Loescht einen evtl. noch ausgewaehlten Eintrag in einer Combo Box,  
3524  * wenn diese eine SelectionPolicy von XmSINGLE_SELECT hat. 
3526 void XmComboBoxClearItemSelection(Widget w
) 
3530     if ( CheckComboBox(w
, "XmComboBoxClearItemSelection") ) return; 
3533      * Wenn bereits kein Eintrag markiert ist, dann loeschen wir nur noch 
3534      * eben das Eingabefeld. 
3536     index 
= XmComboBoxGetSelectedPos(w
); 
3538         XmComboBoxSetString(w
, ""); 
3541      * Ansonsten aktuellen Eintrag entsorgen (wie bei der Methode wipe-out) 
3543         TransferToEditCtrl(ComboBox
, 0, True
); 
3544         CallSelectionCBL(ComboBox
, NULL
); 
3546 } /* XmComboBoxClearItemSelection */ 
3548 /* Die Drop-Down-Liste ein oder ausklappen */ 
3549 void    XmComboBoxShowList(Widget w
) 
3551     if ( CheckComboBox(w
, "XmComboBoxShowList") ) return; 
3552     ShowHideDropDownList((XmComboBoxWidget
) w
, NULL
, False
); 
3553 } /* XmComboBoxShowList */ 
3555 void    XmComboBoxHideList(Widget w
) 
3557     if ( CheckComboBox(w
, "XmComboBoxHideList") ) return; 
3558     ShowHideDropDownList((XmComboBoxWidget
) w
, NULL
, True
); 
3559 } /* XmComboBoxShowList */ 
3562  * Naja, ich komm' ja doch nicht um diese olle Funktion herum... 
3564 Widget 
XmCreateComboBox(Widget parent
, String name
, ArgList arglist
, 
3567     return XtCreateWidget(name
, xmComboBoxWidgetClass
, parent
, 
3569 } /* XmCreateComboBox */ 
3571 /* Ende von ComboBox.c */ 
3573 #endif /* XmVersion < 2000 */