1 /* The lwlib interface to Motif widgets.
2 
3 Copyright (C) 1994-1997, 1999-2021 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
5 
6 This file is part of the Lucid Widget Library.
7 
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
11 any later version.
12 
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
20 
21 #include <config.h>
22 
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <setjmp.h>
26 
27 #include <X11/StringDefs.h>
28 #include <X11/IntrinsicP.h>
29 #include <X11/ObjectP.h>
30 #include <X11/CoreP.h>
31 #include <X11/CompositeP.h>
32 
33 #include <lisp.h>
34 
35 #include "lwlib-Xm.h"
36 #include "lwlib-utils.h"
37 
38 #include <Xm/BulletinB.h>
39 #include <Xm/CascadeB.h>
40 #include <Xm/CascadeBG.h>
41 #include <Xm/DrawingA.h>
42 #include <Xm/FileSB.h>
43 #include <Xm/Label.h>
44 #include <Xm/List.h>
45 #include <Xm/MainW.h>
46 #include <Xm/MenuShell.h>
47 #include <Xm/MessageB.h>
48 #include <Xm/PanedW.h>
49 #include <Xm/PushB.h>
50 #include <Xm/PushBG.h>
51 #include <Xm/ArrowB.h>
52 #include <Xm/SelectioB.h>
53 #include <Xm/Text.h>
54 #include <Xm/TextF.h>
55 #include <Xm/ToggleB.h>
56 #include <Xm/ToggleBG.h>
57 #include <Xm/RowColumn.h>
58 #include <Xm/ScrolledW.h>
59 #include <Xm/Separator.h>
60 #include <Xm/DialogS.h>
61 #include <Xm/Form.h>
62 
63 enum do_call_type { pre_activate, selection, no_selection, post_activate };
64 
65 
66 /* Structures to keep destroyed instances */
67 typedef struct _destroyed_instance
68 {
69   char*		name;
70   char*		type;
71   Widget 	widget;
72   Widget	parent;
73   Boolean	pop_up_p;
74   struct _destroyed_instance*	next;
75 } destroyed_instance;
76 
77 static destroyed_instance *make_destroyed_instance (char *, char *,
78                                                     Widget, Widget,
79                                                     Boolean);
80 static void free_destroyed_instance (destroyed_instance*);
81 Widget first_child (Widget);
82 static XmString resource_motif_string (Widget, char *);
83 static void destroy_all_children (Widget, int);
84 static void xm_update_label (widget_instance *, Widget, widget_value *);
85 static void xm_update_list (widget_instance *, Widget, widget_value *);
86 static void xm_update_pushbutton (widget_instance *, Widget,
87                                   widget_value *);
88 static void xm_update_cascadebutton (widget_instance *, Widget,
89                                      widget_value *);
90 static void xm_update_toggle (widget_instance *, Widget, widget_value *);
91 static void xm_update_radiobox (widget_instance *, Widget, widget_value *);
92 static void make_menu_in_widget (widget_instance *, Widget,
93                                  widget_value *, int);
94 static void update_one_menu_entry (widget_instance *, Widget,
95                                    widget_value *, Boolean);
96 static void xm_update_menu (widget_instance *, Widget, widget_value *,
97                             Boolean);
98 static void xm_update_text (widget_instance *, Widget, widget_value *);
99 static void xm_update_text_field (widget_instance *, Widget,
100                                   widget_value *);
101 static void activate_button (Widget, XtPointer, XtPointer);
102 static Widget make_dialog (char *, Widget, Boolean, char *, char *,
103                            Boolean, Boolean, Boolean, int, int);
104 static destroyed_instance* find_matching_instance (widget_instance*);
105 static void mark_dead_instance_destroyed (Widget, XtPointer, XtPointer);
106 static void recenter_widget (Widget);
107 static Widget recycle_instance (destroyed_instance*);
108 static Widget make_menubar (widget_instance*);
109 static void remove_grabs (Widget, XtPointer, XtPointer);
110 static Widget make_popup_menu (widget_instance*);
111 static Widget make_main (widget_instance*);
112 static void set_min_dialog_size (Widget);
113 static void do_call (Widget, XtPointer, enum do_call_type);
114 static void xm_generic_callback (Widget, XtPointer, XtPointer);
115 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
116 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
117 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
118 static void xm_internal_update_other_instances (Widget, XtPointer,
119                                                 XtPointer);
120 static void xm_arm_callback (Widget, XtPointer, XtPointer);
121 
122 #if 0
123 void xm_update_one_widget (widget_instance *, Widget, widget_value *,
124                            Boolean);
125 void xm_pop_instance (widget_instance*, Boolean);
126 void xm_manage_resizing (Widget, Boolean);
127 #endif
128 
129 
130 #if 0
131 
132 /* Print the complete X resource name of widget WIDGET to stderr.
133    This is sometimes handy to have available.  */
134 
135 void
136 x_print_complete_resource_name (Widget widget)
137 {
138   int i;
139   String names[100];
140 
141   for (i = 0; i < 100 && widget != NULL; ++i)
142     {
143       names[i] = XtName (widget);
144       widget = XtParent (widget);
145     }
146 
147   for (--i; i >= 1; --i)
148     fprintf (stderr, "%s.", names[i]);
149   fprintf (stderr, "%s\n", names[0]);
150 }
151 
152 #endif /* 0 */
153 
154 
155 static destroyed_instance *all_destroyed_instances = NULL;
156 
157 static destroyed_instance*
make_destroyed_instance(char * name,char * type,Widget widget,Widget parent,Boolean pop_up_p)158 make_destroyed_instance (char* name,
159                          char* type,
160                          Widget widget,
161                          Widget parent,
162                          Boolean pop_up_p)
163 {
164   destroyed_instance* instance =
165     (destroyed_instance*) xmalloc (sizeof (destroyed_instance));
166   instance->name = xstrdup (name);
167   instance->type = xstrdup (type);
168   instance->widget = widget;
169   instance->parent = parent;
170   instance->pop_up_p = pop_up_p;
171   instance->next = NULL;
172   return instance;
173 }
174 
175 static void
free_destroyed_instance(destroyed_instance * instance)176 free_destroyed_instance (destroyed_instance* instance)
177 {
178   xfree (instance->name);
179   xfree (instance->type);
180   xfree (instance);
181 }
182 
183 /* motif utility functions */
184 Widget
first_child(Widget widget)185 first_child (Widget widget)
186 {
187   return ((CompositeWidget)widget)->composite.children [0];
188 }
189 
190 Boolean
lw_motif_widget_p(Widget widget)191 lw_motif_widget_p (Widget widget)
192 {
193   return
194     XtClass (widget) == xmDialogShellWidgetClass
195       || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
196 }
197 
198 static XmString
resource_motif_string(Widget widget,char * name)199 resource_motif_string (Widget widget,
200                        char* name)
201 {
202   XtResource resource;
203   XmString result = 0;
204 
205   resource.resource_name = name;
206   resource.resource_class = XmCXmString;
207   resource.resource_type = XmRXmString;
208   resource.resource_size = sizeof (XmString);
209   resource.resource_offset = 0;
210   resource.default_type = XtRImmediate;
211   resource.default_addr = 0;
212 
213   XtGetSubresources (widget, (XtPointer)&result, "dialogString",
214 		     "DialogString", &resource, 1, NULL, 0);
215   return result;
216 }
217 
218 /* Destroy all of the children of WIDGET
219    starting with number FIRST_CHILD_TO_DESTROY.  */
220 
221 static void
destroy_all_children(Widget widget,int first_child_to_destroy)222 destroy_all_children (Widget widget,
223                       int first_child_to_destroy)
224 {
225   Widget* children;
226   unsigned int number;
227   int i;
228 
229   children = XtCompositeChildren (widget, &number);
230   if (children)
231     {
232       XtUnmanageChildren (children + first_child_to_destroy,
233 			  number - first_child_to_destroy);
234 
235       /* Unmanage all children and destroy them.  They will only be
236 	 really destroyed when we get out of DispatchEvent.  */
237       for (i = first_child_to_destroy; i < number; i++)
238 	{
239 	  Arg al[2];
240 	  Widget submenu = 0;
241 	  /* Cascade buttons have submenus,and these submenus
242 	     need to be freed.  But they are not included in
243 	     XtCompositeChildren.  So get it out of the cascade button
244 	     and free it.  If this child is not a cascade button,
245 	     then submenu should remain unchanged.  */
246 	  XtSetArg (al[0], XmNsubMenuId, &submenu);
247   	  XtGetValues (children[i], al, 1);
248 	  if (submenu)
249             {
250               destroy_all_children (submenu, 0);
251               XtDestroyWidget (submenu);
252             }
253 	  XtDestroyWidget (children[i]);
254 	}
255 
256       XtFree ((char *) children);
257     }
258 }
259 
260 
261 
262 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
263    menu.  CLIENT_DATA contains a pointer to the widget_value
264    corresponding to widget W.  CALL_DATA contains a
265    XmPushButtonCallbackStruct containing the reason why the callback
266    is called.  */
267 
268 static void
xm_arm_callback(Widget w,XtPointer client_data,XtPointer call_data)269 xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
270 {
271   XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
272   widget_value *wv = (widget_value *) client_data;
273   widget_instance *instance;
274 
275   /* Get the id of the menu bar or popup menu this widget is in.  */
276   while (w != NULL)
277     {
278       if (XmIsRowColumn (w))
279 	{
280 	  unsigned char type = 0xff;
281 
282 	  XtVaGetValues (w, XmNrowColumnType, &type, NULL);
283 	  if (type == XmMENU_BAR || type == XmMENU_POPUP)
284 	    break;
285 	}
286 
287       w = XtParent (w);
288     }
289 
290   if (w != NULL)
291     {
292       instance = lw_get_widget_instance (w);
293       if (instance && instance->info->highlight_cb)
294 	{
295 	  call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
296 	  instance->info->highlight_cb (w, instance->info->id, call_data);
297 	}
298     }
299 }
300 
301 
302 
303 /* Update the label of widget WIDGET.  WIDGET must be a Label widget
304    or a subclass of Label.  WIDGET_INSTANCE is unused.  VAL contains
305    the value to update.
306 
307    Menus:
308 
309    Emacs fills VAL->name with the text to display in the menu, and
310    sets VAL->value to null.  Function make_menu_in_widget creates
311    widgets with VAL->name as resource name.  This works because the
312    Label widget uses its resource name for display if no
313    XmNlabelString is set.
314 
315    Dialogs:
316 
317    VAL->name is again set to the resource name, but VAL->value is
318    not null, and contains the label string to display.  */
319 
320 static void
xm_update_label(widget_instance * instance,Widget widget,widget_value * val)321 xm_update_label (widget_instance* instance,
322                  Widget widget,
323                  widget_value* val)
324 {
325   XmString res_string = 0;
326   XmString built_string = 0;
327   XmString key_string = 0;
328   Arg al [256];
329   int ac;
330 
331   ac = 0;
332 
333   if (val->value)
334     {
335       /* A label string is specified, i.e. we are in a dialog.  First
336 	 see if it is overridden by something from the resource file.  */
337       res_string = resource_motif_string (widget, val->value);
338 
339       if (res_string)
340 	{
341 	  XtSetArg (al [ac], XmNlabelString, res_string); ac++;
342 	}
343       else
344 	{
345 	  built_string =
346 	    XmStringCreateLocalized (val->value);
347 	  XtSetArg (al [ac], XmNlabelString, built_string); ac++;
348 	}
349 
350       XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
351     }
352 
353   if (val->key)
354     {
355       key_string = XmStringCreateLocalized (val->key);
356       XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
357     }
358 
359   if (ac)
360     XtSetValues (widget, al, ac);
361 
362   if (built_string)
363     XmStringFree (built_string);
364 
365   if (key_string)
366     XmStringFree (key_string);
367 }
368 
369 /* update of list */
370 static void
xm_update_list(widget_instance * instance,Widget widget,widget_value * val)371 xm_update_list (widget_instance* instance,
372                 Widget widget,
373                 widget_value* val)
374 {
375   widget_value* cur;
376   int i;
377   XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
378   XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
379 		 instance);
380   for (cur = val->contents, i = 0; cur; cur = cur->next)
381     if (cur->value)
382       {
383 	XmString xmstr = XmStringCreateLocalized (cur->value);
384 	i += 1;
385 	XmListAddItem (widget, xmstr, 0);
386 	if (cur->selected)
387 	  XmListSelectPos (widget, i, False);
388 	XmStringFree (xmstr);
389       }
390 }
391 
392 /* update of buttons */
393 static void
xm_update_pushbutton(widget_instance * instance,Widget widget,widget_value * val)394 xm_update_pushbutton (widget_instance* instance,
395                       Widget widget,
396                       widget_value* val)
397 {
398   XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
399   XtRemoveAllCallbacks (widget, XmNactivateCallback);
400   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
401 }
402 
403 static void
xm_update_cascadebutton(widget_instance * instance,Widget widget,widget_value * val)404 xm_update_cascadebutton (widget_instance* instance,
405                          Widget widget,
406                          widget_value* val)
407 {
408   /* Should also rebuild the menu by calling ...update_menu... */
409   XtRemoveAllCallbacks (widget, XmNcascadingCallback);
410   XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
411 		 instance);
412 }
413 
414 /* update toggle and radiobox */
415 static void
xm_update_toggle(widget_instance * instance,Widget widget,widget_value * val)416 xm_update_toggle (widget_instance* instance,
417                   Widget widget,
418                   widget_value* val)
419 {
420   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
421   XtAddCallback (widget, XmNvalueChangedCallback,
422 		 xm_generic_callback, instance);
423   XtVaSetValues (widget, XmNset, val->selected,
424 		 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
425 }
426 
427 static void
xm_update_radiobox(widget_instance * instance,Widget widget,widget_value * val)428 xm_update_radiobox (widget_instance* instance,
429                     Widget widget,
430                     widget_value* val)
431 
432 {
433   Widget toggle;
434   widget_value* cur;
435 
436   /* update the callback */
437   XtRemoveAllCallbacks (widget, XmNentryCallback);
438   XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
439 
440   /* first update all the toggles */
441   /* Energize kernel interface is currently bad.  It sets the selected widget
442      with the selected flag but returns it by its name.  So we currently
443      have to support both setting the selection with the selected slot
444      of val contents and setting it with the "value" slot of val.  The latter
445      has a higher priority.  This to be removed when the kernel is fixed. */
446   for (cur = val->contents; cur; cur = cur->next)
447     {
448       toggle = XtNameToWidget (widget, cur->value);
449       if (toggle)
450 	{
451 	  XtSetSensitive (toggle, cur->enabled);
452 	  if (!val->value && cur->selected)
453 	    XtVaSetValues (toggle, XmNset, cur->selected, NULL);
454 	  if (val->value && strcmp (val->value, cur->value))
455 	    XtVaSetValues (toggle, XmNset, False, NULL);
456 	}
457     }
458 
459   /* The selected was specified by the value slot */
460   if (val->value)
461     {
462       toggle = XtNameToWidget (widget, val->value);
463       if (toggle)
464 	XtVaSetValues (toggle, XmNset, True, NULL);
465     }
466 }
467 
468 
469 /* update a popup menu, pulldown menu or a menubar */
470 
471 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep.  */
472 
473 static void
make_menu_in_widget(widget_instance * instance,Widget widget,widget_value * val,int keep_first_children)474 make_menu_in_widget (widget_instance* instance,
475                      Widget widget,
476                      widget_value* val,
477                      int keep_first_children)
478 {
479   Widget* children = 0;
480   int num_children;
481   int child_index;
482   widget_value* cur;
483   Widget button = 0;
484   Widget menu;
485   Arg al [256];
486   int ac;
487   Boolean menubar_p;
488   unsigned char type;
489 
490   Widget* old_children;
491   unsigned int old_num_children;
492 
493   /* Disable drag and drop for labels in menu bar.  */
494   static char overrideTrans[] = "<Btn2Down>: Noop()";
495   XtTranslations override = XtParseTranslationTable (overrideTrans);
496 
497   old_children = XtCompositeChildren (widget, &old_num_children);
498 
499   /* Allocate the children array */
500   for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
501     ;
502   children = (Widget*)(void*)XtMalloc (num_children * sizeof (Widget));
503 
504   /* WIDGET should be a RowColumn.  */
505   if (!XmIsRowColumn (widget))
506     emacs_abort ();
507 
508   /* Determine whether WIDGET is a menu bar.  */
509   type = -1;
510   XtSetArg (al[0], XmNrowColumnType, &type);
511   XtGetValues (widget, al, 1);
512   if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
513     emacs_abort ();
514   menubar_p = type == XmMENU_BAR;
515 
516   /* Add a callback to popups and pulldowns that is called when
517      it is made invisible again.  */
518   if (!menubar_p)
519     XtAddCallback (XtParent (widget), XmNpopdownCallback,
520 		   xm_pop_down_callback, (XtPointer)instance);
521 
522   /* Preserve the first KEEP_FIRST_CHILDREN old children.  */
523   for (child_index = 0, cur = val; child_index < keep_first_children;
524        child_index++, cur = cur->next)
525     children[child_index] = old_children[child_index];
526 
527   /* Check that those are all we have
528      (the caller should have deleted the rest).  */
529   if (old_num_children != keep_first_children)
530     emacs_abort ();
531 
532   /* Create the rest.  */
533   for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
534     {
535       enum menu_separator separator;
536 
537       ac = 0;
538       XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
539       XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
540       XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
541 
542       if (instance->pop_up_p && !cur->contents && !cur->call_data
543 	  && !lw_separator_p (cur->name, &separator, 1))
544 	{
545 	  ac = 0;
546 	  XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
547 	  button = XmCreateLabel (widget, cur->name, al, ac);
548 	}
549       else if (lw_separator_p (cur->name, &separator, 1))
550 	{
551 	  ac = 0;
552 	  XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
553 	  button = XmCreateSeparator (widget, cur->name, al, ac);
554 	}
555       else if (!cur->contents)
556 	{
557 	  if (menubar_p)
558 	    button = XmCreateCascadeButton (widget, cur->name, al, ac);
559 	  else if (!cur->call_data)
560 	    button = XmCreateLabel (widget, cur->name, al, ac);
561 	  else if (cur->button_type == BUTTON_TYPE_TOGGLE
562 		   || cur->button_type == BUTTON_TYPE_RADIO)
563 	    {
564 	      XtSetArg (al[ac], XmNset, cur->selected); ++ac;
565 	      XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
566 	      XtSetArg (al[ac], XmNindicatorType,
567 			(cur->button_type == BUTTON_TYPE_TOGGLE
568 			 ? XmN_OF_MANY : XmONE_OF_MANY));
569 	      ++ac;
570 	      button = XmCreateToggleButton (widget, cur->name, al, ac);
571 	      XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
572 	      XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
573 	    }
574 	  else
575 	    {
576 	      button = XmCreatePushButton (widget, cur->name, al, ac);
577 	      XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
578 	      XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
579 	    }
580 
581 	  xm_update_label (instance, button, cur);
582 
583 	  /* Add a callback that is called when the button is
584 	     selected.  Toggle buttons don't support
585 	     XmNactivateCallback, we use XmNvalueChangedCallback in
586 	     that case.  Don't add a callback to a simple label.  */
587 	  if (cur->button_type)
588 	    xm_update_toggle (instance, button, cur);
589 	  else if (cur->call_data)
590 	    XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
591 			   (XtPointer)instance);
592 	}
593       else
594 	{
595 	  menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
596 
597 	  make_menu_in_widget (instance, menu, cur->contents, 0);
598           XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
599 	  button = XmCreateCascadeButton (widget, cur->name, al, ac);
600 
601 	  xm_update_label (instance, button, cur);
602 
603 	  XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
604 			 (XtPointer)instance);
605           XtOverrideTranslations (button, override);
606 
607 	}
608 
609       children[child_index] = button;
610     }
611 
612   /* Last entry is the help button.  The original comment read "Has to
613      be done after managing the buttons otherwise the menubar is only
614      4 pixels high."  This is no longer true, and to make
615      XmNmenuHelpWidget work, we need to set it before managing the
616      children.. --gerd.  */
617   if (button)
618     XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
619 
620   if (num_children)
621     XtManageChildren (children, num_children);
622 
623   XtFree ((char *) children);
624   if (old_children)
625     XtFree ((char *) old_children);
626 }
627 
628 static void
update_one_menu_entry(widget_instance * instance,Widget widget,widget_value * val,Boolean deep_p)629 update_one_menu_entry (widget_instance* instance,
630                        Widget widget,
631                        widget_value* val,
632                        Boolean deep_p)
633 {
634   Arg al [256];
635   int ac;
636   Widget menu;
637   widget_value* contents;
638 
639   if (val->this_one_change == NO_CHANGE)
640     return;
641 
642   /* update the sensitivity and userdata */
643   /* Common to all widget types */
644   XtSetSensitive (widget, val->enabled);
645   XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
646 
647   /* update the menu button as a label. */
648   if (val->this_one_change >= VISIBLE_CHANGE)
649     {
650       xm_update_label (instance, widget, val);
651       if (val->button_type)
652 	xm_update_toggle (instance, widget, val);
653     }
654 
655   /* update the pulldown/pullaside as needed */
656   ac = 0;
657   menu = NULL;
658   XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
659   XtGetValues (widget, al, ac);
660 
661   contents = val->contents;
662 
663   if (!menu)
664     {
665       if (contents)
666 	{
667 	  unsigned int old_num_children, i;
668 	  Widget parent;
669 	  Widget *widget_list;
670 
671 	  parent = XtParent (widget);
672 	  widget_list = XtCompositeChildren (parent, &old_num_children);
673 
674 	  /* Find the widget position within the parent's widget list.  */
675 	  for (i = 0; i < old_num_children; i++)
676 	    if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
677 	      break;
678 	  if (i == old_num_children)
679 	    emacs_abort ();
680 	  if (XmIsCascadeButton (widget_list[i]))
681 	    {
682 	      menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
683 	      make_menu_in_widget (instance, menu, contents, 0);
684 	      ac = 0;
685 	      XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
686 	      XtSetValues (widget, al, ac);
687 	    }
688 	  else
689 	    {
690 	      Widget button;
691 
692 	      /* The current menuitem is a XmPushButtonGadget, it
693 		 needs to be replaced by a CascadeButtonGadget */
694 	      XtDestroyWidget (widget_list[i]);
695 	      menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
696 	      make_menu_in_widget (instance, menu, contents, 0);
697 	      ac = 0;
698 	      XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
699 	      /* Non-zero values don't work reliably in
700 		 conjunction with Emacs' event loop */
701 	      XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
702 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0.  */
703 	      /* Tell Motif to put it in the right place */
704 	      XtSetArg (al [ac], XmNpositionIndex , i); ac++;
705 #endif
706 	      button = XmCreateCascadeButton (parent, val->name, al, ac);
707 	      xm_update_label (instance, button, val);
708 
709 	      XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
710 			     (XtPointer)instance);
711 	      XtManageChild (button);
712 	    }
713 
714           if (widget_list)
715             XtFree ((char*) widget_list);
716 	}
717     }
718   else if (!contents)
719     {
720       ac = 0;
721       XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
722       XtSetValues (widget, al, ac);
723       XtDestroyWidget (menu);
724     }
725   else if (deep_p && contents->change != NO_CHANGE)
726     xm_update_menu (instance, menu, val, 1);
727 }
728 
729 static void
xm_update_menu(widget_instance * instance,Widget widget,widget_value * val,Boolean deep_p)730 xm_update_menu (widget_instance* instance,
731                 Widget widget,
732                 widget_value* val,
733                 Boolean deep_p)
734 {
735   Widget* children;
736   unsigned int num_children;
737   int num_children_to_keep = 0;
738   int i;
739   widget_value* cur;
740 
741   children = XtCompositeChildren (widget, &num_children);
742 
743   /* Widget is a RowColumn widget whose contents have to be updated
744    * to reflect the list of items in val->contents */
745 
746   /* See how many buttons we can keep, and how many we
747      must completely replace.  */
748   if (val->contents == 0)
749     num_children_to_keep = 0;
750   else if (val->contents->change == STRUCTURAL_CHANGE)
751     {
752       if (children)
753 	{
754 	  for (i = 0, cur = val->contents;
755                (i < num_children
756 		&& cur); /* how else to ditch unwanted children ?? - mgd */
757 	       i++, cur = cur->next)
758 	    {
759 	      if (cur->this_one_change == STRUCTURAL_CHANGE)
760 		break;
761 	    }
762 
763 	  num_children_to_keep = i;
764 	}
765     }
766   else
767     num_children_to_keep = num_children;
768 
769   /* Update all the buttons of the RowColumn, in order,
770      except for those we are going to replace entirely.  */
771   if (children)
772     {
773       for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
774 	{
775 	  if (!cur)
776 	    {
777 	      num_children_to_keep = i;
778 	      break;
779 	    }
780 	  if (children [i]->core.being_destroyed
781 	      || strcmp (XtName (children [i]), cur->name))
782 	    continue;
783 	  update_one_menu_entry (instance, children [i], cur, deep_p);
784 	  cur = cur->next;
785 	}
786     }
787 
788   /* Now replace from scratch all the buttons after the last
789      place that the top-level structure changed.  */
790   if (val->contents && val->contents->change == STRUCTURAL_CHANGE)
791     {
792       destroy_all_children (widget, num_children_to_keep);
793       make_menu_in_widget (instance, widget, val->contents,
794                            num_children_to_keep);
795     }
796 
797   XtFree ((char *) children);
798 }
799 
800 
801 /* update text widgets */
802 
803 static void
xm_update_text(widget_instance * instance,Widget widget,widget_value * val)804 xm_update_text (widget_instance* instance,
805                 Widget widget,
806                 widget_value* val)
807 {
808   XmTextSetString (widget, val->value ? val->value : "");
809   XtRemoveAllCallbacks (widget, XmNactivateCallback);
810   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
811   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
812   XtAddCallback (widget, XmNvalueChangedCallback,
813 		 xm_internal_update_other_instances, instance);
814 }
815 
816 static void
xm_update_text_field(widget_instance * instance,Widget widget,widget_value * val)817 xm_update_text_field (widget_instance* instance,
818                       Widget widget,
819                       widget_value* val)
820 {
821   XmTextFieldSetString (widget, val->value ? val->value : "");
822   XtRemoveAllCallbacks (widget, XmNactivateCallback);
823   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
824   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
825   XtAddCallback (widget, XmNvalueChangedCallback,
826 		 xm_internal_update_other_instances, instance);
827 }
828 
829 
830 /* update a motif widget */
831 
832 void
xm_update_one_widget(widget_instance * instance,Widget widget,widget_value * val,Boolean deep_p)833 xm_update_one_widget (widget_instance* instance,
834                       Widget widget,
835                       widget_value* val,
836                       Boolean deep_p)
837 {
838   WidgetClass class;
839 
840   /* Mark as not edited */
841   val->edited = False;
842 
843   /* Common to all widget types */
844   XtSetSensitive (widget, val->enabled);
845   XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
846 
847   /* Common to all label like widgets */
848   if (XtIsSubclass (widget, xmLabelWidgetClass))
849     xm_update_label (instance, widget, val);
850 
851   class = XtClass (widget);
852   /* Class specific things */
853   if (class == xmPushButtonWidgetClass ||
854       class == xmArrowButtonWidgetClass)
855     {
856       xm_update_pushbutton (instance, widget, val);
857     }
858   else if (class == xmCascadeButtonWidgetClass)
859     {
860       xm_update_cascadebutton (instance, widget, val);
861     }
862   else if (class == xmToggleButtonWidgetClass
863 	   || class == xmToggleButtonGadgetClass)
864     {
865       xm_update_toggle (instance, widget, val);
866     }
867   else if (class == xmRowColumnWidgetClass)
868     {
869       Boolean radiobox = 0;
870       int ac = 0;
871       Arg al [1];
872 
873       XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
874       XtGetValues (widget, al, ac);
875 
876       if (radiobox)
877 	xm_update_radiobox (instance, widget, val);
878       else
879 	xm_update_menu (instance, widget, val, deep_p);
880     }
881   else if (class == xmTextWidgetClass)
882     {
883       xm_update_text (instance, widget, val);
884     }
885   else if (class == xmTextFieldWidgetClass)
886     {
887       xm_update_text_field (instance, widget, val);
888     }
889   else if (class == xmListWidgetClass)
890     {
891       xm_update_list (instance, widget, val);
892     }
893 }
894 
895 /* getting the value back */
896 void
xm_update_one_value(widget_instance * instance,Widget widget,widget_value * val)897 xm_update_one_value (widget_instance* instance,
898                      Widget widget,
899                      widget_value* val)
900 {
901   WidgetClass class = XtClass (widget);
902   widget_value *old_wv;
903 
904   /* copy the call_data slot into the "return" widget_value */
905   for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
906     if (!strcmp (val->name, old_wv->name))
907       {
908 	val->call_data = old_wv->call_data;
909 	break;
910       }
911 
912   if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
913     {
914       XtVaGetValues (widget, XmNset, &val->selected, NULL);
915       val->edited = True;
916     }
917   else if (class == xmTextWidgetClass)
918     {
919       xfree (val->value);
920       val->value = XmTextGetString (widget);
921       val->edited = True;
922     }
923   else if (class == xmTextFieldWidgetClass)
924     {
925       xfree (val->value);
926       val->value = XmTextFieldGetString (widget);
927       val->edited = True;
928     }
929   else if (class == xmRowColumnWidgetClass)
930     {
931       Boolean radiobox = 0;
932       int ac = 0;
933       Arg al [1];
934 
935       XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
936       XtGetValues (widget, al, ac);
937 
938       if (radiobox)
939 	{
940 	  CompositeWidget radio = (CompositeWidget)widget;
941 	  int i;
942 	  for (i = 0; i < radio->composite.num_children; i++)
943 	    {
944 	      int set = False;
945 	      Widget toggle = radio->composite.children [i];
946 
947 	      XtVaGetValues (toggle, XmNset, &set, NULL);
948 	      if (set)
949 		dupstring (&val->value, XtName (toggle));
950 	    }
951 	  val->edited = True;
952 	}
953     }
954   else if (class == xmListWidgetClass)
955     {
956       int pos_cnt;
957       int* pos_list;
958       if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
959 	{
960 	  int i;
961 	  widget_value* cur;
962 	  for (cur = val->contents, i = 0; cur; cur = cur->next)
963 	    if (cur->value)
964 	      {
965 		int j;
966 		cur->selected = False;
967 		i += 1;
968 		for (j = 0; j < pos_cnt; j++)
969 		  if (pos_list [j] == i)
970 		    {
971 		      cur->selected = True;
972 		      val->value = xstrdup (cur->name);
973 		    }
974 	      }
975 	  val->edited = 1;
976 	  XtFree ((char *) pos_list);
977 	}
978     }
979 }
980 
981 
982 /* This function is for activating a button from a program.  It's wrong because
983    we pass a NULL argument in the call_data which is not Motif compatible.
984    This is used from the XmNdefaultAction callback of the List widgets to
985    have a double-click put down a dialog box like the button would do.
986    I could not find a way to do that with accelerators.
987  */
988 static void
activate_button(Widget widget,XtPointer closure,XtPointer call_data)989 activate_button (Widget widget,
990                  XtPointer closure,
991                  XtPointer call_data)
992 {
993   Widget button = (Widget)closure;
994   XtCallCallbacks (button, XmNactivateCallback, NULL);
995 }
996 
997 /* creation functions */
998 
999 /* Called for key press in dialogs.  Used to pop down dialog on ESC.  */
1000 static void
dialog_key_cb(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)1001 dialog_key_cb (Widget widget,
1002                XtPointer closure,
1003                XEvent *event,
1004                Boolean *continue_to_dispatch)
1005 {
1006   KeySym sym = 0;
1007   Modifiers modif_ret;
1008 
1009   XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1010                       &modif_ret, &sym);
1011 
1012   if (sym == osfXK_Cancel)
1013     {
1014       Widget w = *((Widget *) closure);
1015 
1016       while (w && ! XtIsShell (w))
1017         w = XtParent (w);
1018 
1019       if (XtIsShell (w)) XtPopdown (w);
1020     }
1021 
1022   *continue_to_dispatch = TRUE;
1023 }
1024 
1025 /* dialogs */
1026 static Widget
make_dialog(char * name,Widget parent,Boolean pop_up_p,char * shell_title,char * icon_name,Boolean text_input_slot,Boolean radio_box,Boolean list,int left_buttons,int right_buttons)1027 make_dialog (char* name,
1028              Widget parent,
1029              Boolean pop_up_p,
1030              char* shell_title,
1031              char* icon_name,
1032              Boolean text_input_slot,
1033              Boolean radio_box,
1034              Boolean list,
1035              int left_buttons,
1036              int right_buttons)
1037 {
1038   Widget result;
1039   Widget form;
1040   Widget row;
1041   Widget icon;
1042   Widget icon_separator;
1043   Widget message_label;
1044   Widget value = 0;
1045   Widget separator;
1046   Widget button = 0;
1047   Widget children [16];		/* for the final XtManageChildren */
1048   int	 n_children;
1049   Arg 	al[64];			/* Arg List */
1050   int 	ac;			/* Arg Count */
1051   int 	i;
1052 
1053   if (pop_up_p)
1054     {
1055       ac = 0;
1056       XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1057       XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1058       XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1059       result = XmCreateDialogShell (parent, "dialog", al, ac);
1060       ac = 0;
1061       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1062 /*      XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1063       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1064       form = XmCreateForm (result, shell_title, al, ac);
1065     }
1066   else
1067     {
1068       ac = 0;
1069       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1070       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1071       form = XmCreateForm (parent, shell_title, al, ac);
1072       result = form;
1073     }
1074 
1075   n_children = left_buttons + right_buttons + 1;
1076   ac = 0;
1077   XtSetArg(al[ac], XmNpacking, n_children == 3?
1078 	   XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1079   XtSetArg(al[ac], XmNorientation, n_children == 3?
1080 	   XmVERTICAL: XmHORIZONTAL); ac++;
1081   XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1082   XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1083   XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1084   XtSetArg(al[ac], XmNspacing, 13); ac++;
1085   XtSetArg(al[ac], XmNadjustLast, False); ac++;
1086   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1087   XtSetArg(al[ac], XmNisAligned, True); ac++;
1088   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1089   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1090   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1091   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1092   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1093   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1094   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1095   row = XmCreateRowColumn (form, "row", al, ac);
1096 
1097   n_children = 0;
1098   for (i = 0; i < left_buttons; i++)
1099     {
1100       char button_name [16];
1101       sprintf (button_name, "button%d", i + 1);
1102       ac = 0;
1103       if (i == 0)
1104 	{
1105 	  XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1106 	  XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1107 	}
1108       XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1109       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1110       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1111       XtAddEventHandler (children [n_children],
1112                          KeyPressMask, False, dialog_key_cb, result);
1113 
1114       if (i == 0)
1115 	{
1116 	  button = children [n_children];
1117 	  ac = 0;
1118 	  XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1119 	  XtSetValues (row, al, ac);
1120 	}
1121 
1122       n_children++;
1123     }
1124 
1125   /* invisible separator button */
1126   ac = 0;
1127   XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1128   children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1129   n_children++;
1130 
1131   for (i = 0; i < right_buttons; i++)
1132     {
1133       char button_name [16];
1134       sprintf (button_name, "button%d", left_buttons + i + 1);
1135       ac = 0;
1136       XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1137       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1138       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1139       XtAddEventHandler (children [n_children],
1140                          KeyPressMask, False, dialog_key_cb, result);
1141 
1142       if (! button) button = children [n_children];
1143       n_children++;
1144     }
1145 
1146   XtManageChildren (children, n_children);
1147 
1148   ac = 0;
1149   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1150   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1151   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1152   XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1153   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1154   XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1155   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1156   XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1157   separator = XmCreateSeparator (form, "", al, ac);
1158 
1159   ac = 0;
1160   XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1161   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1162   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1163   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1164   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1165   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1166   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1167   icon = XmCreateLabel (form, icon_name, al, ac);
1168 
1169   ac = 0;
1170   XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1171   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1172   XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1173   XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1174   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1175   XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1176   XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1177   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1178   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1179   icon_separator = XmCreateLabel (form, "", al, ac);
1180 
1181   if (text_input_slot)
1182     {
1183       ac = 0;
1184       XtSetArg(al[ac], XmNcolumns, 50); ac++;
1185       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1186       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1187       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1188       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1189       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1190       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1191       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1192       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1193       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1194       value = XmCreateTextField (form, "value", al, ac);
1195     }
1196   else if (radio_box)
1197     {
1198       Widget radio_butt;
1199       ac = 0;
1200       XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1201       XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1202       XtSetArg(al[ac], XmNspacing, 13); ac++;
1203       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1204       XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1205       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1206       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1207       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1208       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1209       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1210       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1211       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1212       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1213       value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1214       ac = 0;
1215       i = 0;
1216       radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1217       children [i++] = radio_butt;
1218       radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1219       children [i++] = radio_butt;
1220       radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1221       children [i++] = radio_butt;
1222       XtManageChildren (children, i);
1223     }
1224   else if (list)
1225     {
1226       ac = 0;
1227       XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1228       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1229       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1230       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1231       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1232       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1233       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1234       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1235       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1236       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1237       value = XmCreateScrolledList (form, "list", al, ac);
1238 
1239       /* this is the easiest way I found to have the dble click in the
1240 	 list activate the default button */
1241       XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1242     }
1243 
1244   ac = 0;
1245   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1246   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1247   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1248   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1249   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1250   XtSetArg(al[ac], XmNbottomWidget,
1251 	   text_input_slot || radio_box || list ? value : separator); ac++;
1252   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1253   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1254   XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1255   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1256   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1257   message_label = XmCreateLabel (form, "message", al, ac);
1258 
1259   if (list)
1260     XtManageChild (value);
1261 
1262   i = 0;
1263   children [i] = row; i++;
1264   children [i] = separator; i++;
1265   if (text_input_slot || radio_box)
1266     {
1267       children [i] = value; i++;
1268     }
1269   children [i] = message_label; i++;
1270   children [i] = icon; i++;
1271   children [i] = icon_separator; i++;
1272   XtManageChildren (children, i);
1273 
1274   if (text_input_slot || list)
1275     {
1276       XtInstallAccelerators (value, button);
1277       XtSetKeyboardFocus (result, value);
1278     }
1279   else
1280     {
1281       XtInstallAccelerators (form, button);
1282       XtSetKeyboardFocus (result, button);
1283     }
1284 
1285   return result;
1286 }
1287 
1288 static destroyed_instance*
find_matching_instance(widget_instance * instance)1289 find_matching_instance (widget_instance* instance)
1290 {
1291   destroyed_instance*	cur;
1292   destroyed_instance*	prev;
1293   char*	type = instance->info->type;
1294   char*	name = instance->info->name;
1295 
1296   for (prev = NULL, cur = all_destroyed_instances;
1297        cur;
1298        prev = cur, cur = cur->next)
1299     {
1300       if (!strcmp (cur->name, name)
1301 	  && !strcmp (cur->type, type)
1302 	  && cur->parent == instance->parent
1303 	  && cur->pop_up_p == instance->pop_up_p)
1304 	{
1305 	  if (prev)
1306 	    prev->next = cur->next;
1307 	  else
1308 	    all_destroyed_instances = cur->next;
1309 	  return cur;
1310 	}
1311       /* do some cleanup */
1312       else if (!cur->widget)
1313 	{
1314 	  if (prev)
1315 	    prev->next = cur->next;
1316 	  else
1317 	    all_destroyed_instances = cur->next;
1318 	  free_destroyed_instance (cur);
1319 	  cur = prev ? prev : all_destroyed_instances;
1320 	}
1321     }
1322   return NULL;
1323 }
1324 
1325 static void
mark_dead_instance_destroyed(Widget widget,XtPointer closure,XtPointer call_data)1326 mark_dead_instance_destroyed (Widget widget,
1327                               XtPointer closure,
1328                               XtPointer call_data)
1329 {
1330   destroyed_instance* instance = (destroyed_instance*)closure;
1331   instance->widget = NULL;
1332 }
1333 
1334 static void
recenter_widget(Widget widget)1335 recenter_widget (Widget widget)
1336 {
1337   Widget parent = XtParent (widget);
1338   Screen* screen = XtScreen (widget);
1339   Dimension screen_width = WidthOfScreen (screen);
1340   Dimension screen_height = HeightOfScreen (screen);
1341   Dimension parent_width = 0;
1342   Dimension parent_height = 0;
1343   Dimension child_width = 0;
1344   Dimension child_height = 0;
1345   Position x;
1346   Position y;
1347 
1348   XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1349   XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1350 		 NULL);
1351 
1352   x = (((Position)parent_width) - ((Position)child_width)) / 2;
1353   y = (((Position)parent_height) - ((Position)child_height)) / 2;
1354 
1355   XtTranslateCoords (parent, x, y, &x, &y);
1356 
1357   if (x + child_width > screen_width)
1358     x = screen_width - child_width;
1359   if (x < 0)
1360     x = 0;
1361 
1362   if (y + child_height > screen_height)
1363     y = screen_height - child_height;
1364   if (y < 0)
1365     y = 0;
1366 
1367   XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1368 }
1369 
1370 static Widget
recycle_instance(destroyed_instance * instance)1371 recycle_instance (destroyed_instance* instance)
1372 {
1373   Widget widget = instance->widget;
1374 
1375   /* widget is NULL if the parent was destroyed. */
1376   if (widget)
1377     {
1378       Widget focus;
1379       Widget separator;
1380 
1381       /* Remove the destroy callback as the instance is not in the list
1382 	 anymore */
1383       XtRemoveCallback (instance->parent, XtNdestroyCallback,
1384 			mark_dead_instance_destroyed,
1385 			(XtPointer)instance);
1386 
1387       /* Give the focus to the initial item */
1388       focus = XtNameToWidget (widget, "*value");
1389       if (!focus)
1390 	focus = XtNameToWidget (widget, "*button1");
1391       if (focus)
1392 	XtSetKeyboardFocus (widget, focus);
1393 
1394       /* shrink the separator label back to their original size */
1395       separator = XtNameToWidget (widget, "*separator_button");
1396       if (separator)
1397 	XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1398 
1399       /* Center the dialog in its parent */
1400       recenter_widget (widget);
1401     }
1402   free_destroyed_instance (instance);
1403   return widget;
1404 }
1405 
1406 Widget
xm_create_dialog(widget_instance * instance)1407 xm_create_dialog (widget_instance* instance)
1408 {
1409   char* 	name = instance->info->type;
1410   Widget 	parent = instance->parent;
1411   Widget	widget;
1412   Boolean 	pop_up_p = instance->pop_up_p;
1413   char*		shell_name = 0;
1414   char* 	icon_name = 0;
1415   Boolean	text_input_slot = False;
1416   Boolean	radio_box = False;
1417   Boolean	list = False;
1418   int		total_buttons;
1419   int		left_buttons = 0;
1420   int		right_buttons = 1;
1421   destroyed_instance*	dead_one;
1422 
1423   /* try to find a widget to recycle */
1424   dead_one = find_matching_instance (instance);
1425   if (dead_one)
1426     {
1427       Widget recycled_widget = recycle_instance (dead_one);
1428       if (recycled_widget)
1429 	return recycled_widget;
1430     }
1431 
1432   switch (name [0]){
1433   case 'E': case 'e':
1434     icon_name = "dbox-error";
1435     shell_name = "Error";
1436     break;
1437 
1438   case 'I': case 'i':
1439     icon_name = "dbox-info";
1440     shell_name = "Information";
1441     break;
1442 
1443   case 'L': case 'l':
1444     list = True;
1445     icon_name = "dbox-question";
1446     shell_name = "Prompt";
1447     break;
1448 
1449   case 'P': case 'p':
1450     text_input_slot = True;
1451     icon_name = "dbox-question";
1452     shell_name = "Prompt";
1453     break;
1454 
1455   case 'Q': case 'q':
1456     icon_name = "dbox-question";
1457     shell_name = "Question";
1458     break;
1459   }
1460 
1461   total_buttons = name [1] - '0';
1462 
1463   if (name [3] == 'T' || name [3] == 't')
1464     {
1465       text_input_slot = False;
1466       radio_box = True;
1467     }
1468   else if (name [3])
1469     right_buttons = name [4] - '0';
1470 
1471   left_buttons = total_buttons - right_buttons;
1472 
1473   widget = make_dialog (name, parent, pop_up_p,
1474 			shell_name, icon_name, text_input_slot, radio_box,
1475 			list, left_buttons, right_buttons);
1476 
1477   XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1478 		 (XtPointer) instance);
1479 
1480   return widget;
1481 }
1482 
1483 /* Create a menu bar.  We turn off the f10 key
1484    because we have not yet managed to make it work right in Motif.  */
1485 
1486 static Widget
make_menubar(widget_instance * instance)1487 make_menubar (widget_instance* instance)
1488 {
1489   Arg al[3];
1490   int ac;
1491 
1492   ac = 0;
1493   XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1494   return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1495 }
1496 
1497 static void
remove_grabs(Widget shell,XtPointer closure,XtPointer call_data)1498 remove_grabs (Widget shell,
1499               XtPointer closure,
1500               XtPointer call_data)
1501 {
1502   Widget menu = (Widget) closure;
1503   XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1504 }
1505 
1506 static Widget
make_popup_menu(widget_instance * instance)1507 make_popup_menu (widget_instance* instance)
1508 {
1509   Widget parent = instance->parent;
1510   Window parent_window = parent->core.window;
1511   Widget result;
1512 
1513   /* sets the parent window to 0 to fool Motif into not generating a grab */
1514   parent->core.window = 0;
1515   result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1516   XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1517 		 (XtPointer)result);
1518   parent->core.window = parent_window;
1519   return result;
1520 }
1521 
1522 static Widget
make_main(widget_instance * instance)1523 make_main (widget_instance* instance)
1524 {
1525   Widget parent = instance->parent;
1526   Widget result;
1527   Arg al[2];
1528   int ac;
1529 
1530   ac = 0;
1531   XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1532   XtSetArg (al[ac], XmNspacing, 0); ac++;
1533   result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1534   return result;
1535 }
1536 
1537 /* Table of functions to create widgets */
1538 
1539 #ifdef ENERGIZE
1540 
1541 /* interface with the XDesigner generated functions */
1542 typedef Widget (*widget_maker) (Widget);
1543 extern Widget create_project_p_sheet (Widget parent);
1544 extern Widget create_debugger_p_sheet (Widget parent);
1545 extern Widget create_breaklist_p_sheet (Widget parent);
1546 extern Widget create_le_browser_p_sheet (Widget parent);
1547 extern Widget create_class_browser_p_sheet (Widget parent);
1548 extern Widget create_call_browser_p_sheet (Widget parent);
1549 extern Widget create_build_dialog (Widget parent);
1550 extern Widget create_editmode_dialog (Widget parent);
1551 extern Widget create_search_dialog (Widget parent);
1552 extern Widget create_project_display_dialog (Widget parent);
1553 
1554 static Widget
make_one(widget_instance * instance,widget_maker fn)1555 make_one (widget_instance* instance, widget_maker fn)
1556 {
1557   Widget result;
1558   Arg 	al [64];
1559   int 	ac = 0;
1560 
1561   if (instance->pop_up_p)
1562     {
1563       XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1564       result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1565       XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1566 		     (XtPointer) instance);
1567       (*fn) (result);
1568     }
1569   else
1570     {
1571       result = (*fn) (instance->parent);
1572       XtRealizeWidget (result);
1573     }
1574   return result;
1575 }
1576 
1577 static Widget
make_project_p_sheet(widget_instance * instance)1578 make_project_p_sheet (widget_instance* instance)
1579 {
1580   return make_one (instance, create_project_p_sheet);
1581 }
1582 
1583 static Widget
make_debugger_p_sheet(widget_instance * instance)1584 make_debugger_p_sheet (widget_instance* instance)
1585 {
1586   return make_one (instance, create_debugger_p_sheet);
1587 }
1588 
1589 static Widget
make_breaklist_p_sheet(widget_instance * instance)1590 make_breaklist_p_sheet (widget_instance* instance)
1591 {
1592   return make_one (instance, create_breaklist_p_sheet);
1593 }
1594 
1595 static Widget
make_le_browser_p_sheet(widget_instance * instance)1596 make_le_browser_p_sheet (widget_instance* instance)
1597 {
1598   return make_one (instance, create_le_browser_p_sheet);
1599 }
1600 
1601 static Widget
make_class_browser_p_sheet(widget_instance * instance)1602 make_class_browser_p_sheet (widget_instance* instance)
1603 {
1604   return make_one (instance, create_class_browser_p_sheet);
1605 }
1606 
1607 static Widget
make_call_browser_p_sheet(widget_instance * instance)1608 make_call_browser_p_sheet (widget_instance* instance)
1609 {
1610   return make_one (instance, create_call_browser_p_sheet);
1611 }
1612 
1613 static Widget
make_build_dialog(widget_instance * instance)1614 make_build_dialog (widget_instance* instance)
1615 {
1616   return make_one (instance, create_build_dialog);
1617 }
1618 
1619 static Widget
make_editmode_dialog(widget_instance * instance)1620 make_editmode_dialog (widget_instance* instance)
1621 {
1622   return make_one (instance, create_editmode_dialog);
1623 }
1624 
1625 static Widget
make_search_dialog(widget_instance * instance)1626 make_search_dialog (widget_instance* instance)
1627 {
1628   return make_one (instance, create_search_dialog);
1629 }
1630 
1631 static Widget
make_project_display_dialog(widget_instance * instance)1632 make_project_display_dialog (widget_instance* instance)
1633 {
1634   return make_one (instance, create_project_display_dialog);
1635 }
1636 
1637 #endif /* ENERGIZE */
1638 
1639 widget_creation_entry
1640 xm_creation_table [] =
1641 {
1642   {"menubar", 			make_menubar},
1643   {"popup",			make_popup_menu},
1644   {"main",			make_main},
1645 #ifdef ENERGIZE
1646   {"project_p_sheet",		make_project_p_sheet},
1647   {"debugger_p_sheet",		make_debugger_p_sheet},
1648   {"breaklist_psheet",		make_breaklist_p_sheet},
1649   {"leb_psheet",       		make_le_browser_p_sheet},
1650   {"class_browser_psheet",	make_class_browser_p_sheet},
1651   {"ctree_browser_psheet",	make_call_browser_p_sheet},
1652   {"build",			make_build_dialog},
1653   {"editmode",			make_editmode_dialog},
1654   {"search",			make_search_dialog},
1655   {"project_display",		make_project_display_dialog},
1656 #endif /* ENERGIZE */
1657   {NULL, NULL}
1658 };
1659 
1660 /* Destruction of instances */
1661 void
xm_destroy_instance(widget_instance * instance)1662 xm_destroy_instance ( widget_instance* instance)
1663 {
1664   Widget widget = instance->widget;
1665   /* recycle the dialog boxes */
1666   /* Disable the recycling until we can find a way to have the dialog box
1667      get reasonable layout after we modify its contents. */
1668   if (0
1669       && XtClass (widget) == xmDialogShellWidgetClass)
1670     {
1671       destroyed_instance* dead_instance =
1672 	make_destroyed_instance (instance->info->name,
1673 				 instance->info->type,
1674 				 instance->widget,
1675 				 instance->parent,
1676 				 instance->pop_up_p);
1677       dead_instance->next = all_destroyed_instances;
1678       all_destroyed_instances = dead_instance;
1679       XtUnmanageChild (first_child (instance->widget));
1680       XFlush (XtDisplay (instance->widget));
1681       XtAddCallback (instance->parent, XtNdestroyCallback,
1682 		     mark_dead_instance_destroyed, (XtPointer)dead_instance);
1683     }
1684   else
1685     {
1686       /* This might not be necessary now that the nosel is attached to
1687 	 popdown instead of destroy, but it can't hurt. */
1688       XtRemoveCallback (instance->widget, XtNdestroyCallback,
1689 			xm_nosel_callback, (XtPointer)instance);
1690       XtDestroyWidget (instance->widget);
1691     }
1692 }
1693 
1694 /* popup utility */
1695 void
xm_popup_menu(Widget widget,XEvent * event)1696 xm_popup_menu (Widget widget, XEvent *event)
1697 {
1698   XButtonPressedEvent dummy;
1699 
1700   if (event == 0)
1701     {
1702       dummy.type = ButtonPress;
1703       dummy.serial = 0;
1704       dummy.send_event = 0;
1705       dummy.display = XtDisplay (widget);
1706       dummy.window = XtWindow (XtParent (widget));
1707       dummy.time = 0;
1708       dummy.button = 0;
1709       XQueryPointer (dummy.display, dummy.window, &dummy.root,
1710 		     &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1711 		     &dummy.x, &dummy.y, &dummy.state);
1712       event = (XEvent *) &dummy;
1713     }
1714 
1715   if (event->type == ButtonPress || event->type == ButtonRelease)
1716     {
1717       /* Setting the menuPost resource only required by Motif 1.1 and
1718 	 LessTif 0.84 and earlier.  With later versions of LessTif,
1719 	 setting menuPost is unnecessary and may cause problems, so
1720 	 don't do it.  */
1721 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1722 	{
1723 	  /* This is so totally ridiculous: there's NO WAY to tell Motif
1724 	     that *any* button can select a menu item.  Only one button
1725 	     can have that honor.  */
1726 
1727 	  char *trans = 0;
1728 	  if      (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1729 	  else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1730 	  else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1731 	  else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1732 	  else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1733 	  if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1734 	}
1735 #endif
1736 
1737       XmMenuPosition (widget, (XButtonPressedEvent *) event);
1738     }
1739 
1740   XtManageChild (widget);
1741 }
1742 
1743 static void
set_min_dialog_size(Widget w)1744 set_min_dialog_size (Widget w)
1745 {
1746   short width;
1747   short height;
1748   XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1749   XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1750 }
1751 
1752 void
xm_pop_instance(widget_instance * instance,Boolean up)1753 xm_pop_instance (widget_instance* instance, Boolean up)
1754 {
1755   Widget widget = instance->widget;
1756 
1757   if (XtClass (widget) == xmDialogShellWidgetClass)
1758     {
1759       Widget widget_to_manage = first_child (widget);
1760       if (up)
1761 	{
1762 	  XtManageChild (widget_to_manage);
1763 	  set_min_dialog_size (widget);
1764 	  XtSetKeyboardFocus (instance->parent, widget);
1765 	}
1766       else
1767 	XtUnmanageChild (widget_to_manage);
1768     }
1769   else
1770     {
1771       if (up)
1772 	XtManageChild (widget);
1773       else
1774 	XtUnmanageChild (widget);
1775     }
1776 }
1777 
1778 
1779 /* motif callback */
1780 
1781 static void
do_call(Widget widget,XtPointer closure,enum do_call_type type)1782 do_call (Widget widget,
1783          XtPointer closure,
1784          enum do_call_type type)
1785 {
1786   Arg al [256];
1787   int ac;
1788   XtPointer user_data;
1789   widget_instance* instance = (widget_instance*)closure;
1790   Widget instance_widget;
1791   LWLIB_ID id;
1792 
1793   if (!instance)
1794     return;
1795   if (widget->core.being_destroyed)
1796     return;
1797 
1798   instance_widget = instance->widget;
1799   if (!instance_widget)
1800     return;
1801 
1802   id = instance->info->id;
1803   ac = 0;
1804   user_data = NULL;
1805   XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1806   XtGetValues (widget, al, ac);
1807 
1808   switch (type)
1809     {
1810     case pre_activate:
1811       if (instance->info->pre_activate_cb)
1812 	instance->info->pre_activate_cb (widget, id, user_data);
1813       break;
1814 
1815     case selection:
1816       if (instance->info->selection_cb)
1817 	instance->info->selection_cb (widget, id, user_data);
1818       break;
1819 
1820     case no_selection:
1821       if (instance->info->selection_cb)
1822 	instance->info->selection_cb (widget, id, (XtPointer) -1);
1823       break;
1824 
1825     case post_activate:
1826       if (instance->info->post_activate_cb)
1827 	instance->info->post_activate_cb (widget, id, user_data);
1828       break;
1829 
1830     default:
1831       emacs_abort ();
1832     }
1833 }
1834 
1835 /* Like lw_internal_update_other_instances except that it does not do
1836    anything if its shell parent is not managed.  This is to protect
1837    lw_internal_update_other_instances to dereference freed memory
1838    if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1839    list */
1840 static void
xm_internal_update_other_instances(Widget widget,XtPointer closure,XtPointer call_data)1841 xm_internal_update_other_instances (Widget widget,
1842                                     XtPointer closure,
1843                                     XtPointer call_data)
1844 {
1845   Widget parent;
1846   for (parent = widget; parent; parent = XtParent (parent))
1847     if (XtIsShell (parent))
1848       break;
1849     else if (!XtIsManaged (parent))
1850       return;
1851    lw_internal_update_other_instances (widget, closure, call_data);
1852 }
1853 
1854 static void
xm_generic_callback(Widget widget,XtPointer closure,XtPointer call_data)1855 xm_generic_callback (Widget widget,
1856                      XtPointer closure,
1857                      XtPointer call_data)
1858 {
1859   lw_internal_update_other_instances (widget, closure, call_data);
1860   do_call (widget, closure, selection);
1861 }
1862 
1863 static void
xm_nosel_callback(Widget widget,XtPointer closure,XtPointer call_data)1864 xm_nosel_callback (Widget widget,
1865                    XtPointer closure,
1866                    XtPointer call_data)
1867 {
1868   /* This callback is only called when a dialog box is dismissed with
1869      the wm's destroy button (WM_DELETE_WINDOW.)  We want the dialog
1870      box to be destroyed in that case, not just unmapped, so that it
1871      releases its keyboard grabs.  But there are problems with running
1872      our callbacks while the widget is in the process of being
1873      destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1874      XmDESTROY and then destroy it ourself after having run the
1875      callback.  */
1876   do_call (widget, closure, no_selection);
1877   XtDestroyWidget (widget);
1878 }
1879 
1880 static void
xm_pull_down_callback(Widget widget,XtPointer closure,XtPointer call_data)1881 xm_pull_down_callback (Widget widget,
1882                        XtPointer closure,
1883                        XtPointer call_data)
1884 {
1885   Widget parent = XtParent (widget);
1886 
1887   if (XmIsRowColumn (parent))
1888     {
1889       unsigned char type = 0xff;
1890       XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1891       if (type == XmMENU_BAR)
1892 	do_call (widget, closure, pre_activate);
1893     }
1894 }
1895 
1896 
1897 /* XmNpopdownCallback for MenuShell widgets.  WIDGET is the MenuShell,
1898    CLOSURE is a pointer to the widget_instance of the shell,
1899 
1900    Note that this callback is called for each cascade button in a
1901    menu, whether or not its submenu is visible.  */
1902 
1903 static void
xm_pop_down_callback(Widget widget,XtPointer closure,XtPointer call_data)1904 xm_pop_down_callback (Widget widget,
1905                       XtPointer closure,
1906                       XtPointer call_data)
1907 {
1908   widget_instance *instance = (widget_instance *) closure;
1909 
1910   if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1911       || XtParent (widget) == instance->parent)
1912     do_call (widget, closure, post_activate);
1913 }
1914 
1915 
1916 /* set the keyboard focus */
1917 void
xm_set_keyboard_focus(Widget parent,Widget w)1918 xm_set_keyboard_focus (Widget parent, Widget w)
1919 {
1920   XmProcessTraversal (w, 0);
1921   XtSetKeyboardFocus (parent, w);
1922 }
1923 
1924 /* Motif hack to set the main window areas. */
1925 void
xm_set_main_areas(Widget parent,Widget menubar,Widget work_area)1926 xm_set_main_areas (Widget parent,
1927                    Widget menubar,
1928                    Widget work_area)
1929 {
1930   XmMainWindowSetAreas (parent,
1931 			menubar,	/* menubar (maybe 0) */
1932 			0,		/* command area (psheets) */
1933 			0,		/* horizontal scroll */
1934 			0,              /* vertical scroll */
1935 			work_area);	/* work area */
1936 }
1937 
1938 /* Motif hack to control resizing on the menubar. */
1939 void
xm_manage_resizing(Widget w,Boolean flag)1940 xm_manage_resizing (Widget w, Boolean flag)
1941 {
1942   XtVaSetValues (w, XtNallowShellResize, flag, NULL);
1943 }
1944