1/*
2 * ComboBox.c - Das schon lange schmerzlich vermisste Combo-Box-
3 *              Widget -- nun endlich auf fuer Motif!
4 *
5 * Version 1.32a -- 04.10.95
6 *
7 * Letzte Modifikation:
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
39 *               behaupten!
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-
57 *               Kinds erreicht.
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-
62 *               gegeben.
63 *               ESC-Behandlung implementiert.
64 *               Spiegel-Ressourcen-Initialisierung aus Ressourcen-Daten-
65 *               bank implementiert.
66 *               Weitergabe von neu gesetzten Farben an die Kinder
67 *               implementiert.
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
72 *
73 * (c) 1993, 1994, 1995 Harald Albrecht
74 * Institut fuer Geometrie und Praktische Mathematik
75 * RWTH Aachen, Germany
76 * albrecht@igpm.rwth-aachen.de
77 *
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.
82 *
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.
87 *
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.
92 *
93 */
94#ifdef __VMS
95/* vms_x_fix.h should be included before any of the X11/Motif headers */
96#include <wx/vms_x_fix.h>
97#undef XtDisplay
98#undef XtScreen
99#undef XtWindow
100#undef XtIsRealized
101#undef XtParent
102#undef XtClass
103#endif
104
105/* get XmVersion definition */
106#include <Xm/Xm.h>
107
108#if (XmVersion < 2000)
109
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....
118	    */
119#include <Xmu/Converters.h>
120#else
121#include <X11/Xmu/Converters.h>
122#endif
123#include <Xm/ArrowB.h>
124#include <Xm/TextF.h>
125#include <Xm/List.h>
126#include <Xm/LabelP.h>
127
128#include <string.h>
129#include <ctype.h> /* define toupper */
130#include "combop.h"
131
132#include <stdio.h>
133
134/* --- Systemspezifische Definitionen */
135#if defined(VMS)
136#define strcasecmp(s1, s2) strcmp(s1, s2)
137#elif defined(__EMX__)
138#define strcasecmp stricmp
139#endif
140
141/* --- sonstiger Quark */
142/* #ifdef DEBUG */
143#if 0
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);
147#else
148#define LOG(p1)
149#define LOG2(p1, p2)
150#define LOG3(p1, p2, p3)
151#endif
152
153/* ---------------------------------------------------------------------------
154 * Resourcen-Liste...
155 * Hier werden diejenigen Resourcen definiert, die von "aussen" - also  fuer
156 * den Programmierer oder Anwender - benutzbar und veraenderbar sind.
157 *
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
165 *			Widgetinstanz
166 * Defaultwert-Type     Typ des Defaultwertes
167 * Defaultwert		(normalerweise) Zeiger auf den Defaultwert
168 */
169#define offset(field) XtOffsetOf(XmComboBoxRec, field)
170static XtResource resources[] = {
171    { /* Eingabefeld kann veraendert werden, oder aber es sind nur
172       * die Vorgaben aus der Liste auswaehlbar.
173       */
174	XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean),
175	offset(combobox.Editable), XmRString, "False"
176    },
177    { /* Liste wird automatisch sortiert -- wie konnten die bei
178       * der OSF denn SOETWAS nur vergessen ??
179       */
180	XmNsorted, XmCSorted, XmRBoolean, sizeof(Boolean),
181	offset(combobox.Sorted), XmRString, "False"
182    },
183    { /* externe Sortierreihenfolge */
184	XmNsortingCallback, XmCSortingCallback, XmRCallback,
185	sizeof(XtCallbackList),
186	offset(combobox.SortingCBL), XmRCallback, NULL
187    },
188    { /* Anzahl auf einmal sichtbarer Eintraege in der Liste (ent-
189       * spricht damit der Listenhoehe.
190       */
191	XmNvisibleItemCount, XmCVisibleItemCount, XmRInt, sizeof(int),
192	offset(combobox.VisibleItemCount), XmRImmediate, (caddr_t) 8
193    },
194    { /* Fuer das Eingabefeld sowie die Liste verwandte Fonts */
195	XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
196	offset(combobox.Font), XmRImmediate, NULL
197    },
198    { /* Rueckruf bei Anwahl */
199	XmNselectionCallback, XmCSelectionCallback, XmRCallback,
200	sizeof(XtCallbackList),
201	offset(combobox.SelectionCBL), XmRCallback, NULL
202    },
203    { /* Gegenteil zum vorherigen Callback! */
204	XmNunselectionCallback, XmCUnselectionCallback, XmRCallback,
205	sizeof(XtCallbackList),
206	offset(combobox.UnselectionCBL), XmRCallback, NULL
207    },
208    { /* Doppelklick in der Liste */
209	XmNdefaultActionCallback, XmCCallback, XmRCallback,
210	sizeof(XtCallbackList),
211	offset(combobox.DefaultActionCBL), XmRCallback, NULL
212    },
213    { /* Rueckruf bei Liste ausklappen/verstecken */
214	XmNdropDownCallback, XmCDropDownCallback, XmRCallback,
215	sizeof(XtCallbackList),
216	offset(combobox.DropDownCBL), XmRCallback, NULL
217    },
218    { /* Eingabe abchecken... */
219	XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
220	sizeof(XtCallbackList),
221	offset(combobox.ModifyVerifyCBL), XmRCallback, NULL
222    },
223    {
224	XmNvalueChangedCallback, XmCCallback, XmRCallback,
225	sizeof(XtCallbackList),
226	offset(combobox.ValueChangedCBL), XmRCallback, NULL
227    },
228    {
229	XmNactivateCallback, XmCCallback, XmRCallback,
230	sizeof(XtCallbackList),
231	offset(combobox.ActivateCBL), XmRCallback, NULL
232    },
233    {
234	XmNmotionVerifyCallback, XmCCallback, XmRCallback,
235	sizeof(XtCallbackList),
236	offset(combobox.MotionVerifyCBL), XmRCallback, NULL
237    },
238    { /* Verhalten der ausgeklappten Liste bei Focus-Out */
239	XmNpersistentDropDown, XmCPersistentDropDown, XmRBoolean,
240	sizeof(Boolean),
241	offset(combobox.Persistent), XmRString, "False"
242    },
243    { /* Wie verhaelt sich der Window-Manager? */
244	XmNtwmHandlingOn, XmCTwmHandlingOn, XmRBoolean, sizeof(Boolean),
245	offset(combobox.TwmHandlingOn), XmRString, "False"
246    },
247    { /* Label anzeigen oder nicht? */
248	XmNshowLabel, XmCShowLabel, XmRBoolean, sizeof(Boolean),
249	offset(combobox.ShowLabel), XmRString, "False"
250    },
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
255    },
256    { /* Neue Voreinstellung bzgl. des Randes */
257	XmNborderWidth, XmCBorderWidth, XmRDimension, sizeof(Dimension),
258	offset(core.border_width), XmRImmediate, (caddr_t) 0
259    },
260    { /* welcher Cursor soll in der Dropdown-Liste benutzt werden? */
261	XmNdropDownCursor, XmCDropDownCursor, XmRCursor, sizeof(Cursor),
262	offset(combobox.ArrowCursor), XmRString, "center_ptr"
263    },
264    { /* wie lassen sich Eintraege auswaehlen? */
265	XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy, sizeof(unsigned char),
266	offset(combobox.SelectionPolicy), XmRImmediate, (caddr_t) XmBROWSE_SELECT
267    },
268    { /* Wann werden die Callbacks aufgerufen? */
269	XmNautomaticSelection, XmCAutomaticSelection, XmRBoolean, sizeof(Boolean),
270	offset(combobox.AutomaticSelection), XmRString, "False"
271    },
272    { /* erscheint die Liste staendig? */
273	XmNstaticList, XmCStaticList, XmRBoolean, sizeof(Boolean),
274	offset(combobox.StaticList), XmRString, "False"
275    },
276    {
277    	XmNscrollBarDisplayPolicy, XmCScrollBarDisplayPolicy, XmRScrollBarDisplayPolicy, sizeof(unsigned char),
278    	offset(combobox.ScrollBarDisplayPolicy), XmRImmediate, (caddr_t) XmAS_NEEDED
279    },
280    {
281        XmNlistSizePolicy, XmCListSizePolicy, XmRListSizePolicy, sizeof(unsigned char),
282        offset(combobox.ListSizePolicy), XmRImmediate, (caddr_t) XmVARIABLE
283    },
284    {
285        XmNsquareArrow, XmCSquareArrow, XmRBoolean, sizeof(Boolean),
286        offset(combobox.SquareArrow), XmRString, "False"
287    },
288    {
289        XmNarrowSpacingOn, XmCArrowSpacingOn, XmRBoolean, sizeof(Boolean),
290        offset(combobox.ArrowSpacingOn), XmRString, "True"
291    },
292#ifndef DONT_LOOK_IN_THE_MIRROR
293    /* Mirror-Ressourcen, Adressen sind ungueltig!!!! */
294    {
295	XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
296	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
297    },
298    {
299	XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int),
300	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
301    },
302    {
303	XmNcolumns, XmCColumns, XmRShort, sizeof(short),
304	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
305    },
306    {
307	XmNcursorPosition, XmCCursorPosition, XmRTextPosition, sizeof(XmTextPosition),
308	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
309    },
310    {
311	XmNitemCount, XmCItemCount, XmRInt, sizeof(int),
312	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
313    },
314    {
315	XmNitems, XmCItems, XmRXmStringTable, sizeof(XmStringTable),
316	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
317    },
318    {
319	XmNlabelFontList, XmCLabelFontList, XmRFontList, sizeof(XmFontList),
320	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
321    },
322    {
323	XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, XmRPixmap, sizeof(Pixmap),
324	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
325    },
326    {
327	XmNlabelMarginBottom, XmCLabelMarginBottom, XmRDimension, sizeof(Dimension),
328	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
329    },
330    {
331	XmNlabelMarginHeight, XmCLabelMarginHeight, XmRDimension, sizeof(Dimension),
332	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
333    },
334    {
335	XmNlabelMarginLeft, XmCLabelMarginLeft, XmRDimension, sizeof(Dimension),
336	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
337    },
338    {
339	XmNlabelMarginRight, XmCLabelMarginRight, XmRDimension, sizeof(Dimension),
340	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
341    },
342    {
343	XmNlabelMarginTop, XmCLabelMarginTop, XmRDimension, sizeof(Dimension),
344	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
345    },
346    {
347	XmNlabelMarginWidth, XmCLabelMarginWidth, XmRDimension, sizeof(Dimension),
348	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
349    },
350    {
351	XmNlabelPixmap, XmCLabelPixmap, XmRPixmap, sizeof(Pixmap),
352	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
353    },
354    {
355	XmNlabelString, XmCLabelString, XmRString, sizeof(XmString),
356	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
357    },
358    {
359	XmNlabelType, XmCLabelType, XmRLabelType, sizeof(unsigned char),
360	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
361    },
362    {
363	XmNlistMarginHeight, XmCListMarginHeight, XmRDimension, sizeof(Dimension),
364	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
365    },
366    {
367	XmNlistMarginWidth, XmCListMarginWidth, XmRDimension, sizeof(Dimension),
368	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
369    },
370    {
371	XmNlistSpacing, XmCListSpacing, XmRDimension, sizeof(Dimension),
372	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
373    },
374    {
375	XmNmarginHeight, XmCMarginHeight, XmRDimension, sizeof(Dimension),
376	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
377    },
378    {
379	XmNmarginWidth, XmCMarginWidth, XmRDimension, sizeof(Dimension),
380	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
381    },
382    {
383	XmNmaxLength, XmCMaxLength, XmRInt, sizeof(int),
384	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
385    },
386    {
387	XmNselectThreshold, XmCSelectThreshold, XmRInt, sizeof(int),
388	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
389    },
390    {
391	XmNstringDirection, XmCStringDirection, XmRStringDirection, sizeof(XmStringDirection),
392	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
393    },
394    {
395	XmNtopItemPosition, XmCTopItemPosition, XmRInt, sizeof(int),
396	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
397    },
398    {
399	XmNvalue, XmCValue, XmRString, sizeof(String),
400	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
401    },
402    {
403	XmNvalue, XmCValue, XmRInt, sizeof(int),
404	offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
405    },
406#endif
407}; /* resources[] */
408
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.
413 */
414static void             Initialize     (Widget, XmComboBoxWidget, ArgList,
415			                Cardinal *);
416static void             Destroy        (XmComboBoxWidget);
417static void             Resize         (XmComboBoxWidget);
418static Boolean          SetValues      (XmComboBoxWidget, XmComboBoxWidget,
419                                        XmComboBoxWidget, ArgList, Cardinal *);
420static void             GetValuesAlmost(XmComboBoxWidget, ArgList, Cardinal *);
421static XtGeometryResult QueryGeometry  (XmComboBoxWidget, XtWidgetGeometry *,
422			                XtWidgetGeometry *);
423static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
424                                        XtWidgetGeometry *);
425static void		ClassInit      ();
426static void             Realize        (XmComboBoxWidget, Mask *,
427                                        XSetWindowAttributes *);
428/* ---------------------------------------------------------------------------
429 * diverse restliche Prototypen... naja, hier halt etwas mager! Hierbei
430 */
431static void ShowHideDropDownList       (XmComboBoxWidget w, XEvent *event,
432                                        Boolean Show);
433static void ShellCallback              (Widget w, XtPointer cbw,
434                                        XEvent *event, Boolean *ContDispatch);
435static void DoLayout                   (XmComboBoxWidget w);
436/* --------------------------------------------------------------------
437 * Klassen-Definition
438 */
439XmComboBoxClassRec 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,
450    /* actions		  	    */	NULL,
451    /* num_actions	  	    */	0,
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,
461    /* expose		  	    */	NULL,
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,
472    /* extension          	    */	NULL
473    },
474    { /*** composite-Klasse ***/
475    /* geometry_manager		    */	(XtGeometryHandler) GeometryManager,
476    /* change_managed		    */	XtInheritChangeManaged,
477    /* insert_child		    */	XtInheritInsertChild,
478    /* delete_child		    */	XtInheritDeleteChild,
479    /* extension		    */	NULL
480    },
481    { /*** constraint-Klasse ***/
482    /* resources		    */	NULL,
483    /* num_resources		    */	0,
484    /* constraint_size		    */	sizeof(XmManagerConstraintPart),
485    /* initialize		    */	NULL,
486    /* destroy			    */	NULL,
487    /* set_values		    */	NULL,
488    /* extension		    */	NULL
489    },
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,
497    /* extension		    */	NULL
498    },
499    { /*** combobox-Klasse ***/
500    /*				    */	0
501    }
502}; /* xmComboBoxClassRec */
503WidgetClass xmComboBoxWidgetClass = (WidgetClass) &xmComboBoxClassRec;
504
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!
510 */
511static 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()"
522    ;
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".
528 */
529static char newEditTranslationsNE[] =
530    "<Key>osfDelete:	    ComboBox-Manager(wipe-out)		\n\
531     <Key>osfBeginLine:	    ComboBox-Manager(top)		\n\
532     <Key>osfEndLine:	    ComboBox-Manager(bottom)		  "
533    ;
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!
539 */
540#ifdef NODRAGNDROP
541static char newListTranslations[] =
542    "<Btn2Down>:	    ComboBox-Manager(no-operation)	";
543#endif
544static char newListTranslationsE[] =
545    "<Key>osfPageUp:	    ComboBox-Manager(page-up)		\n\
546     <Key>osfPageDown:	    ComboBox-Manager(page-down)		";
547
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.
557 */
558static void CBoxManager(Widget w, XEvent *event, String *params,
559                        Cardinal *num_params);
560
561static XtActionsRec actions[] = {
562    { "ComboBox-Manager", CBoxManager },
563    { NULL, NULL }
564}; /* actions */
565
566
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.
571 */
572static XtTranslations NewEditTranslations, NewEditTranslationsNE,
573#ifdef NODRAGNDROP
574                      NewListTranslations,
575#endif
576                      NewListTranslationsE;
577
578static XtConvertArgRec ConverterScreenConvertArg[] = {
579    { XtBaseOffset, (XtPointer) XtOffset(Widget, core.screen),
580      sizeof(Screen *) }
581};
582
583static void ClassInit()
584{
585    NewEditTranslations =
586	    XtParseTranslationTable(newEditTranslations);
587    NewEditTranslationsNE =
588	    XtParseTranslationTable(newEditTranslationsNE);
589#ifdef NODRAGNDROP
590    NewListTranslations =
591	    XtParseTranslationTable(newListTranslations);
592#endif
593    NewListTranslationsE =
594	    XtParseTranslationTable(newListTranslationsE);
595    XtAddConverter(XtRString, XtRBitmap,
596                   XmuCvtStringToBitmap,
597		   ConverterScreenConvertArg,
598                   XtNumber(ConverterScreenConvertArg));
599} /* ClassInit */
600
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!).
613 */
614static void Realize(XmComboBoxWidget w, Mask *ValueMask,
615                    XSetWindowAttributes *Attributes)
616{
617    /*
618     * Also: wenn die Liste staendig sichtbar ist, dann zuerst noch einmal
619     * das Layout berechnen. Sonst wird vorne und hinten 'was abgeschnitten.
620     */
621    if ( w->combobox.StaticList )
622	DoLayout(w);
623    (*w->core.widget_class->core_class.superclass->core_class.realize)
624	((Widget) w, ValueMask, Attributes);
625} /* Realize */
626
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.
640 *
641 * Parameter:
642 *   w			Diejenige Combo-Box, fuer die wir dasjenige
643 *			Fenster des Window-Managers ermitteln sollen,
644 *			dass direkt unterhalb des Root-Fensters liegt.
645 * Ergebnis:
646 *   besagtes zu suchendes Fenster, dass die Dekoration enthaelt (hoffentlich
647 *   nur echte Bruesseler Spitze!)
648 */
649static Window GetDecorationWindow(XmComboBoxWidget w)
650{
651    Window       Root, Parent, AWindow;
652    Window       *Children;
653    unsigned int NumChildren;
654
655    Parent = XtWindow((Widget) w);
656    /* Suche nach dem Dekorationsfenster des Window-Managers */
657    do {
658	AWindow = Parent;
659	XQueryTree(XtDisplay((Widget) w), AWindow,
660		   &Root, &Parent, &Children, &NumChildren);
661	XFree((char *) Children);
662    } while ( Parent != Root );
663    return AWindow;
664} /* GetDecorationWindow */
665
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.
672 */
673static void Destroy(XmComboBoxWidget w)
674{
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,
687		      (XtPointer) w);
688} /* Destroy */
689
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).
697 */
698static void CheckDropDownOffset(XmComboBoxWidget w)
699{
700    if ( w->combobox.DropDownOffset < 0 ) {
701	XtWidgetGeometry ArrowGeom;
702
703	XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
704	w->combobox.DropDownOffset = ArrowGeom.width;
705    }
706} /* CheckDropDownOffset */
707
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.
717 */
718static void DefaultGeometry(XmComboBoxWidget w,
719                            Dimension *TotalWidth,
720			    Dimension *TotalHeight,
721			    Dimension *EditCtrlWidth,
722			    Dimension *LabelCtrlWidth)
723{
724    XtWidgetGeometry EditGeom, ArrowGeom, LabelGeom, ListGeom;
725
726    XtQueryGeometry(w->combobox.EditCtrl,  NULL, &EditGeom);
727    XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
728    XtQueryGeometry(w->combobox.LabelCtrl, NULL, &LabelGeom);
729
730    /*
731     * Soll die Pfeilschaltflaeche quadratisch, praktisch, gut sein?
732     */
733    if ( w->combobox.SquareArrow )
734        ArrowGeom.width = ArrowGeom.height;
735    else
736        ArrowGeom.width = (ArrowGeom.height * 4) / 5;
737
738    /*
739     * Zuerst einmal ein paar einfache Werte ermitteln und zurueckgeben...
740     */
741    *TotalHeight    = EditGeom.height;
742    *EditCtrlWidth  = EditGeom.width;
743    *LabelCtrlWidth = LabelGeom.width;
744
745    /*
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!
753     */
754    if ( w->combobox.StaticList ) {
755	/*
756	 * Beachte: Frage nicht die Listbox, sondern das ScrolledWindow,
757	 * in welchem die Liste eingebettet ist.
758	 */
759	CheckDropDownOffset(w);
760	XtQueryGeometry(XtParent(w->combobox.ListCtrl), NULL, &ListGeom);
761	if ( w->combobox.InInit ) {
762	    *TotalWidth = EditGeom.width;
763	} else {
764            if ( EditGeom.width < (Dimension)
765                                   (ListGeom.width + w->combobox.DropDownOffset) )
766		*TotalWidth = ListGeom.width + w->combobox.DropDownOffset;
767	    else
768		*TotalWidth = EditGeom.width;
769        }
770	*TotalHeight += ListGeom.height;
771    } else {
772	/*
773	 * Das Listenfeld interessiert uns hier nicht. Degegen sollte noch
774	 * die Breite fuer den Pfeil und ein evtl. Angstrasen beachtet
775	 * werden.
776	 */
777	*TotalWidth  = EditGeom.width + ArrowGeom.width;
778	if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
779	    *TotalWidth += ArrowGeom.width/2;
780    }
781
782    /*
783     * Vergiss nicht, auch noch ein evtl. sichtbares Schriftfeld zu berueck-
784     * sichtigen!
785     */
786    if ( w->combobox.ShowLabel )
787	*TotalWidth += LabelGeom.width;
788
789} /* DefaultGeometry */
790
791/* --------------------------------------------------------------------
792 * Anhand eines Widgets ermittele darueber die Screennummer desjenigen
793 * Screens, auf dem das Widget erscheint.
794 * Parameter:
795 *   w			betroffenes Widget.
796 * Ergebnis:
797 *   Nummer desjenigen Screens, auf dem das Widget angezeigt wird.
798 */
799static int WidgetToScreen(Widget w)
800{
801    Screen  *screen;
802    Display *display;
803    int     NumScreens, i;
804
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 )
809	    return i;
810    XtError("WidgetToScreen: data structures are destroyed.");
811    return 0; /* to avoid a compiler warning */
812} /* WidgetToScreen */
813
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.
818 */
819static void DoDropDownLayout(XmComboBoxWidget w)
820{
821    Position       abs_x, abs_y;
822    Dimension      ArrowWidth, ListWidth, ListHeight;
823    Dimension      ScreenHeight, LabelWidth;
824    XWindowChanges WindowChanges;
825
826    /*
827     * etwa nicht sichtbar ?!! Oder etwa immer sichtbar ?!!
828     * Dann sind wir jetzt sofort fertig.
829     */
830    if ( !w->combobox.ListVisible || w->combobox.StaticList ) return;
831    /*
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.
836     */
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;
845	abs_x     += LabelWidth;
846    }
847    if ( ListWidth < 20 ) ListWidth = 20;
848    XtVaGetValues(XtParent(w->combobox.ListCtrl), XmNheight, &ListHeight, NULL);
849    /*
850     * Hier ueberpruefen wir noch, ob die Liste unten aus dem Bildschirm
851     * herausfallen wuerde. In dem Fall klappen wir die Liste oberhalb des
852     * Eingabefeldes auf.
853     */
854    ScreenHeight = DisplayHeight(XtDisplay((Widget) w),
855                                 WidgetToScreen((Widget) w));
856    if ( abs_y + ListHeight + 2 > ScreenHeight ) {
857        int y;
858
859        y = ((int) abs_y) - ListHeight - w->core.height - 1;
860        if ( y < 0 ) y = 0;
861        abs_y = (Position) y;
862    }
863    XtConfigureWidget(w->combobox.PopupShell,
864		      abs_x, abs_y, ListWidth, ListHeight, 1);
865    /*
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().
870     */
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);
878    }
879} /* DoDropDownLayout */
880
881/* --------------------------------------------------------------------
882 * Naja... diese Routine scheint ja bereits zu einer Institution beim
883 * Schreiben von Composite-Widgets geworden zu sein.
884 *
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.
892 */
893static void DoLayout(XmComboBoxWidget w)
894{
895    Dimension        EditCtrlWidth, ArrowCtrlWidth, LabelCtrlWidth;
896    Dimension        ComboBoxHeight;
897    Dimension        BorderWidth;
898    Dimension        HighlightThickness;
899    Position         EditX;
900
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);
907
908    /*
909     * In Abhaengigkeit davon, ob die ComboBox editierbar ist und ob das
910     * Listenfeld staendig sichtbar sein soll, hier die Breite einzelner
911     * Widgets bestimmen.
912     */
913    if ( w->combobox.StaticList ) {
914	ComboBoxHeight = w->combobox.EditCtrl->core.height;
915	EditCtrlWidth  = w->core.width;
916    } else {
917	ComboBoxHeight = w->core.height;
918	EditCtrlWidth  = w->core.width - ArrowCtrlWidth;
919    	if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
920    	    EditCtrlWidth -= ArrowCtrlWidth/2;
921    }
922    /* Beruecksichtige noch ein evtl. ebenfalls anzuzeigendes Schriftfeld
923     * neben dem Eingabefeld.
924     */
925    if ( w->combobox.ShowLabel ) {
926	EditX          = LabelCtrlWidth;
927	EditCtrlWidth -= LabelCtrlWidth;
928    } else
929        EditX = 0;
930    if ( EditCtrlWidth < 20 ) EditCtrlWidth = 20;
931/* Plaziere nun das Eingabefeld... */
932    XtVaGetValues(w->combobox.EditCtrl,
933                  XmNborderWidth,        &BorderWidth,
934		  XmNhighlightThickness, &HighlightThickness,
935		  NULL);
936    XtConfigureWidget(w->combobox.EditCtrl,
937                      EditX, 0,
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,
944		      ArrowCtrlWidth,
945		      ComboBoxHeight - 2 * HighlightThickness,
946		      BorderWidth);
947/* ...und ggf. das Textlabel. */
948    if ( w->combobox.ShowLabel ) {
949	XtVaGetValues(w->combobox.LabelCtrl,
950		      XmNborderWidth, &BorderWidth,
951		      NULL);
952	XtConfigureWidget(w->combobox.LabelCtrl,
953	                  0, 0,
954			  LabelCtrlWidth, ComboBoxHeight,
955			  BorderWidth);
956    }
957/* Falls da noch die Liste herumgurkt... */
958    if ( w->combobox.StaticList ) {
959	Dimension Width, Height;
960
961	if ( w->core.height > ComboBoxHeight )
962	    Height = w->core.height - ComboBoxHeight;
963	else
964	    Height = 10;
965
966	if ( w->core.width > (Dimension)(ArrowCtrlWidth + EditX) )
967	    Width = w->core.width - ArrowCtrlWidth - EditX;
968	else
969	    Width = 10;
970
971	XtConfigureWidget(XtParent(w->combobox.ListCtrl),
972	    EditX + ArrowCtrlWidth, ComboBoxHeight, Width, Height, 0);
973    } else if ( w->combobox.ListVisible )
974	DoDropDownLayout(w);
975} /* DoLayout */
976
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.
988 * Parameter:
989 *   *Request	    Vom Vater vorgeschlagene Geometrie
990 * Ergebnis:
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.
994 */
995static XtGeometryResult QueryGeometry(XmComboBoxWidget w,
996                                      XtWidgetGeometry *Request,
997			              XtWidgetGeometry *Reply)
998{
999    XtGeometryResult result = XtGeometryYes;
1000    Dimension        minW, minH, editW, labelW;
1001
1002/* Elternteil will nichts weiter aendern, also ist uns das
1003 * recht so.
1004 */
1005    Request->request_mode &= CWWidth | CWHeight;
1006    if ( Request->request_mode == 0 ) return result;
1007
1008    DefaultGeometry(w, &minW, &minH, &editW, &labelW);
1009
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.)
1017 */
1018	    result               = XtGeometryAlmost;
1019	    Reply->width         = minW;
1020	    Reply->request_mode |= CWWidth;
1021	}
1022    }
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;
1029	}
1030    }
1031    return result;
1032} /* QueryGeometry */
1033
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.
1039 * Parameter:
1040 *   w		    Die bereits hinlaenglich bekannte Instanz dieses
1041 *		    Widgets
1042 */
1043static void Resize(XmComboBoxWidget w)
1044{
1045    DoLayout(w);
1046} /* Resize */
1047
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.)
1056 *
1057 * Parameter:
1058 *   w		    Die naechste Shell in Reichweite ueber unserer
1059 *		    Combo-Box.
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
1066 *		    mithoeren.
1067 */
1068static void ShellCallback(Widget w, XtPointer pClientData,
1069                          XEvent *event, Boolean *ContDispatch)
1070{
1071    XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1072
1073    switch ( event->type ) {
1074	case ConfigureNotify:
1075	case CirculateNotify:
1076	    DoDropDownLayout((XmComboBoxWidget) cbw);
1077	    break;
1078	case FocusOut:
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;
1086	    break;
1087	case UnmapNotify:
1088	    ShowHideDropDownList((XmComboBoxWidget) cbw,
1089	                         event, False);
1090	    break;
1091    }
1092    *ContDispatch = True;
1093} /* ShellCallback */
1094
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
1100 * bewegt wird.
1101 */
1102static void OverrideShellCallback(Widget w, XtPointer pClientData,
1103                                  XEvent *event, Boolean *ContDispatch)
1104
1105{
1106    XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1107    switch ( event->type ) {
1108        case EnterNotify:
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;
1115            break;
1116        case LeaveNotify:
1117            LOG("OverrideShellCallback: LeaveNotify\n");
1118	    if ( cbw->combobox.TwmHandlingOn )
1119              cbw->combobox.PendingOverrideInOut = True;
1120            break;
1121    }
1122} /* OverrideShellCallback */
1123
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
1137 * werden darf.
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!
1142 */
1143static void ArrowCrossingCallback(Widget w, XtPointer pClientData,
1144                               XEvent *event, Boolean *ContDispatch)
1145
1146{
1147    XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1148    switch ( event->type ) {
1149        case LeaveNotify:
1150	    LOG2("ArrowCrossingCallback: LeaveNotify, mode: %i\n",
1151	         event->xcrossing.mode);
1152            if ( event->xcrossing.mode == NotifyGrab )
1153                cbw->combobox.IgnoreFocusOut = True;
1154            else
1155                cbw->combobox.IgnoreFocusOut = False;
1156            break;
1157    }
1158} /* ArrowCrossingCallback */
1159
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.
1164 */
1165static void HelpCallback(Widget w, XtPointer cbw, XtPointer CallData)
1166{
1167    XtCallCallbacks((Widget) cbw, XmNhelpCallback, CallData);
1168} /* HelpCallback */
1169
1170/* --------------------------------------------------------------------
1171 * Wenn der Benutzer im Eingabefeld osfActivate drueckt, dann dieses
1172 * Ereignis offiziell bekanntgeben.
1173 */
1174static void ActivateCallback(Widget w, XtPointer cbw, XtPointer CallData)
1175{
1176    XtCallCallbacks((Widget) cbw, XmNactivateCallback, CallData);
1177} /* ActivateCallback */
1178
1179/* --------------------------------------------------------------------
1180 * Ein Kind moechte sein Groesse veraendern und fragt deshalb hier bei
1181 * uns an.
1182 * Parameter:
1183 *   w		    Naja...
1184 *   *Request	    Vorschlag des Kindes
1185 * Ergebnis:
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!).
1191 */
1192static XtGeometryResult GeometryManager(Widget w,
1193                                        XtWidgetGeometry *Request,
1194				        XtWidgetGeometry *Reply)
1195{
1196    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1197    XtGeometryResult Result = XtGeometryNo;
1198
1199    /*
1200     * Falls das Listenfeld statisch dargestellt wird, muessen wir seine
1201     * Wuensche doch beruecksichtigen. Was fuer ein Aufwand...
1202     */
1203    if ( (w == XtParent(cbw->combobox.ListCtrl)) && cbw->combobox.StaticList ) {
1204        Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth;
1205        XtWidgetGeometry MyRequest, YourReply, EditGeom;
1206
1207        XtQueryGeometry(cbw->combobox.EditCtrl, NULL, &EditGeom);
1208        DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
1209                             &EditWidth, &LabelWidth);
1210      	CheckDropDownOffset(cbw);
1211
1212        if ( Request->request_mode && CWWidth )
1213            if ( (Dimension)(LabelWidth + cbw->combobox.DropDownOffset +
1214                             Request->width) > TotalWidth )
1215                TotalWidth = LabelWidth + cbw->combobox.DropDownOffset +
1216                             Request->width;
1217
1218        if ( Request->request_mode && CWHeight )
1219            TotalHeight = EditGeom.height + Request->height;
1220    /*
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....
1226     */
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);
1235	}
1236	if ( Result == XtGeometryYes )
1237	    DoLayout(cbw);
1238    } else
1239    /*
1240     * Ansonsten darf nur noch das Schriftfeld Ansprueche anmelden.
1241     */
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;
1247
1248        if ( Request->request_mode & CWWidth ) {
1249            DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
1250                                 &EditWidth, &LabelWidth);
1251            TotalWidth = TotalWidth - LabelWidth +
1252                         Request->width;
1253
1254            MyRequest.request_mode = CWWidth;
1255            MyRequest.width        = TotalWidth;
1256            Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, NULL);
1257
1258            if ( Result == XtGeometryYes )
1259		DoLayout(cbw);
1260        }
1261    }
1262    return Result;
1263} /* GeometryManager */
1264
1265/* --------------------------------------------------------------------
1266 * Hier werden auf Wunsch diejenigen Farben, die bei der Combo-Box neu
1267 * gesetzt wurden, an alle Kinder weitergegeben.
1268 */
1269#define BOTTOMSHADOWCOLOR   0x0001
1270#define TOPSHADOWCOLOR	    0x0002
1271#define FOREGROUND	    0x0004
1272#define BACKGROUND	    0x0008
1273
1274static struct { String Resource; int Flag; }
1275       ColorResources[] = {
1276	   { XmNbottomShadowColor, BOTTOMSHADOWCOLOR },
1277	   { XmNtopShadowColor,    TOPSHADOWCOLOR    },
1278	   { XmNforeground,        FOREGROUND        },
1279	   { XmNbackground,        BACKGROUND        }
1280       };
1281
1282static int UpdateColors(XmComboBoxWidget w, int flags)
1283{
1284    Pixel  Color, White, Black, EditCol;
1285    int    i, size = XtNumber(ColorResources);
1286    Widget ScrolledWin, ScrollBar;
1287
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 )
1295                EditCol = White;
1296            else if ( ColorResources[i].Flag == FOREGROUND )
1297                EditCol = Black;
1298            else
1299                EditCol = Color;
1300	    XtVaGetValues((Widget) w, ColorResources[i].Resource, &Color,
1301	                  NULL);
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);
1316	}
1317
1318	return 1;
1319} /* UpdateColors */
1320
1321/* --------------------------------------------------------------------
1322 * Liste aller vorgespiegelten Resourcen, die automatisch verarbeitet
1323 * werden koennen, ohne weiter darueber nachdenken zu muessen...
1324 */
1325typedef enum  { EDITCTRL, LISTCTRL, LABELCTRL } CHILDCTRL;
1326typedef enum { RO, RW, RWS, RWL, RWI, RWIGNORE } aUniqueName;
1327typedef struct {
1328    String                    rsc;
1329    CHILDCTRL                 ctrl;
1330/*    enum { RO, RW, RWS, RWL, RWI, RWIGNORE } dir; */
1331    aUniqueName dir;
1332    /* nur lesen, lesen&schreiben, lesen&schreiben spezial,
1333       lesen&schreiben label, lesen&schreiben items */
1334} MIRROR;
1335
1336/* Alle mit !!! gekennzeichneten Eintraege werden auf die richtigen
1337 * Namen des entsprechenden Widgets umgesetzt.
1338 */
1339static 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  },
1347
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 },
1357
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 }, /* !!! */
1372};
1373
1374typedef struct {
1375    char *from, *to;
1376} TRANSFORMATION;
1377static TRANSFORMATION Transformations[] = {
1378    { XmNlabelMarginBottom, XmNmarginBottom },
1379    { XmNlabelMarginHeight, XmNmarginHeight },
1380    { XmNlabelMarginLeft,   XmNmarginLeft   },
1381    { XmNlabelMarginRight,  XmNmarginRight  },
1382    { XmNlabelMarginTop,    XmNmarginTop    },
1383    { XmNlabelMarginWidth,  XmNmarginWidth  },
1384    { XmNlabelFontList,     XmNfontList     },
1385};
1386
1387/* --------------------------------------------------------------------
1388 * Sobald irgendeine Resource veraendert wird, erfolgt der Aufruf
1389 * hierin als Benachrichtigung, einmal nach dem rechten zu sehen.
1390 * Parameter:
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
1401 * Ergebnis:
1402 *   True, falls Widget neu gezeichnet werden soll.
1403 */
1404static Boolean SetValues(XmComboBoxWidget current, XmComboBoxWidget req,
1405                         XmComboBoxWidget newW,
1406	                 ArgList args, Cardinal *NumArgs)
1407{
1408    Boolean Update = False;
1409    int i, j, MirrorSize = XtNumber(MirroredResources);
1410    int k, TransformationSize = XtNumber(Transformations);
1411    Arg arg;
1412    int Flags;
1413
1414/*
1415 * Alle Resourcen, die nicht mehr nach dem Erstellen der Widget-Instanz
1416 * veraendert werden koennen.
1417 */
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;
1425
1426/*
1427 * Kontrolliere nun alle Resourcen, die sich veraendert haben koennten
1428 * und gebe die neuen Einstellungen entsprechend weiter...
1429 *
1430 * Hat sich der Sensitive-Zustand veraendert? Dann muessen wir hier dafuer
1431 * sorgen, dass alle Kinder ebenfalls den neuen Zustand annehmen.
1432 */
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);
1440    }
1441/*
1442 * Die ScrollBarPolicy kann nur dann geaendert werden, wenn das Listenfeld
1443 * dauerhaft dargestellt wird.
1444 */
1445    if ( newW->combobox.ScrollBarDisplayPolicy !=
1446	 current->combobox.ScrollBarDisplayPolicy ) {
1447        if ( newW->combobox.StaticList )
1448            XtVaSetValues(newW->combobox.ListCtrl,
1449                          XmNscrollBarDisplayPolicy, newW->combobox.ScrollBarDisplayPolicy,
1450                          NULL);
1451        else
1452            XtWarning(
1453"XmComboBox: ScrollBarDisplayPolicy can not be changed when StaticList == False."
1454);
1455    }
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,
1461		      NULL);
1462	Update = True;
1463    }
1464    if ( current->combobox.AutomaticSelection !=
1465	 newW->combobox.AutomaticSelection ) {
1466	XtVaSetValues(newW->combobox.ListCtrl,
1467	              XmNautomaticSelection, newW->combobox.AutomaticSelection,
1468		      NULL);
1469    }
1470/*
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
1475 * benutzen ist.
1476 */
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);
1482    	Update = True;
1483    }
1484
1485    Flags = 0;
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; }
1495
1496
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);
1502   }
1503/* Hier werden die vorgespiegelten Resourcen verwaltet, die in
1504 * Wirklichkeit zu einem unserer Kinder gehoeren.
1505 */
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.
1509 */
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),
1519			&(args[i]), 1);
1520		    break;
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,
1525			                &(args[i]), 1);
1526		    }
1527		    break;
1528		case RWL: /* Transformation in andere Resource beim
1529		             Label-Widget */
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,
1535			                &arg, 1);
1536			    break;
1537			}
1538		    break;
1539		case RWIGNORE: /* Zugriff auf XmNitemCount */
1540		               /* Wird von XmNitems erledigt! */
1541		    break;
1542		case RWI: /* Zugriff auf XmNitems */
1543		    for ( k = 0; k < *NumArgs; k++ )
1544			if ( strcmp(args[k].name, XmNitemCount) == 0 ) {
1545			    Arg MyArgs[2];
1546
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,
1552			                args, 2);
1553			    /*XtVaSetValues(newW->combobox.ListCtrl,
1554			                  XmNitems,     args[i].value,
1555					  XmNitemCount, args[k].value,
1556					  NULL);*/
1557			    break;
1558			}
1559		    break;
1560		case RO:
1561		    break;
1562		} /* case write mode */
1563		goto ScanForNextResource;
1564	    } /* if entry found */
1565	} /* for every mirrored entry */
1566        ScanForNextResource: ;
1567    } /* for every Arg */
1568
1569    if ( (newW->combobox.SquareArrow != current->combobox.SquareArrow) ||
1570         (newW->combobox.ArrowSpacingOn != current->combobox.ArrowSpacingOn) ) {
1571        Update = False;
1572        DoLayout(newW);
1573    }
1574
1575    return Update;
1576} /* SetValues */
1577
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.
1584 * Parameter:
1585 *   w		    Widget-Instanz
1586 *   args	    Abgefragte Resourcen
1587 *   NumArgs	    Anzahl der abgefragten Resourcen
1588 */
1589static void GetValuesAlmost(XmComboBoxWidget w, ArgList args,
1590                            Cardinal *NumArgs)
1591{
1592    int i, j, MirrorSize = XtNumber(MirroredResources);
1593    int k, TransformationSize = XtNumber(Transformations);
1594    Arg arg;
1595
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.
1599 */
1600	for ( j = 0; j < MirrorSize; j++ ) {
1601	    if ( strcmp(args[i].name, MirroredResources[j].rsc) == 0 ) {
1602		switch ( MirroredResources[j].dir ) {
1603		case RO:
1604		case RW:
1605		case RWS:
1606		case RWI:
1607		    XtGetValues(MirroredResources[j].ctrl == LISTCTRL ?
1608			          w->combobox.ListCtrl :
1609				MirroredResources[j].ctrl == EDITCTRL ?
1610				  w->combobox.EditCtrl :
1611				  w->combobox.LabelCtrl,
1612			&(args[i]), 1);
1613		    break;
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,
1620			                (ArgList) &arg, 1);
1621			    break;
1622			}
1623		    break;
1624        case RWIGNORE:
1625            ;
1626		} /* case read mode */
1627	    } /* if entry found */
1628	} /* for every mirrored entry */
1629    } /* for every Arg */
1630} /* GetValuesAlmost */
1631
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.
1636 * Parameter:
1637 *   w		    Her Royal Majesty ComboBox
1638 *   Show	    True, falls anzuzeigen, andernfalls False
1639 */
1640static void ShowHideDropDownList(XmComboBoxWidget w, XEvent *event,
1641                                 Boolean Show)
1642{
1643    XmComboBoxDropDownCallbackStruct info;
1644
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;
1651	info.event  = event;
1652	XtCallCallbacks((Widget) w, XmNdropDownCallback,
1653	                (XtPointer) &info);
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;
1665	info.event  = event;
1666	XtCallCallbacks((Widget) w, XmNdropDownCallback,
1667	                (XtPointer) &info);
1668    }
1669} /* ShowHideDropDownList */
1670
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.
1681 */
1682static void ArrowCallback(Widget w, XtPointer pClientData,
1683                          XmAnyCallbackStruct *info)
1684{
1685    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1686
1687    switch ( info->reason ) {
1688	case XmCR_ARM:
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;
1693	    break;
1694	case XmCR_ACTIVATE:
1695	    XmProcessTraversal(cbw->combobox.EditCtrl, XmTRAVERSE_CURRENT);
1696	    ShowHideDropDownList(cbw, info->event,
1697	                         (Boolean)(!cbw->combobox.ListVisible));
1698	    break;
1699    }
1700} /* ArrowCallback */
1701
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
1709 * reagieren.
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.)
1723 */
1724static Boolean DelayedFocusOutWorkProc(XtPointer pClientData)
1725{
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 */
1735
1736static void EditFocusCallback(Widget w, XtPointer pClientData,
1737                              XmAnyCallbackStruct *info)
1738{
1739    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1740
1741    if ( cbw->combobox.StaticList ) return;
1742
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!
1755	     */
1756	    if ( info->event )
1757	        cbw->combobox.xevent = *info->event;
1758            cbw->combobox.WorkProcID = XtAppAddWorkProc(
1759	                     XtWidgetToApplicationContext((Widget) cbw),
1760                             (XtWorkProc) DelayedFocusOutWorkProc,
1761                             (XtPointer) cbw);
1762            cbw->combobox.PendingFocusOut = True;
1763        }
1764        cbw->combobox.PendingOverrideInOut = False;
1765    }
1766} /* EditFocusCallback */
1767
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.
1772 * Parameter:
1773 *   w		    Die Combo-Box (ueblicher Parameter)
1774 *   Index	    Index des neu zu markierenden Eintrages.
1775 *   Notify	    Schickt Mitteilung via Callback
1776 * Ergebnis:
1777 *   Index des markierten Eintrages oder 0, falls die Listbox leer
1778 *   war und deshalb auch kein Eintrag markiert werden konnte.
1779 */
1780static int SetSelectionPos(XmComboBoxWidget w, int Index, Boolean Notify)
1781{
1782    Widget ListBox = w->combobox.ListCtrl;
1783    int            ItemCount;      /* Anzahl Eintraege in Listbox   */
1784    int            TopItem, VisibleItems;
1785
1786    XtVaGetValues(ListBox, XmNitemCount,        &ItemCount,
1787			   XmNtopItemPosition,  &TopItem,
1788			   XmNvisibleItemCount, &VisibleItems,
1789	                   NULL);
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);
1798	return Index;
1799    } else
1800	return 0;
1801} /* SetSelectionPos */
1802
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.
1809 */
1810static void TransferToEditCtrl(XmComboBoxWidget w, int SelectionIndex,
1811                               Boolean MayWipeOut)
1812{
1813    Widget ListBox = w->combobox.ListCtrl;
1814    XmStringTable  Items;
1815    char           *pItemText;
1816
1817    XtVaGetValues(ListBox, XmNitems, &Items, NULL);
1818
1819    if ( MayWipeOut &&
1820         (SelectionIndex == w->combobox.LastSelection) &&
1821         (w->combobox.SelectionPolicy == XmSINGLE_SELECT) ) {
1822	SelectionIndex = 0;
1823    }
1824
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, "");
1830    } else {
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);
1837	    XtFree(pItemText);
1838	}
1839    }
1840    w->combobox.LastSelection = SelectionIndex;
1841} /* TransferToEditCtrl */
1842
1843/* --------------------------------------------------------------------
1844 * Alle registrierten Callbacks bei Anwahl eines neuen Eintrages in
1845 * der Listbox aktivieren.
1846 */
1847static void CallSelectionCBL(XmComboBoxWidget w, XEvent *Event)
1848{
1849    int index;
1850
1851    index  = XmComboBoxGetSelectedPos((Widget) w);
1852    /*
1853     * Wenn momentan KEIN Eintrag selektiert ist, dann rufe den neuen
1854     * XmNunselectionCallback auf!
1855     */
1856    if ( index == 0 ) {
1857	XmComboBoxUnselectionCallbackStruct info;
1858
1859	info.reason = XmCR_UNSELECT;
1860	info.event  = Event;
1861	XtCallCallbacks((Widget) w, XmNunselectionCallback, (XtPointer) &info);
1862    } else {
1863    /*
1864     * Ansonsten den ueblichen SelectionCallback!
1865     */
1866	XmComboBoxSelectionCallbackStruct info;
1867	XmStringTable                     Items;
1868
1869	info.reason = w->combobox.SelectionPolicy == XmSINGLE_SELECT ?
1870			    XmCR_SINGLE_SELECT : XmCR_BROWSE_SELECT;
1871	info.event  = Event;
1872	info.index  = index;
1873	XtVaGetValues(w->combobox.ListCtrl, XmNitems, &Items, NULL);
1874	info.value  = Items[info.index-1];
1875	XtCallCallbacks((Widget) w, XmNselectionCallback, (XtPointer) &info);
1876    }
1877} /* CallSelectionCBL */
1878
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!
1884 */
1885static void CBoxManager(Widget w, XEvent *Event, String *params,
1886                        Cardinal *num_params)
1887{
1888    XmComboBoxWidget cbw;
1889    Widget           ListBox;
1890    int              *SelectionList;
1891    int              SelectionCount;
1892    int              SelectionIndex; /* Wer denn nun markiert wird... */
1893    int              ItemCount;      /* Anzahl Eintraege in Listbox   */
1894    int		     VisibleItems;   /* Hoehe der Liste in Eintraegen */
1895    char             opt;
1896
1897    /*
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.
1901     */
1902    if ( XtClass(w) == xmListWidgetClass )
1903        cbw = (XmComboBoxWidget) XtParent(XtParent(w));
1904    else
1905        cbw = (XmComboBoxWidget) XtParent(w);
1906    ListBox = cbw->combobox.ListCtrl;
1907
1908    switch ( *(params[0]) ) {
1909/* --------------------------------------------------------------------
1910 * Klappe die Liste auf Wunsch des Benutzers aus oder wieder ein.
1911 */
1912    case 's': /* show-hide-list */
1913	ShowHideDropDownList(cbw, Event,
1914	                     (Boolean)(!cbw->combobox.ListVisible));
1915	break;
1916    case 'h': /* hide-list */
1917	ShowHideDropDownList(cbw, Event, False);
1918	break;
1919/* --------------------------------------------------------------------
1920 * Hier werden die Bewegungen in der Listbox behandelt.
1921 */
1922    case 'u': /* up                */
1923    case 'd': /* down              */
1924    case 't': /* top               */
1925    case 'b': /* bottom            */
1926    case 'p': /* page-up/page-down */
1927	opt = *(params[0]);
1928	XtVaGetValues(ListBox, XmNitemCount,        &ItemCount,
1929	                       XmNvisibleItemCount, &VisibleItems, NULL);
1930	if ( XmListGetSelectedPos(ListBox,
1931	                          &SelectionList, &SelectionCount) ) {
1932	    SelectionIndex = *SelectionList;
1933	    XtFree((char *)SelectionList);
1934	    switch ( opt ) {
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;
1941		          else
1942		              SelectionIndex += VisibleItems;
1943		          break;
1944	    }
1945	} else { /* momentan noch kein Eintrag in der Liste ausgewaehlt */
1946	    if ( opt == 'b' ) SelectionIndex = ItemCount;
1947	    else              SelectionIndex = 1; /* nun ersten Eintrag nehmen */
1948	}
1949	TransferToEditCtrl(cbw, SelectionIndex, False);
1950	CallSelectionCBL(cbw, Event);
1951	break;
1952/* --------------------------------------------------------------------
1953 * Der Benutzer hat die Eingabetaste gedrueckt oder einen Eintrag in
1954 * der Listbox angeklickt.
1955 */
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);
1965	} else {
1966	    if ( cbw->combobox.SelectionPolicy != XmSINGLE_SELECT )
1967		SelectionIndex = 1;
1968	    else
1969		SelectionIndex = 0;
1970	}
1971
1972	TransferToEditCtrl(cbw, SelectionIndex,
1973	    *(params[0]) == 'S');
1974	CallSelectionCBL(cbw, Event);
1975	ShowHideDropDownList(cbw, Event, (Boolean)
1976	                      (*(params[0]) == 'S' ? True : False));
1977	break;
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.
1984 */
1985    case 'c': /* Cancel */
1986	if ( cbw->combobox.ListVisible )
1987	    ShowHideDropDownList(cbw, Event, False);
1988	else
1989	    XtCallActionProc(cbw->combobox.EditCtrl,
1990	                     "process-cancel", Event, NULL, 0);
1991	break;
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.
1996 */
1997    case 'w': /* wipe */
1998	if ( cbw->combobox.SelectionPolicy == XmSINGLE_SELECT ) {
1999	    TransferToEditCtrl(cbw, 0, True);
2000	    CallSelectionCBL(cbw, Event);
2001	}
2002	break;
2003/* --------------------------------------------------------------------
2004 * Dummy-Operation
2005 */
2006    case 'n': /* no-operation */
2007        break;
2008    }
2009} /* CBoxManager */
2010
2011/* --------------------------------------------------------------------
2012 * Der Benutzer hat einen Eintrag in der Listbox angeklickt. Der Ein-
2013 * fachkeit halber wird einfach nur ein Druecken der Eingabetaste
2014 * simuliert.
2015 */
2016static void ListSelectionCallback(Widget w, XtPointer pClientData,
2017                                  XmAnyCallbackStruct *info)
2018{
2019    String           paramsMouse[1] = { "a" }, paramsKeyboard[1] = { "S" };
2020    Cardinal         NumParams = 1;
2021    XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
2022/*
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.
2027 */
2028    if ( info->event == NULL )
2029	CBoxManager(cbw->combobox.EditCtrl, info->event,
2030	            paramsKeyboard, &NumParams);
2031    else {
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);
2038    }
2039} /* ListSelectionCallback */
2040
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.
2046 */
2047static void ListDefaultActionCallback(Widget w, XtPointer pClientData,
2048                                      XmAnyCallbackStruct *OldInfo)
2049{
2050    XmComboBoxWidget                      cbw = (XmComboBoxWidget) pClientData;
2051    XmComboBoxDefaultActionCallbackStruct info;
2052    XmStringTable                         Items;
2053
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 */
2062
2063
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!!!
2073 */
2074static void Button1UpInList(Widget w, XtPointer pClientData,
2075                           XEvent *Event, Boolean *ContDispatch)
2076{
2077    XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
2078
2079    if ( Event->xbutton.button == Button1 ) {
2080	if ( cbw->combobox.AutomaticSelection )
2081	    ShowHideDropDownList(cbw, Event, False);
2082    }
2083} /* Button1UpInList */
2084
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.
2090 */
2091static void EditVerifyCallback(Widget w, XtPointer pClientData,
2092                               XmTextVerifyCallbackStruct *info)
2093{
2094    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2095
2096/*
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.)
2101 */
2102    if ( cbw->combobox.PassVerification ) {
2103	cbw->combobox.PassVerification = False;
2104	info->doit = True;
2105	return;
2106    }
2107/*
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
2110 * ausgeloest.
2111 */
2112    if ( !cbw->combobox.Editable ) {
2113	Widget         ListBox = cbw->combobox.ListCtrl;
2114	char           WarpCharLow, WarpCharHigh;
2115	XmString       Item;
2116	XmStringTable  Items;
2117	int            *SelectionList;
2118	int            SelectionCount;
2119	int            i, ItemCount, Start;
2120	char           *pItem;
2121	Boolean        Ignore;
2122
2123	info->doit = False;
2124	if ( (info->text         == NULL ) ||
2125	     (info->text->length == 0    ) ) return; /* Hoppala! */
2126/*
2127 * Nun aus dem Zeichen einen String (Motif-like) basteln und
2128 * in der Listbox danach auf die Suche gehen.
2129 */
2130        if ( info->text->length > 1 ) {
2131            /* Das ist nun endweder ein normaler Paste, oder aber
2132             * das Ergebnis einer Drag'n'Drop-Operation.
2133             */
2134            Item = XmStringCreateSimple(info->text->ptr);
2135            XmComboBoxSelectItem((Widget) cbw, Item, True);
2136            XmStringFree(Item);
2137        } else {
2138            /* Ansonsten soll nur eine Schnellsuche ausgefuehrt
2139             * werden, der entsprechende Buchstabe ist das einzige
2140             * Zeichen im dem Callback uebergebenen Text.
2141             */
2142	    WarpCharLow  = tolower(*(info->text->ptr));
2143	    WarpCharHigh = toupper(WarpCharLow);
2144
2145            XtVaGetValues(ListBox, XmNitemCount, &ItemCount,
2146    			           XmNitems,     &Items,
2147    	                           NULL);
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;
2155
2156    	    if ( i > ItemCount ) i = 1;
2157    	    Ignore = True;
2158    	    while ( i != Start || Ignore ) {
2159    	        Ignore = False;
2160    	        XmStringGetLtoR(Items[i-1], XmSTRING_DEFAULT_CHARSET,
2161    	                        &pItem);
2162    	        if ( (strchr(pItem, WarpCharLow ) == pItem) ||
2163    	             (strchr(pItem, WarpCharHigh) == pItem) ) {
2164    	            XtFree(pItem);
2165    		    TransferToEditCtrl(cbw, i, False);
2166    		    CallSelectionCBL(cbw, info->event);
2167    		    break;
2168    	        }
2169    	        XtFree(pItem);
2170    	        if ( ++i > ItemCount ) i = 1;
2171    	    }
2172    	}
2173    } else {
2174/*
2175 * Wenn das Eingabefeld editierbar ist, dann fragen wir ueber die Callbacks
2176 * nach, ob es genehm ist, den neuen Text einzufuegen.
2177 */
2178	XtCallCallbacks((Widget) cbw, XmNmodifyVerifyCallback,
2179	                (XtPointer) info);
2180    }
2181} /* EditVerifyCallback */
2182
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.
2189 */
2190static void EditChangedCallback(Widget w, XtPointer pClientDate,
2191                                XmAnyCallbackStruct *info)
2192{
2193    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2194    XmStringTable    Items;
2195    int              ItemCount, i;
2196    XmString         EditStr;
2197    String           EditLine;
2198
2199    /*
2200     * Zuerst nach einem passenden Eintrag zum Eingabefeld in der Liste
2201     * suchen...
2202     */
2203    XtVaGetValues(cbw->combobox.EditCtrl, XmNvalue, &EditLine, NULL);
2204    XtVaGetValues(cbw->combobox.ListCtrl,
2205                  XmNitemCount, &ItemCount,
2206		  XmNitems,     &Items,
2207		  NULL);
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);
2214	    break;
2215	}
2216    XmStringFree(EditStr);
2217    /*
2218     * Zum Abschluss noch den Callback aufrufen...
2219     */
2220    XtCallCallbacks((Widget) cbw, XmNvalueChangedCallback, (XtPointer) info);
2221} /* EditChangedCallback */
2222
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...
2227 */
2228static void MotionVerifyCallback(Widget w, XtPointer pClientDate,
2229                                 XmTextVerifyCallbackStruct *info)
2230{
2231    XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2232
2233    XtCallCallbacks((Widget) cbw, XmNmotionVerifyCallback, (XtPointer) info);
2234} /* MotionVerifyCallback */
2235
2236/* --------------------------------------------------------------------
2237 * Bastele einen vollstaendigen Namens- und Klassenbezeichner anhand
2238 * des angegebenen Widgets zusammen.
2239 */
2240static void MakeNameAndClass(Widget w, char *NameBuff, char *ClassBuff)
2241{
2242    Widget Parent = XtParent(w);
2243
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
2248	 * des Widgets.
2249	 */
2250	String AppName, AppClass;
2251	XtGetApplicationNameAndClass(
2252	    XtDisplayOfObject(w), &AppName, &AppClass);
2253	strcpy(NameBuff, AppName);
2254	strcpy(ClassBuff, AppClass);
2255    } else {
2256	/* Ansonsten sind wir noch mitten irgendwo in der Hierarchie
2257	 * und besorgen uns den Namen und die Klasse dieses Widgets
2258	 */
2259	strcat(NameBuff,  ".");
2260	strcat(NameBuff,  XtName(w));
2261	strcat(ClassBuff, ".");
2262	strcat(ClassBuff, ((CoreClassRec *) XtClass(w))->core_class.class_name);
2263    }
2264} /* MakeNameAndClass */
2265
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.
2270 */
2271static Boolean FetchResource(Widget w,
2272                             char *FullName, char *FullClass,
2273                             char *RscName, char *RscClass,
2274			     XrmValue *RscValue,
2275			     String   *RepresentationType)
2276{
2277    Boolean ok;
2278    char *EndOfName  = FullName  + strlen(FullName);
2279    char *EndOfClass = FullClass + strlen(FullClass);
2280
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;
2288    return ok;
2289} /* FetchResource */
2290
2291/* --------------------------------------------------------------------
2292 * Nun folgen diejenigen Routinen, mit denen die Konvertierung in das
2293 * gewuenschte Zielformat einer Resource moeglich ist.
2294 * Verfuegbar:
2295 *   String --> Int
2296 *   String --> Short
2297 *   String XmPIXMAP / XmSTRING --> unsigned char
2298 *   String --> Dimension
2299 *   String --> XmString
2300 *   String --> XmStringTable
2301 *   String --> XmFontList
2302 *   String --> Pixmap (genauer: Bitmap)
2303 *   String --> String
2304 *   String --> KeySym
2305 */
2306static Boolean FetchIntResource(Widget w,
2307                                char *FullName, char *FullClass,
2308                                char *RscName, char *RscClass,
2309			        int *pInt)
2310{
2311    XrmValue RscValue, RscDest;
2312    String   RepresentationType;
2313
2314    if ( FetchResource(w, FullName, FullClass,
2315                       RscName, RscClass,
2316		       &RscValue, &RepresentationType) ) {
2317	RscDest.size = sizeof(int);
2318	RscDest.addr = (caddr_t) pInt;
2319	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2320	                       XtRInt, &RscDest) )
2321	    return True;
2322    }
2323    return False;
2324} /* FetchIntResource */
2325
2326static Boolean FetchShortResource(Widget w,
2327                                char *FullName, char *FullClass,
2328                                char *RscName, char *RscClass,
2329			        short *pShort)
2330{
2331    XrmValue RscValue, RscDest;
2332    String   RepresentationType;
2333
2334    if ( FetchResource(w, FullName, FullClass,
2335                       RscName, RscClass,
2336		       &RscValue, &RepresentationType) ) {
2337	RscDest.size = sizeof(short);
2338	RscDest.addr = (caddr_t) pShort;
2339	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2340	                       XtRShort, &RscDest) )
2341	    return True;
2342    }
2343    return False;
2344} /* FetchShortResource */
2345
2346static Boolean FetchLabelTypeResource(Widget w,
2347                                char *FullName, char *FullClass,
2348                                char *RscName, char *RscClass,
2349			        unsigned char *pUChar)
2350{
2351    XrmValue RscValue;
2352    String   RepresentationType;
2353
2354    if ( FetchResource(w, FullName, FullClass,
2355                       RscName, RscClass,
2356		       &RscValue, &RepresentationType) ) {
2357	if ( strcasecmp((char *) RscValue.addr, "XmPIXMAP") == 0 )
2358	    *pUChar = XmPIXMAP;
2359	else
2360	    *pUChar = XmSTRING;
2361	return True;
2362   }
2363    return False;
2364} /* FetchLabelTypeResource */
2365
2366static Boolean FetchDimensionResource(Widget w,
2367                                char *FullName, char *FullClass,
2368                                char *RscName, char *RscClass,
2369			        Dimension *pDimension)
2370{
2371    XrmValue RscValue, RscDest;
2372    String   RepresentationType;
2373
2374    if ( FetchResource(w, FullName, FullClass,
2375                       RscName, RscClass,
2376		       &RscValue, &RepresentationType) ) {
2377	RscDest.size = sizeof(Dimension);
2378	RscDest.addr = (caddr_t) pDimension;
2379	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2380	                       XtRDimension, &RscDest) )
2381	    return True;
2382    }
2383    return False;
2384} /* FetchDimensionResource */
2385
2386static Boolean FetchStringResource(Widget w,
2387                                char *FullName, char *FullClass,
2388                                char *RscName, char *RscClass,
2389			        String *pString)
2390{
2391    XrmValue RscValue;
2392    String   RepresentationType;
2393
2394    if ( FetchResource(w, FullName, FullClass,
2395                       RscName, RscClass,
2396		       &RscValue, &RepresentationType) ) {
2397	*pString = (char *) RscValue.addr;
2398	return True;
2399    }
2400    return False;
2401} /* FetchStringResource */
2402
2403static Boolean FetchKeySymResource(Widget w,
2404                                char *FullName, char *FullClass,
2405                                char *RscName, char *RscClass,
2406			        KeySym *pKeySym)
2407{
2408    XrmValue RscValue, RscDest;
2409    String   RepresentationType;
2410
2411    if ( FetchResource(w, FullName, FullClass,
2412                       RscName, RscClass,
2413		       &RscValue, &RepresentationType) ) {
2414	RscDest.size = sizeof(KeySym);
2415	RscDest.addr = (caddr_t) pKeySym;
2416	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2417	                       XmRKeySym, &RscDest) )
2418	    return True;
2419    }
2420    return False;
2421} /* FetchKeySymResource */
2422
2423static Boolean FetchXmStringResource(Widget w,
2424                                char *FullName, char *FullClass,
2425                                char *RscName, char *RscClass,
2426			        XmString *pString)
2427{
2428    XrmValue RscValue;
2429    String   RepresentationType;
2430
2431    if ( FetchResource(w, FullName, FullClass,
2432                       RscName, RscClass,
2433		       &RscValue, &RepresentationType) ) {
2434	*pString = XmCvtCTToXmString((char *) RscValue.addr);
2435	return True;
2436    }
2437    return False;
2438} /* FetchXmStringResource */
2439
2440static Boolean FetchXmStringTableResource(Widget w,
2441                                char *FullName, char *FullClass,
2442                                char *RscName, char *RscClass,
2443			        XmStringTable *pStringTable,
2444				int *pTableSize)
2445{
2446    XrmValue RscValue;
2447    String   RepresentationType;
2448    String   TmpList, p, pStart;
2449    int      Entries, Entry;
2450
2451    if ( FetchResource(w, FullName, FullClass,
2452                       RscName, RscClass,
2453		       &RscValue, &RepresentationType) ) {
2454	/*
2455	 * Zuerst eine Kopie erzeugen und dann daraus die Liste
2456	 * zusammenbasteln.
2457	 */
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.
2463	 */
2464	Entries = 1; p = TmpList;
2465	while ( *p )
2466	    if ( *p++ == ',' ) ++Entries;
2467	*pStringTable = (XmStringTable)
2468	    XtMalloc(Entries * sizeof(XmString));
2469
2470	p = TmpList;
2471	for ( Entry = 0; Entry < Entries; ++Entry ) {
2472	    pStart = p;
2473	    while ( (*p != 0) && (*p != ',') ) ++p;
2474	    *p++ = 0;
2475	    (*pStringTable)[Entry] = (XmString)
2476	        XmStringCreateSimple(pStart);
2477	}
2478	/* Hier geht ausnahmsweise einmal Rueckgabe vor
2479	 * Entschaedigung... hey, das war doch nur ein
2480	 * (wenn auch ziemlich miserabler) Scherz
2481	 */
2482	XtFree(TmpList);
2483	*pTableSize = Entries;
2484	return True;
2485    }
2486    return False;
2487} /* FetchXmStringTableResource */
2488
2489static Boolean FetchXmFontListResource(Widget w,
2490                                char *FullName, char *FullClass,
2491                                char *RscName, char *RscClass,
2492			        XmFontList *pFontList)
2493{
2494    XrmValue RscValue, RscDest;
2495    String   RepresentationType;
2496
2497    if ( FetchResource(w, FullName, FullClass,
2498                       RscName, RscClass,
2499		       &RscValue, &RepresentationType) ) {
2500	RscDest.size = sizeof(XmFontList);
2501	RscDest.addr = (caddr_t) pFontList;
2502	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2503	                       XmRFontList, &RscDest) )
2504	    return True;
2505    }
2506    return False;
2507} /* FetchXmFontListResource */
2508
2509static Boolean FetchPixmapResource(Widget w,
2510                                char *FullName, char *FullClass,
2511                                char *RscName, char *RscClass,
2512				Pixmap *pPixmap)
2513{
2514    XrmValue RscValue, RscDest;
2515    String   RepresentationType;
2516
2517    if ( FetchResource(w, FullName, FullClass,
2518                       RscName, RscClass,
2519		       &RscValue, &RepresentationType) ) {
2520	RscDest.size = sizeof(Pixmap);
2521	RscDest.addr = (caddr_t) pPixmap;
2522	if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2523	                       XtRBitmap, &RscDest) )
2524	    return True;
2525    }
2526    return False;
2527} /* FetchPixmapResource */
2528
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...
2536 */
2537
2538#define RInt		0
2539#define RShort		1
2540#define RLType		2
2541#define RDimension	3
2542#define RXmString	4
2543#define RPixmap		5
2544#define RXmFontList	6
2545#define RKeySym		7
2546#define RString		8
2547#define RXmStringTable	9
2548#define RXmItemCount	10
2549
2550
2551typedef struct
2552{
2553    String Name, Class;
2554
2555    int Converter;
2556
2557} RESOURCEMIRROR;
2558
2559static 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           },
2566
2567    { XmNlistMarginHeight,	 XmCListMarginHeight,	    RDimension     },
2568    { XmNlistMarginWidth,	 XmCListMarginWidth,	    RDimension     },
2569    { XmNlistSpacing,		 XmCListSpacing,	    RDimension     },
2570    { XmNitems,		         XmCItems,		    RXmStringTable },
2571    { XmNitemCount,		 XmCItemCount,	    	    RXmItemCount   },
2572
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    },
2586};
2587
2588static void InitMirrorResources(XmComboBoxWidget w)
2589{
2590    char          FullName[1024], FullClass[1024];
2591    int           AInt, TableSize;
2592    short         AShort;
2593    unsigned char AUChar;
2594    Dimension     ADimension;
2595    XmString      AXmString;
2596    XmStringTable AStringTable;
2597    Pixmap        APixmap;
2598    XmFontList    AFontList;
2599    String        AString;
2600    KeySym        AKeySym;
2601    int           i, size = XtNumber(ResourceMirror);
2602
2603    FullName[0] = 0; FullClass[0] = 0;
2604    MakeNameAndClass((Widget) w, FullName, FullClass);
2605
2606    for ( i=0; i < size; i++ ) {
2607	switch ( ResourceMirror[i].Converter ) {
2608	    case RInt:
2609		if ( FetchIntResource((Widget) w,
2610			FullName, FullClass,
2611			ResourceMirror[i].Name, ResourceMirror[i].Class,
2612			&AInt) )
2613		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2614		                  AInt, NULL);
2615		break;
2616	    case RXmItemCount:
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,
2622		                  AInt, NULL);
2623		break;
2624	    case RShort:
2625		if ( FetchShortResource((Widget) w,
2626			FullName, FullClass,
2627			ResourceMirror[i].Name, ResourceMirror[i].Class,
2628			&AShort) )
2629		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2630		                  AShort, NULL);
2631		break;
2632	    case RLType:
2633		if ( FetchLabelTypeResource((Widget) w,
2634			FullName, FullClass,
2635			ResourceMirror[i].Name, ResourceMirror[i].Class,
2636			&AUChar) )
2637		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2638		                  AUChar, NULL);
2639		break;
2640	    case RDimension:
2641		if ( FetchDimensionResource((Widget) w,
2642			FullName, FullClass,
2643			ResourceMirror[i].Name, ResourceMirror[i].Class,
2644			&ADimension) )
2645		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2646		                  ADimension, NULL);
2647		break;
2648	    case RXmString:
2649		if ( FetchXmStringResource((Widget) w,
2650			FullName, FullClass,
2651			ResourceMirror[i].Name, ResourceMirror[i].Class,
2652			&AXmString) )
2653		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2654		                  AXmString, NULL);
2655		break;
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);
2664		}
2665	        break;
2666	    case RKeySym:
2667		if ( FetchKeySymResource((Widget) w,
2668			FullName, FullClass,
2669			ResourceMirror[i].Name, ResourceMirror[i].Class,
2670			&AKeySym) )
2671		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2672		                  AKeySym, NULL);
2673		break;
2674	    case RString:
2675		if ( FetchStringResource((Widget) w,
2676			FullName, FullClass,
2677			ResourceMirror[i].Name, ResourceMirror[i].Class,
2678			&AString) )
2679		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2680		                  AString, NULL);
2681		break;
2682	    case RPixmap:
2683		if ( FetchPixmapResource((Widget) w,
2684			FullName, FullClass,
2685			ResourceMirror[i].Name, ResourceMirror[i].Class,
2686			&APixmap) ) {
2687		    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2688		                  APixmap, NULL);
2689		    if ( strcmp(ResourceMirror[i].Name, XmNlabelPixmap) == 0 )
2690			w->combobox.ConvertBitmapToPixmap = True;
2691		    else
2692			w->combobox.ConvertBitmapToPixmapInsensitive = True;
2693		}
2694		break;
2695	    case RXmFontList:
2696	    	if ( FetchXmFontListResource((Widget) w,
2697	    	       FullName, FullClass,
2698	    	       ResourceMirror[i].Name, ResourceMirror[i].Class,
2699	    	       &AFontList) )
2700	    	    XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2701	    	                  AFontList, NULL);
2702	    	break;
2703	}
2704    }
2705} /* InitMirrorResources */
2706
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.
2711 */
2712static Pixmap BitmapToPixmap(XmComboBoxWidget w,
2713                           String Resource, GC ColorGC)
2714{
2715    Pixmap       LabelPixmap, LabelBitmap;
2716    Display      *display = XtDisplay(w);
2717    Window       root;
2718    int          PixX, PixY;
2719    unsigned int PixW, PixH, PixBW, PixDepth;
2720
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)),
2726			PixW, PixH,
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);
2732    return LabelPixmap;
2733} /* BitmapToPixmap */
2734
2735/* --------------------------------------------------------------------
2736 * Alles initialisieren, sobald das Widget eingerichtet wird. Das sagt
2737 * sich hier so einfach, ist es aber *definitiv* nicht!!!!
2738 */
2739static void Initialize(Widget request, XmComboBoxWidget newW,
2740                       ArgList wargs, Cardinal *ArgCount)
2741{
2742    Dimension    width, height, dummy;
2743    Widget       w;
2744    Arg          args[10];
2745    int          n = 0;
2746
2747/*
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.
2754 */
2755    XtAppAddActions(XtWidgetToApplicationContext((Widget) newW),
2756	                actions, XtNumber(actions));
2757
2758/* Allgemeine Initialisierungen... */
2759    newW->combobox.ConvertBitmapToPixmap            = False;
2760    newW->combobox.ConvertBitmapToPixmapInsensitive = False;
2761
2762    newW->combobox.LastSelection                    = 0;
2763
2764    newW->combobox.InInit                           = True;
2765
2766/*
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.
2776 */
2777    if ( !newW->combobox.StaticList ) {
2778	w = (Widget) newW;
2779	while ( !XtIsSubclass(w, shellWidgetClass) )
2780	    w = XtParent(w);
2781	newW->combobox.MyNextShell = w;
2782	XtAddEventHandler(w,
2783			  StructureNotifyMask | FocusChangeMask,
2784			  False, (XtEventHandler) ShellCallback,
2785			  (XtPointer) newW);
2786    }
2787
2788/* Richte nun alle zu diesem Widget gehoerenden Kinder ein, als da
2789 * waeren:
2790 * 1 x editierbares Eingabefeld
2791 * 1 x ein Pfeil nach unten
2792 * 1 x ein Schriftfeld
2793 */
2794    newW->combobox.EditCtrl = XtVaCreateManagedWidget(
2795	"edit", xmTextFieldWidgetClass, (Widget) newW,
2796	XmNverifyBell, False,
2797	NULL);
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,
2808                  XmNhelpCallback,
2809		  (XtCallbackProc) HelpCallback,
2810		  (XtPointer) newW);
2811    XtAddCallback(newW->combobox.EditCtrl,
2812                  XmNactivateCallback,
2813		  (XtCallbackProc) ActivateCallback,
2814		  (XtPointer) newW);
2815    if ( newW->combobox.Editable )
2816	XtAddCallback(newW->combobox.EditCtrl,
2817		      XmNmotionVerifyCallback,
2818		      (XtCallbackProc) MotionVerifyCallback,
2819		      (XtPointer) newW);
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);
2828    }
2829#ifdef NODRAGNDROP
2830    XtOverrideTranslations(newW->combobox.EditCtrl,
2831                           NewListTranslations); /* Btn2Dwn aus! */
2832#endif
2833
2834/* --- */
2835    newW->combobox.ArrowCtrl = XtVaCreateManagedWidget(
2836	"arrow", xmArrowButtonWidgetClass, (Widget) newW,
2837	XmNarrowDirection,     XmARROW_DOWN,
2838	XmNtraversalOn,	       False,
2839	XmNnavigationType,     XmNONE,
2840	XmNborderWidth,        0,
2841	XmNhighlightThickness, 0,
2842	NULL);
2843    XmRemoveTabGroup(newW->combobox.ArrowCtrl);
2844    if ( newW->combobox.StaticList ) {
2845	XtVaSetValues(newW->combobox.ArrowCtrl,
2846	    XmNmappedWhenManaged, False, NULL);
2847    } else {
2848	XtAddEventHandler(newW->combobox.ArrowCtrl,
2849			  EnterWindowMask | LeaveWindowMask,
2850			  False, (XtEventHandler) ArrowCrossingCallback,
2851			  (XtPointer) newW);
2852	XtAddCallback(newW->combobox.ArrowCtrl,
2853		      XmNactivateCallback,
2854		      (XtCallbackProc) ArrowCallback, NULL);
2855	XtAddCallback(newW->combobox.ArrowCtrl,
2856		      XmNarmCallback,
2857		      (XtCallbackProc) ArrowCallback, NULL);
2858	XtAddCallback(newW->combobox.ArrowCtrl,
2859		      XmNhelpCallback,
2860		      (XtCallbackProc) HelpCallback,
2861		      (XtPointer) newW);
2862    }
2863
2864/* --- */
2865    newW->combobox.LabelCtrl = XtVaCreateWidget(
2866	"label", xmLabelWidgetClass, (Widget) newW,
2867	XmNstringDirection, newW->manager.string_direction,
2868	NULL);
2869    if ( newW->combobox.ShowLabel ) {
2870	XtManageChild((Widget) newW->combobox.LabelCtrl);
2871	XtAddCallback(newW->combobox.LabelCtrl,
2872		      XmNhelpCallback,
2873		      (XtCallbackProc) HelpCallback,
2874		      (XtPointer) newW);
2875    }
2876
2877/*
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
2885 * Drag'n'Drop!!!
2886 * Noch neuer: Wenn die Liste dauerhaft angezeigt werden muss, entfaellt
2887 * diese Shell zwangslaeufig. Dann ist das Listenfeld ein direktes Kind
2888 * der ComboBox.
2889 */
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,
2896	    NULL);
2897	XtAddEventHandler(newW->combobox.PopupShell,
2898			  EnterWindowMask | LeaveWindowMask,
2899			  False, (XtEventHandler) OverrideShellCallback,
2900			  (XtPointer) newW);
2901    } else {
2902    /*
2903     * Sieht ja pervers nach einer Rekursion aus...daher: OBACHT!
2904     */
2905	newW->combobox.PopupShell = (Widget) newW;
2906    }
2907
2908/*
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.
2914 */
2915    XtSetArg(args[n], XmNselectionPolicy, newW->combobox.SelectionPolicy); n++;
2916
2917    if ( !newW->combobox.StaticList ) {
2918    /*
2919     * Es gibt halt so eine ganze Reihe von Einstellungen, die koennen nicht
2920     * veraendert werden, wenn das Listenfeld nur bei Bedarf ausgeklappt wird.
2921     */
2922	XtSetArg(args[n], XmNhighlightThickness, 0); n++;
2923    }
2924    XtSetArg(args[n], XmNlistSizePolicy,
2925                      newW->combobox.ListSizePolicy); n++;
2926    XtSetArg(args[n], XmNscrollBarDisplayPolicy,
2927                      newW->combobox.ScrollBarDisplayPolicy); n++;
2928
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",
2935	args, n);
2936
2937/*
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
2941 * hoffentlich...!)
2942 */
2943    if ( !newW->combobox.StaticList ) {
2944	XtVaSetValues(newW->combobox.ListCtrl,
2945		      XmNtraversalOn,  False,  NULL);
2946	XtVaSetValues(XtParent(newW->combobox.ListCtrl),
2947		      XmNtraversalOn, False, NULL);
2948    } else {
2949	if ( !newW->combobox.Editable ) {
2950	    XtVaSetValues(XtParent(newW->combobox.ListCtrl),
2951		      XmNtraversalOn, False, NULL);
2952	    XmRemoveTabGroup(newW->combobox.ListCtrl);
2953	}
2954    }
2955
2956    XtManageChild(newW->combobox.ListCtrl);
2957    XtAddCallback(newW->combobox.ListCtrl,
2958                  XmNsingleSelectionCallback,
2959		  (XtCallbackProc) ListSelectionCallback,
2960		  (XtPointer) newW);
2961    XtAddCallback(newW->combobox.ListCtrl,
2962                  XmNbrowseSelectionCallback,
2963		  (XtCallbackProc) ListSelectionCallback,
2964		  (XtPointer) newW);
2965    XtAddCallback(newW->combobox.ListCtrl,
2966                  XmNdefaultActionCallback,
2967		  (XtCallbackProc) ListDefaultActionCallback,
2968		  (XtPointer) newW);
2969    XtAddCallback(newW->combobox.ListCtrl,
2970                  XmNhelpCallback,
2971		  (XtCallbackProc) HelpCallback,
2972		  (XtPointer) newW);
2973
2974    XtAddEventHandler(newW->combobox.ListCtrl,
2975                      ButtonReleaseMask,
2976		      False, (XtEventHandler) Button1UpInList,
2977		      (XtPointer) newW);
2978
2979#ifdef NODRAGNDROP
2980    XtOverrideTranslations(newW->combobox.ListCtrl,
2981                           NewListTranslations);
2982#endif
2983    if ( newW->combobox.StaticList && newW->combobox.Editable )
2984        XtOverrideTranslations(newW->combobox.ListCtrl,
2985                               NewListTranslationsE);
2986
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.
2991 */
2992    InitMirrorResources(newW);
2993    UpdateColors(newW, -1);
2994    SetValues(newW, newW, newW, wargs, ArgCount);
2995
2996    if ( newW->combobox.ConvertBitmapToPixmap )
2997	newW->combobox.LabelPixmap =
2998	    BitmapToPixmap(newW, XmNlabelPixmap,
2999	               ((XmLabelRec *) newW->combobox.LabelCtrl)->
3000		         label.normal_GC);
3001    if ( newW->combobox.ConvertBitmapToPixmapInsensitive )
3002	newW->combobox.LabelInsensitivePixmap =
3003	    BitmapToPixmap(newW, XmNlabelInsensitivePixmap,
3004	               ((XmLabelRec *) newW->combobox.LabelCtrl)->
3005		         label.insensitive_GC);
3006
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;
3012
3013/*
3014 * Falls wir keine Fontliste besitzen, dann nehmen wir die von
3015 * dem Eingabefeld...
3016 */
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);
3022    } else {
3023	XtVaSetValues(newW->combobox.ListCtrl,
3024	              XmNfontList, newW->combobox.Font, NULL);
3025	XtVaSetValues(newW->combobox.EditCtrl,
3026	              XmNfontList, newW->combobox.Font, NULL);
3027    }
3028
3029/*
3030 * Initialisiere alle Statusflaggen, die mit diesem unseligen Focus-
3031 * problem zu tun haben...
3032 */
3033    newW->combobox.ListVisible          = False;
3034    newW->combobox.IgnoreFocusOut       = False;
3035    newW->combobox.PendingFocusOut      = False;
3036    newW->combobox.PendingOverrideInOut = False;
3037
3038    newW->combobox.PassVerification = False;
3039
3040/*
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!
3045 */
3046    DoLayout(newW);
3047/*
3048 * Endlich fertig mit der Initialisierung. Das hier ist aber auch
3049 * wirklich viel Arbeit fuer so ein Widget!
3050 */
3051    newW->combobox.InInit = False;
3052} /* Initialize */
3053
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.
3058 */
3059Widget XmComboBoxGetEditWidget(Widget w)
3060{
3061    return ((XmComboBoxWidget) w)->combobox.EditCtrl;
3062} /* XmComboBoxGetEditWidget */
3063
3064Widget XmComboBoxGetListWidget(Widget w)
3065{
3066    return ((XmComboBoxWidget) w)->combobox.ListCtrl;
3067} /* XmComboBoxGetListWidget */
3068
3069Widget XmComboBoxGetLabelWidget(Widget w)
3070{
3071    return ((XmComboBoxWidget) w)->combobox.LabelCtrl;
3072} /* XmComboBoxGetLabelWidget */
3073
3074
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...
3084 *
3085 * Parameter:
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)
3091 */
3092static int UpdateComboBox(XmComboBoxWidget w, int Index, Boolean Deleted)
3093{
3094    int OldIndex, ItemCount;
3095
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-
3101 * waehlt.
3102 */
3103	if ( Deleted ) {
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.
3110		 */
3111		SetSelectionPos(w, Index, False);
3112	    }
3113	}
3114    }
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.
3118 */
3119    if ( !w->combobox.Editable ) {
3120	TransferToEditCtrl(w, Index, False);
3121    }
3122
3123    return 1;
3124} /* UpdateComboBox */
3125
3126
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.
3131 */
3132static int FindSortedItemPos(XmComboBoxWidget w, XmString item)
3133{
3134    Widget                          ListBox = w->combobox.ListCtrl;
3135    XmStringTable                   Items;
3136    int                             ItemCount, index, Left, Right, Result;
3137    char                            *pItemText, *pCompareText;
3138    Boolean	                    ExternSort;
3139    XmComboBoxSortingCallbackStruct data;
3140
3141    XtVaGetValues(ListBox, XmNitems,     &Items,
3142                           XmNitemCount, &ItemCount, NULL);
3143    if ( ItemCount == 0 ) return 1;
3144
3145    /*
3146     * Moechte das Programm die Kontrolle ueber den Sortiervorgang
3147     * uebernehmen? Dann bereite alles vor...
3148     */
3149    ExternSort = XtHasCallbacks((Widget) w, XmNsortingCallback) ==
3150                     XtCallbackHasSome;
3151    if ( ExternSort ) {
3152        data.reason    = XmCR_SORTING;
3153        data.event     = NULL;
3154        data.operation = XmOP_INIT;
3155        data.item      = item;
3156        XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3157    } else
3158        XmStringGetLtoR(item, XmSTRING_DEFAULT_CHARSET, &pCompareText);
3159
3160    Left = 0; Right = ItemCount - 1;
3161    do {
3162	index = (Left + Right) / 2;
3163	if ( ExternSort ) {
3164	    data.operation = XmOP_COMPARE;
3165	    data.item      = Items[index];
3166	    data.result    = 1;
3167            XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3168            Result = data.result;
3169	} else {
3170	    XmStringGetLtoR(Items[index], XmSTRING_DEFAULT_CHARSET, &pItemText);
3171	    Result = strcmp(pCompareText, pItemText);
3172	    XtFree(pItemText);
3173	}
3174	if      ( Result < 0 ) Right = index - 1;
3175	else if ( Result > 0 ) Left  = index + 1;
3176    } while ( (Result != 0) && (Left <= Right) );
3177
3178    /*
3179     * Nach Gebrauch wieder alles aufraeumen (bei einer externen Sortierung
3180     * muss das das Programm uebernehmen!)
3181     */
3182    if ( ExternSort ) {
3183        data.operation = XmOP_DONE;
3184        XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3185    } else
3186        XtFree(pCompareText);
3187
3188    if ( Result < 0 )
3189	return index + 1; /* Beachte, dass Indizes mit 1 beginnen! */
3190    else
3191	return index + 2; /* Beachte, dass Indizes mit 1 beginnen! */
3192} /* FindSortedItemPos */
3193
3194/* --------------------------------------------------------------------
3195 * Kontrolliere, ob es sich ueberhaupt um eine Combo-Box (bzw. einen
3196 * hypothetischen Nachkommen) handelt -- ansonsten mecker kraeftig
3197 * herum!
3198 * Ergebnis:
3199 *   True, falls wir hier ein falsches Widget untergejubelt bekommen!
3200 */
3201static Boolean CheckComboBox(Widget w, char *pFuncName)
3202{
3203    char buff[256];
3204    char *pWName;
3205
3206#if (XmVersion >= 2000)
3207    return False; /* temporary workaround */
3208#else
3209    if ( XmIsComboBox(w) ) return False;
3210    pWName = XrmQuarkToString(w->core.xrm_name);
3211    sprintf(buff,
3212"Warning: %s called on widget named %s beeing \
3213not a descendant of class XmComboBox!",
3214		  pFuncName, pWName);
3215    XtWarning(buff);
3216    return True;
3217#endif
3218} /* CheckComboBox */
3219
3220/* --------------------------------------------------------------------
3221 * Saemtliche Interface-Routinen zur Combo-Box
3222 */
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)
3227
3228/* !!!
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
3237 * nur verwirren...
3238 */
3239void    XmComboBoxAddItem(Widget w, XmString item, int pos)
3240{
3241    int OldIndex = XmComboBoxGetSelectedPos(w);
3242
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
3250	 * soll!
3251	 */
3252	SetSelectionPos(ComboBox, OldIndex, False);
3253} /* XmComboBoxAddItem */
3254/* !!!
3255 * Hier gilt das bereits oben gesagte (siehe XmComboBoxAddItem).
3256 * Bei sortierten Listboxen wird die Sortierung beim Gebrauch dieser
3257 * Funktion zerstoert!
3258 */
3259void    XmComboBoxAddItems(Widget w, XmString *items, int item_count, int pos)
3260{
3261    int OldIndex = XmComboBoxGetSelectedPos(w);
3262
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 */
3269
3270void    XmComboBoxAddItemUnselected(Widget w, XmString item, int pos)
3271{ XmListAddItemUnselected(ListBox, item, pos); }
3272
3273/* !!!
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
3277 * werden.
3278 */
3279void    XmComboBoxDeleteItem(Widget w, XmString item)
3280{
3281    int Index = XmListItemPos(ListBox, item);
3282
3283    if ( CheckComboBox(w, "XmComboBoxDeleteItem") ) return;
3284    if ( Index ) XmComboBoxDeletePos(w, Index);
3285} /* XmComboBoxDeleteItem */
3286
3287void    XmComboBoxDeleteItems(Widget w, XmString *items, int item_count)
3288{
3289    int i;
3290
3291    if ( CheckComboBox(w, "XmComboBoxDeleteItems") ) return;
3292    for ( i = 0; i < item_count; i++ )
3293	XmListDeleteItem(w, items[i]);
3294} /* XmComboBoxDeleteItems */
3295
3296void    XmComboBoxDeletePos(Widget w, int pos)
3297{
3298    int OldIndex = XmComboBoxGetSelectedPos(w);
3299
3300    if ( CheckComboBox(w, "XmComboBoxDeletePos") ) return;
3301    XmListDeletePos(ListBox, pos);
3302    if ( pos == OldIndex ) UpdateComboBox(ComboBox, pos, True);
3303} /* XmComboBoxDeletePos */
3304
3305void    XmComboBoxDeleteItemsPos(Widget w, int item_count, int pos)
3306{
3307    int i;
3308
3309    if ( CheckComboBox(w, "XmComboBoxDeleteItemsPos") ) return;
3310    for ( i = 0; i < item_count; i++ )
3311	XmComboBoxDeletePos(w, pos++);
3312} /* XmComboBoxDeleteItemsPos */
3313
3314void    XmComboBoxDeleteAllItems(Widget w)
3315{
3316    if ( CheckComboBox(w, "XmComboBoxAllDeleteItems") ) return;
3317    XmListDeleteAllItems(ListBox);
3318    UpdateComboBox(ComboBox, 0, True);
3319} /* XmComboBoxDeleteAllItems */
3320
3321/* !!!
3322 * Werden Eintraege ausgetauscht, so heisst es fuer uns, auch hierbei
3323 * auf der Hut zu sein.
3324 */
3325void    XmComboBoxReplaceItems(Widget w, XmString *old_items, int item_count, XmString *new_items)
3326{
3327    if ( CheckComboBox(w, "XmComboBoxReplaceItems") ) return;
3328    XmListReplaceItems(ListBox, old_items, item_count, new_items);
3329    UpdateComboBox(ComboBox, XmComboBoxGetSelectedPos(w), False);
3330} /* XmComboBoxReplaceItems */
3331
3332void    XmComboBoxReplaceItemsPos(Widget w, XmString *new_items, int item_count, int position)
3333{
3334    int OldIndex = XmComboBoxGetSelectedPos(w);
3335
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 */
3341
3342Boolean XmComboBoxItemExists(Widget w, XmString item)
3343{
3344    if ( CheckComboBox(w, "XmComboBoxItemExists") ) return False;
3345    return XmListItemExists(ListBox, item);
3346} /* XmComboBoxItemExists */
3347
3348int     XmComboBoxItemPos(Widget w, XmString item)
3349{
3350    if ( CheckComboBox(w, "XmComboBoxItemPos") ) return 0;
3351    return XmListItemPos(ListBox, item);
3352} /* XmComboBoxItemPos */
3353
3354Boolean XmComboBoxGetMatchPos(Widget w, XmString item, int **pos_list, int *pos_count)
3355{
3356    if ( CheckComboBox(w, "XmComboBoxGetMatchPos") ) return False;
3357    return XmListGetMatchPos(ListBox, item, pos_list, pos_count);
3358} /* XmComboBoxGetMatchPos */
3359
3360/* !!!
3361 * Sobald ein anderer Eintrag in der Listbox ausgewaehlt werden soll,
3362 * muessen wir hier helfend eingreifen.
3363 */
3364void    XmComboBoxSelectPos(Widget w, int pos, Boolean notify)
3365{
3366    int index;
3367
3368    if ( CheckComboBox(w, "XmComboBoxSelectPos") ) return;
3369    index = SetSelectionPos(ComboBox, pos, notify);
3370    if ( index ) TransferToEditCtrl(ComboBox, index, False);
3371} /* XmComboBoxSelectPos */
3372
3373/* !!!
3374 * dto. analog zu XmComboBoxSelectPos, nur statt des Index wird der
3375 * Eintragstext angegeben, um einen Eintrag in der Listbox zu
3376 * markieren.
3377 */
3378void    XmComboBoxSelectItem(Widget w, XmString item, Boolean notify)
3379{
3380    int index;
3381
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 */
3387
3388/* !!!
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.
3394 */
3395int     XmComboBoxGetSelectedPos(Widget w)
3396{
3397    int *SelectionList, SelectionCount, SelectionIndex;
3398
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 */
3407
3408
3409
3410void    XmComboBoxClearSelection(Widget w, Time time)
3411{
3412    XmTextFieldClearSelection(EditBox, time);
3413} /* XmComboBoxClearSelection */
3414
3415Boolean XmComboBoxCopy(Widget w, Time time)
3416{
3417    return XmTextFieldCopy(EditBox, time);
3418} /* XmComboBoxCopy */
3419
3420Boolean XmComboBoxCut(Widget w, Time time)
3421{
3422    return XmTextFieldCut(EditBox, time);
3423} /* XmComboBoxCut */
3424
3425XmTextPosition XmComboBoxGetInsertionPosition(Widget w)
3426{
3427    return XmTextFieldGetInsertionPosition(EditBox);
3428} /* XmComboBoxGetInsertionPosition */
3429
3430XmTextPosition XmComboBoxGetLastPosition(Widget w)
3431{
3432    return XmTextFieldGetLastPosition(EditBox);
3433} /* XmComboBoxGetLastPosition */
3434
3435int     XmComboBoxGetMaxLength(Widget w)
3436{
3437    return XmTextFieldGetMaxLength(EditBox);
3438} /* XmComboBoxGetMaxLength */
3439
3440char *  XmComboBoxGetSelection(Widget w)
3441{
3442    return XmTextFieldGetSelection(EditBox);
3443} /* XmComboBoxGetSelection */
3444
3445Boolean XmComboBoxGetSelectionPosition(Widget w, XmTextPosition *left,
3446                                       XmTextPosition *right)
3447{
3448    return XmTextFieldGetSelectionPosition(EditBox, left, right);
3449} /* XmComboBoxGetSelectionPosition */
3450
3451char *  XmComboBoxGetString(Widget w)
3452{
3453    return XmTextFieldGetString(EditBox);
3454} /* XmComboBoxGetString */
3455
3456void    XmComboBoxInsert(Widget w, XmTextPosition position, char *value)
3457{
3458    XmTextFieldInsert(EditBox, position, value);
3459} /* XmComboBoxInsert */
3460
3461Boolean XmComboBoxPaste(Widget w)
3462{
3463    return XmTextFieldPaste(EditBox);
3464} /* XmComboBoxPaste */
3465
3466Boolean XmComboBoxRemove(Widget w)
3467{
3468    return XmTextFieldRemove(EditBox);
3469} /* XmComboBoxRemove */
3470
3471void    XmComboBoxReplace(Widget w, XmTextPosition from_pos,
3472                          XmTextPosition to_pos, char *value)
3473{
3474    XmTextFieldReplace(EditBox, from_pos, to_pos, value);
3475} /* XmComboBoxReplace */
3476
3477void    XmComboBoxSetAddMode(Widget w, Boolean state)
3478{
3479    XmTextFieldSetAddMode(EditBox, state);
3480} /* XmComboBoxSetAddMode */
3481
3482void    XmComboBoxSetHighlight(Widget w, XmTextPosition left,
3483                               XmTextPosition right, XmHighlightMode mode)
3484{
3485    XmTextFieldSetHighlight(EditBox, left, right, mode);
3486} /* XmComboBoxSetHighlight */
3487
3488void    XmComboBoxSetInsertionPosition(Widget w, XmTextPosition position)
3489{
3490    XmTextFieldSetInsertionPosition(EditBox, position);
3491} /* XmComboBoxSetInsertionPosition */
3492
3493void    XmComboBoxSetMaxLength(Widget w, int max_length)
3494{
3495    XmTextFieldSetMaxLength(EditBox, max_length);
3496} /* XmComboBoxSetMaxLength */
3497
3498void    XmComboBoxSetSelection(Widget w, XmTextPosition first,
3499                               XmTextPosition last, Time time)
3500{
3501    XmTextFieldSetSelection(EditBox, first, last, time);
3502} /* XmComboBoxSetSelection */
3503
3504void    XmComboBoxSetString(Widget w, char *value)
3505{
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.
3510 */
3511    if ( (value == NULL) || (*value == 0) )
3512        XtVaSetValues(w, XmNvalue, "", NULL);
3513    else
3514	XmTextFieldSetString(EditBox, value);
3515} /* XmComboBoxSetString */
3516
3517void    XmComboBoxShowPosition(Widget w, XmTextPosition position)
3518{
3519    XmTextFieldShowPosition(EditBox, position);
3520} /* XmComboBoxShowPosition */
3521
3522/*
3523 * Loescht einen evtl. noch ausgewaehlten Eintrag in einer Combo Box,
3524 * wenn diese eine SelectionPolicy von XmSINGLE_SELECT hat.
3525 */
3526void XmComboBoxClearItemSelection(Widget w)
3527{
3528    int index;
3529
3530    if ( CheckComboBox(w, "XmComboBoxClearItemSelection") ) return;
3531
3532    /*
3533     * Wenn bereits kein Eintrag markiert ist, dann loeschen wir nur noch
3534     * eben das Eingabefeld.
3535     */
3536    index = XmComboBoxGetSelectedPos(w);
3537    if ( index == 0 ) {
3538	XmComboBoxSetString(w, "");
3539    } else {
3540    /*
3541     * Ansonsten aktuellen Eintrag entsorgen (wie bei der Methode wipe-out)
3542     */
3543	TransferToEditCtrl(ComboBox, 0, True);
3544	CallSelectionCBL(ComboBox, NULL);
3545    }
3546} /* XmComboBoxClearItemSelection */
3547
3548/* Die Drop-Down-Liste ein oder ausklappen */
3549void    XmComboBoxShowList(Widget w)
3550{
3551    if ( CheckComboBox(w, "XmComboBoxShowList") ) return;
3552    ShowHideDropDownList((XmComboBoxWidget) w, NULL, False);
3553} /* XmComboBoxShowList */
3554
3555void    XmComboBoxHideList(Widget w)
3556{
3557    if ( CheckComboBox(w, "XmComboBoxHideList") ) return;
3558    ShowHideDropDownList((XmComboBoxWidget) w, NULL, True);
3559} /* XmComboBoxShowList */
3560
3561/*
3562 * Naja, ich komm' ja doch nicht um diese olle Funktion herum...
3563 */
3564Widget XmCreateComboBox(Widget parent, String name, ArgList arglist,
3565                           Cardinal argcount)
3566{
3567    return XtCreateWidget(name, xmComboBoxWidgetClass, parent,
3568                          arglist, argcount);
3569} /* XmCreateComboBox */
3570
3571/* Ende von ComboBox.c */
3572
3573#endif /* XmVersion < 2000 */
3574