(lunar-phase): Use calendar-mod instead of % so that it
[emacs.git] / lwlib / lwlib-Xm.c
blob13d288626977842c08e32c598b91732f26582997
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdio.h>
25 #include <X11/StringDefs.h>
26 #include <X11/IntrinsicP.h>
27 #include <X11/ObjectP.h>
28 #include <X11/CoreP.h>
29 #include <X11/CompositeP.h>
31 #include "lwlib-Xm.h"
32 #include "lwlib-utils.h"
34 #include <Xm/BulletinB.h>
35 #include <Xm/CascadeB.h>
36 #include <Xm/DrawingA.h>
37 #include <Xm/FileSB.h>
38 #include <Xm/Label.h>
39 #include <Xm/List.h>
40 #include <Xm/MenuShell.h>
41 #include <Xm/MessageB.h>
42 #include <Xm/PushB.h>
43 #include <Xm/PushBG.h>
44 #include <Xm/ArrowB.h>
45 #include <Xm/SelectioB.h>
46 #include <Xm/Text.h>
47 #include <Xm/TextF.h>
48 #include <Xm/ToggleB.h>
49 #include <Xm/ToggleBG.h>
50 #include <Xm/RowColumn.h>
51 #include <Xm/ScrolledW.h>
52 #include <Xm/Separator.h>
53 #include <Xm/DialogS.h>
54 #include <Xm/Form.h>
56 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
57 static void xm_internal_update_other_instances (Widget, XtPointer,
58 XtPointer);
59 static void xm_generic_callback (Widget, XtPointer, XtPointer);
60 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
61 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
63 static void
64 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
65 Boolean deep_p);
67 \f/* Structures to keep destroyed instances */
68 typedef struct _destroyed_instance
70 char* name;
71 char* type;
72 Widget widget;
73 Widget parent;
74 Boolean pop_up_p;
75 struct _destroyed_instance* next;
76 } destroyed_instance;
78 static destroyed_instance*
79 all_destroyed_instances = NULL;
81 static destroyed_instance*
82 make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
83 Boolean pop_up_p)
85 destroyed_instance* instance =
86 (destroyed_instance*)malloc (sizeof (destroyed_instance));
87 instance->name = strdup (name);
88 instance->type = strdup (type);
89 instance->widget = widget;
90 instance->parent = parent;
91 instance->pop_up_p = pop_up_p;
92 instance->next = NULL;
93 return instance;
96 static void
97 free_destroyed_instance (destroyed_instance* instance)
99 free (instance->name);
100 free (instance->type);
101 free (instance);
104 \f/* motif utility functions */
105 Widget
106 first_child (Widget widget)
108 return ((CompositeWidget)widget)->composite.children [0];
111 Boolean
112 lw_motif_widget_p (Widget widget)
114 return
115 XtClass (widget) == xmDialogShellWidgetClass
116 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
119 static XmString
120 resource_motif_string (Widget widget, char* name)
122 XtResource resource;
123 XmString result = 0;
125 resource.resource_name = name;
126 resource.resource_class = XmCXmString;
127 resource.resource_type = XmRXmString;
128 resource.resource_size = sizeof (XmString);
129 resource.resource_offset = 0;
130 resource.default_type = XtRImmediate;
131 resource.default_addr = 0;
133 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
134 "DialogString", &resource, 1, NULL, 0);
135 return result;
138 static void
139 destroy_all_children (Widget widget)
141 Widget* children;
142 unsigned int number;
143 int i;
145 children = XtCompositeChildren (widget, &number);
146 if (children)
148 /* Unmanage all children and destroy them. They will only be
149 * really destroyed when we get out of DispatchEvent. */
150 for (i = 0; i < number; i++)
152 Widget child = children [i];
153 if (!child->core.being_destroyed)
155 XtUnmanageChild (child);
156 XtDestroyWidget (child);
159 XtFree ((char *) children);
163 \f/* update the label of anything subclass of a label */
164 static void
165 xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
167 XmString res_string = 0;
168 XmString built_string = 0;
169 XmString key_string = 0;
170 Arg al [256];
171 int ac;
173 ac = 0;
175 if (val->value)
177 res_string = resource_motif_string (widget, val->value);
179 if (res_string)
181 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
183 else
185 built_string =
186 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
187 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
189 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
192 if (val->key)
194 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
195 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
198 if (ac)
199 XtSetValues (widget, al, ac);
201 if (built_string)
202 XmStringFree (built_string);
204 if (key_string)
205 XmStringFree (key_string);
208 \f/* update of list */
209 static void
210 xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
212 widget_value* cur;
213 int i;
214 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
215 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
216 instance);
217 for (cur = val->contents, i = 0; cur; cur = cur->next)
218 if (cur->value)
220 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
221 i += 1;
222 XmListAddItem (widget, xmstr, 0);
223 if (cur->selected)
224 XmListSelectPos (widget, i, False);
225 XmStringFree (xmstr);
229 \f/* update of buttons */
230 static void
231 xm_update_pushbutton (widget_instance* instance, Widget widget,
232 widget_value* val)
234 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
235 XtRemoveAllCallbacks (widget, XmNactivateCallback);
236 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
239 static void
240 xm_update_cascadebutton (widget_instance* instance, Widget widget,
241 widget_value* val)
243 /* Should also rebuild the menu by calling ...update_menu... */
244 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
245 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
246 instance);
249 \f/* update toggle and radiobox */
250 static void
251 xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
253 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
254 XtAddCallback (widget, XmNvalueChangedCallback,
255 xm_internal_update_other_instances, instance);
256 XtVaSetValues (widget, XmNset, val->selected,
257 XmNalignment, XmALIGNMENT_BEGINNING, 0);
260 static void
261 xm_update_radiobox (widget_instance* instance, Widget widget,
262 widget_value* val)
264 Widget toggle;
265 widget_value* cur;
267 /* update the callback */
268 XtRemoveAllCallbacks (widget, XmNentryCallback);
269 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
271 /* first update all the toggles */
272 /* Energize kernel interface is currently bad. It sets the selected widget
273 with the selected flag but returns it by its name. So we currently
274 have to support both setting the selection with the selected slot
275 of val contents and setting it with the "value" slot of val. The latter
276 has a higher priority. This to be removed when the kernel is fixed. */
277 for (cur = val->contents; cur; cur = cur->next)
279 toggle = XtNameToWidget (widget, cur->value);
280 if (toggle)
282 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
283 if (!val->value && cur->selected)
284 XtVaSetValues (toggle, XmNset, cur->selected, 0);
285 if (val->value && strcmp (val->value, cur->value))
286 XtVaSetValues (toggle, XmNset, False, 0);
290 /* The selected was specified by the value slot */
291 if (val->value)
293 toggle = XtNameToWidget (widget, val->value);
294 if (toggle)
295 XtVaSetValues (toggle, XmNset, True, 0);
299 \f/* update a popup menu, pulldown menu or a menubar */
300 static Boolean
301 all_dashes_p (char* s)
303 char* t;
304 for (t = s; *t; t++)
305 if (*t != '-')
306 return False;
307 return True;
310 static void
311 make_menu_in_widget (widget_instance* instance, Widget widget,
312 widget_value* val)
314 Widget* children = 0;
315 int num_children;
316 int child_index;
317 widget_value* cur;
318 Widget button = 0;
319 Widget menu;
320 Arg al [256];
321 int ac;
322 Boolean menubar_p;
324 /* Allocate the children array */
325 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
326 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
328 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
329 menubar_p = False;
330 XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
331 XtGetValues (widget, al, 1);
333 /* add the unmap callback for popups and pulldowns */
334 /*** this sounds bogus ***/
335 if (!menubar_p)
336 XtAddCallback (XtParent (widget), XmNpopdownCallback,
337 xm_pop_down_callback, (XtPointer)instance);
339 for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
341 ac = 0;
342 XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
343 XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
344 XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
346 if (all_dashes_p (cur->name))
348 button = XmCreateSeparator (widget, cur->name, NULL, 0);
350 else if (!cur->contents)
352 if (menubar_p)
353 button = XmCreateCascadeButton (widget, cur->name, al, ac);
354 else if (!cur->call_data)
355 button = XmCreateLabel (widget, cur->name, al, ac);
356 else
357 button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
359 xm_update_label (instance, button, cur);
361 /* don't add a callback to a simple label */
362 if (cur->call_data)
363 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
364 (XtPointer)instance);
366 else
368 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
369 make_menu_in_widget (instance, menu, cur->contents);
370 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
371 button = XmCreateCascadeButton (widget, cur->name, al, ac);
373 xm_update_label (instance, button, cur);
375 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
376 (XtPointer)instance);
379 children [child_index] = button;
382 XtManageChildren (children, num_children);
384 /* Last entry is the help button. Has to be done after managing
385 * the buttons otherwise the menubar is only 4 pixels high... */
386 if (button)
388 ac = 0;
389 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
390 XtSetValues (widget, al, ac);
393 XtFree ((char *) children);
396 static void
397 update_one_menu_entry (widget_instance* instance, Widget widget,
398 widget_value* val, Boolean deep_p)
400 Arg al [256];
401 int ac;
402 Widget menu;
403 widget_value* contents;
405 if (val->change == NO_CHANGE)
406 return;
408 /* update the sensitivity and userdata */
409 /* Common to all widget types */
410 XtVaSetValues (widget,
411 XmNsensitive, val->enabled,
412 XmNuserData, val->call_data,
415 /* update the menu button as a label. */
416 if (val->change >= VISIBLE_CHANGE)
417 xm_update_label (instance, widget, val);
419 /* update the pulldown/pullaside as needed */
420 ac = 0;
421 menu = NULL;
422 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
423 XtGetValues (widget, al, ac);
425 contents = val->contents;
427 if (!menu)
429 if (contents)
431 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
432 make_menu_in_widget (instance, menu, contents);
433 ac = 0;
434 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
435 XtSetValues (widget, al, ac);
438 else if (!contents)
440 ac = 0;
441 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
442 XtSetValues (widget, al, ac);
443 XtDestroyWidget (menu);
445 else if (deep_p && contents->change != NO_CHANGE)
446 xm_update_menu (instance, menu, val, 1);
449 static void
450 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
451 Boolean deep_p)
453 /* Widget is a RowColumn widget whose contents have to be updated
454 * to reflect the list of items in val->contents */
455 if (val->contents->change == STRUCTURAL_CHANGE)
457 destroy_all_children (widget);
458 make_menu_in_widget (instance, widget, val->contents);
460 else
462 /* Update all the buttons of the RowColumn in order. */
463 Widget* children;
464 unsigned int num_children;
465 int i;
466 widget_value* cur;
468 children = XtCompositeChildren (widget, &num_children);
469 if (children)
471 for (i = 0, cur = val->contents; i < num_children; i++)
473 if (!cur)
474 abort ();
475 if (children [i]->core.being_destroyed
476 || strcmp (XtName (children [i]), cur->name))
477 continue;
478 update_one_menu_entry (instance, children [i], cur, deep_p);
479 cur = cur->next;
481 XtFree ((char *) children);
483 if (cur)
484 abort ();
489 /* update text widgets */
491 static void
492 xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
494 XmTextSetString (widget, val->value ? val->value : "");
495 XtRemoveAllCallbacks (widget, XmNactivateCallback);
496 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
497 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
498 XtAddCallback (widget, XmNvalueChangedCallback,
499 xm_internal_update_other_instances, instance);
502 static void
503 xm_update_text_field (widget_instance* instance, Widget widget,
504 widget_value* val)
506 XmTextFieldSetString (widget, val->value ? val->value : "");
507 XtRemoveAllCallbacks (widget, XmNactivateCallback);
508 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
509 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
510 XtAddCallback (widget, XmNvalueChangedCallback,
511 xm_internal_update_other_instances, instance);
515 /* update a motif widget */
517 void
518 xm_update_one_widget (widget_instance* instance, Widget widget,
519 widget_value* val, Boolean deep_p)
521 WidgetClass class;
523 /* Mark as not edited */
524 val->edited = False;
526 /* Common to all widget types */
527 XtVaSetValues (widget,
528 XmNsensitive, val->enabled,
529 XmNuserData, val->call_data,
532 /* Common to all label like widgets */
533 if (XtIsSubclass (widget, xmLabelWidgetClass))
534 xm_update_label (instance, widget, val);
536 class = XtClass (widget);
537 /* Class specific things */
538 if (class == xmPushButtonWidgetClass ||
539 class == xmArrowButtonWidgetClass)
541 xm_update_pushbutton (instance, widget, val);
543 else if (class == xmCascadeButtonWidgetClass)
545 xm_update_cascadebutton (instance, widget, val);
547 else if (class == xmToggleButtonWidgetClass
548 || class == xmToggleButtonGadgetClass)
550 xm_update_toggle (instance, widget, val);
552 else if (class == xmRowColumnWidgetClass)
554 Boolean radiobox = 0;
555 int ac = 0;
556 Arg al [1];
558 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
559 XtGetValues (widget, al, ac);
561 if (radiobox)
562 xm_update_radiobox (instance, widget, val);
563 else
564 xm_update_menu (instance, widget, val, deep_p);
566 else if (class == xmTextWidgetClass)
568 xm_update_text (instance, widget, val);
570 else if (class == xmTextFieldWidgetClass)
572 xm_update_text_field (instance, widget, val);
574 else if (class == xmListWidgetClass)
576 xm_update_list (instance, widget, val);
580 \f/* getting the value back */
581 void
582 xm_update_one_value (widget_instance* instance, Widget widget,
583 widget_value* val)
585 WidgetClass class = XtClass (widget);
586 widget_value *old_wv;
588 /* copy the call_data slot into the "return" widget_value */
589 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
590 if (!strcmp (val->name, old_wv->name))
592 val->call_data = old_wv->call_data;
593 break;
596 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
598 XtVaGetValues (widget, XmNset, &val->selected, 0);
599 val->edited = True;
601 else if (class == xmTextWidgetClass)
603 if (val->value)
604 free (val->value);
605 val->value = XmTextGetString (widget);
606 val->edited = True;
608 else if (class == xmTextFieldWidgetClass)
610 if (val->value)
611 free (val->value);
612 val->value = XmTextFieldGetString (widget);
613 val->edited = True;
615 else if (class == xmRowColumnWidgetClass)
617 Boolean radiobox = 0;
618 int ac = 0;
619 Arg al [1];
621 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
622 XtGetValues (widget, al, ac);
624 if (radiobox)
626 CompositeWidget radio = (CompositeWidget)widget;
627 int i;
628 for (i = 0; i < radio->composite.num_children; i++)
630 int set = False;
631 Widget toggle = radio->composite.children [i];
633 XtVaGetValues (toggle, XmNset, &set, 0);
634 if (set)
636 if (val->value)
637 free (val->value);
638 val->value = strdup (XtName (toggle));
641 val->edited = True;
644 else if (class == xmListWidgetClass)
646 int pos_cnt;
647 int* pos_list;
648 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
650 int i;
651 widget_value* cur;
652 for (cur = val->contents, i = 0; cur; cur = cur->next)
653 if (cur->value)
655 int j;
656 cur->selected = False;
657 i += 1;
658 for (j = 0; j < pos_cnt; j++)
659 if (pos_list [j] == i)
661 cur->selected = True;
662 val->value = strdup (cur->name);
665 val->edited = 1;
666 XtFree ((char *) pos_list);
672 /* This function is for activating a button from a program. It's wrong because
673 we pass a NULL argument in the call_data which is not Motif compatible.
674 This is used from the XmNdefaultAction callback of the List widgets to
675 have a dble-click put down a dialog box like the button woudl do.
676 I could not find a way to do that with accelerators.
678 static void
679 activate_button (Widget widget, XtPointer closure, XtPointer call_data)
681 Widget button = (Widget)closure;
682 XtCallCallbacks (button, XmNactivateCallback, NULL);
685 /* creation functions */
687 /* dialogs */
688 static Widget
689 make_dialog (char* name, Widget parent, Boolean pop_up_p,
690 char* shell_title, char* icon_name, Boolean text_input_slot,
691 Boolean radio_box, Boolean list,
692 int left_buttons, int right_buttons)
694 Widget result;
695 Widget form;
696 Widget row;
697 Widget icon;
698 Widget icon_separator;
699 Widget message;
700 Widget value = 0;
701 Widget separator;
702 Widget button = 0;
703 Widget children [16]; /* for the final XtManageChildren */
704 int n_children;
705 Arg al[64]; /* Arg List */
706 int ac; /* Arg Count */
707 int i;
709 if (pop_up_p)
711 ac = 0;
712 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
713 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
714 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
715 result = XmCreateDialogShell (parent, "dialog", al, ac);
716 ac = 0;
717 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
718 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
719 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
720 form = XmCreateForm (result, shell_title, al, ac);
722 else
724 ac = 0;
725 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
726 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
727 form = XmCreateForm (parent, shell_title, al, ac);
728 result = form;
731 ac = 0;
732 XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
733 XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++;
734 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
735 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
736 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
737 XtSetArg(al[ac], XmNspacing, 13); ac++;
738 XtSetArg(al[ac], XmNadjustLast, False); ac++;
739 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
740 XtSetArg(al[ac], XmNisAligned, True); ac++;
741 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
742 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
743 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
744 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
745 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
746 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
747 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
748 row = XmCreateRowColumn (form, "row", al, ac);
750 n_children = 0;
751 for (i = 0; i < left_buttons; i++)
753 char button_name [16];
754 sprintf (button_name, "button%d", i + 1);
755 ac = 0;
756 if (i == 0)
758 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
759 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
761 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
762 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
764 if (i == 0)
766 button = children [n_children];
767 ac = 0;
768 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
769 XtSetValues (row, al, ac);
772 n_children++;
775 /* invisible seperator button */
776 ac = 0;
777 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
778 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
779 n_children++;
781 for (i = 0; i < right_buttons; i++)
783 char button_name [16];
784 sprintf (button_name, "button%d", left_buttons + i + 1);
785 ac = 0;
786 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
787 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
788 if (! button) button = children [n_children];
789 n_children++;
792 XtManageChildren (children, n_children);
794 ac = 0;
795 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
796 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
797 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
798 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
799 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
800 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
801 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
802 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
803 separator = XmCreateSeparator (form, "", al, ac);
805 ac = 0;
806 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
807 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
808 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
809 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
810 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
811 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
812 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
813 icon = XmCreateLabel (form, icon_name, al, ac);
815 ac = 0;
816 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
817 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
818 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
819 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
820 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
821 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
822 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
823 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
824 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
825 icon_separator = XmCreateLabel (form, "", al, ac);
827 if (text_input_slot)
829 ac = 0;
830 XtSetArg(al[ac], XmNcolumns, 50); ac++;
831 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
832 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
833 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
834 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
835 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
836 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
837 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
838 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
839 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
840 value = XmCreateTextField (form, "value", al, ac);
842 else if (radio_box)
844 Widget radio_butt;
845 ac = 0;
846 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
847 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
848 XtSetArg(al[ac], XmNspacing, 13); ac++;
849 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
850 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
851 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
852 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
853 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
854 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
855 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
856 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
857 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
858 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
859 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
860 ac = 0;
861 i = 0;
862 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
863 children [i++] = radio_butt;
864 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
865 children [i++] = radio_butt;
866 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
867 children [i++] = radio_butt;
868 XtManageChildren (children, i);
870 else if (list)
872 ac = 0;
873 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
874 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
875 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
876 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
877 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
878 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
879 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
880 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
881 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
882 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
883 value = XmCreateScrolledList (form, "list", al, ac);
885 /* this is the easiest way I found to have the dble click in the
886 list activate the default button */
887 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
890 ac = 0;
891 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
892 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
893 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
894 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
895 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
896 XtSetArg(al[ac], XmNbottomWidget,
897 text_input_slot || radio_box || list ? value : separator); ac++;
898 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
899 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
900 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
901 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
902 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
903 message = XmCreateLabel (form, "message", al, ac);
905 if (list)
906 XtManageChild (value);
908 i = 0;
909 children [i] = row; i++;
910 children [i] = separator; i++;
911 if (text_input_slot || radio_box)
913 children [i] = value; i++;
915 children [i] = message; i++;
916 children [i] = icon; i++;
917 children [i] = icon_separator; i++;
918 XtManageChildren (children, i);
920 if (text_input_slot || list)
922 XtInstallAccelerators (value, button);
923 XtSetKeyboardFocus (result, value);
925 else
927 XtInstallAccelerators (form, button);
928 XtSetKeyboardFocus (result, button);
931 return result;
934 static destroyed_instance*
935 find_matching_instance (widget_instance* instance)
937 destroyed_instance* cur;
938 destroyed_instance* prev;
939 char* type = instance->info->type;
940 char* name = instance->info->name;
942 for (prev = NULL, cur = all_destroyed_instances;
943 cur;
944 prev = cur, cur = cur->next)
946 if (!strcmp (cur->name, name)
947 && !strcmp (cur->type, type)
948 && cur->parent == instance->parent
949 && cur->pop_up_p == instance->pop_up_p)
951 if (prev)
952 prev->next = cur->next;
953 else
954 all_destroyed_instances = cur->next;
955 return cur;
957 /* do some cleanup */
958 else if (!cur->widget)
960 if (prev)
961 prev->next = cur->next;
962 else
963 all_destroyed_instances = cur->next;
964 free_destroyed_instance (cur);
965 cur = prev ? prev : all_destroyed_instances;
968 return NULL;
971 static void
972 mark_dead_instance_destroyed (Widget widget, XtPointer closure,
973 XtPointer call_data)
975 destroyed_instance* instance = (destroyed_instance*)closure;
976 instance->widget = NULL;
979 static void
980 recenter_widget (Widget widget)
982 Widget parent = XtParent (widget);
983 Screen* screen = XtScreen (widget);
984 Dimension screen_width = WidthOfScreen (screen);
985 Dimension screen_height = HeightOfScreen (screen);
986 Dimension parent_width = 0;
987 Dimension parent_height = 0;
988 Dimension child_width = 0;
989 Dimension child_height = 0;
990 Position x;
991 Position y;
993 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
994 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
997 x = (((Position)parent_width) - ((Position)child_width)) / 2;
998 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1000 XtTranslateCoords (parent, x, y, &x, &y);
1002 if (x + child_width > screen_width)
1003 x = screen_width - child_width;
1004 if (x < 0)
1005 x = 0;
1007 if (y + child_height > screen_height)
1008 y = screen_height - child_height;
1009 if (y < 0)
1010 y = 0;
1012 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1015 static Widget
1016 recycle_instance (destroyed_instance* instance)
1018 Widget widget = instance->widget;
1020 /* widget is NULL if the parent was destroyed. */
1021 if (widget)
1023 Widget focus;
1024 Widget separator;
1026 /* Remove the destroy callback as the instance is not in the list
1027 anymore */
1028 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1029 mark_dead_instance_destroyed,
1030 (XtPointer)instance);
1032 /* Give the focus to the initial item */
1033 focus = XtNameToWidget (widget, "*value");
1034 if (!focus)
1035 focus = XtNameToWidget (widget, "*button1");
1036 if (focus)
1037 XtSetKeyboardFocus (widget, focus);
1039 /* shrink the separator label back to their original size */
1040 separator = XtNameToWidget (widget, "*separator_button");
1041 if (separator)
1042 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1044 /* Center the dialog in its parent */
1045 recenter_widget (widget);
1047 free_destroyed_instance (instance);
1048 return widget;
1051 Widget
1052 xm_create_dialog (widget_instance* instance)
1054 char* name = instance->info->type;
1055 Widget parent = instance->parent;
1056 Widget widget;
1057 Boolean pop_up_p = instance->pop_up_p;
1058 char* shell_name = 0;
1059 char* icon_name;
1060 Boolean text_input_slot = False;
1061 Boolean radio_box = False;
1062 Boolean list = False;
1063 int total_buttons;
1064 int left_buttons = 0;
1065 int right_buttons = 1;
1066 destroyed_instance* dead_one;
1068 /* try to find a widget to recycle */
1069 dead_one = find_matching_instance (instance);
1070 if (dead_one)
1072 Widget recycled_widget = recycle_instance (dead_one);
1073 if (recycled_widget)
1074 return recycled_widget;
1077 switch (name [0]){
1078 case 'E': case 'e':
1079 icon_name = "dbox-error";
1080 shell_name = "Error";
1081 break;
1083 case 'I': case 'i':
1084 icon_name = "dbox-info";
1085 shell_name = "Information";
1086 break;
1088 case 'L': case 'l':
1089 list = True;
1090 icon_name = "dbox-question";
1091 shell_name = "Prompt";
1092 break;
1094 case 'P': case 'p':
1095 text_input_slot = True;
1096 icon_name = "dbox-question";
1097 shell_name = "Prompt";
1098 break;
1100 case 'Q': case 'q':
1101 icon_name = "dbox-question";
1102 shell_name = "Question";
1103 break;
1106 total_buttons = name [1] - '0';
1108 if (name [3] == 'T' || name [3] == 't')
1110 text_input_slot = False;
1111 radio_box = True;
1113 else if (name [3])
1114 right_buttons = name [4] - '0';
1116 left_buttons = total_buttons - right_buttons;
1118 widget = make_dialog (name, parent, pop_up_p,
1119 shell_name, icon_name, text_input_slot, radio_box,
1120 list, left_buttons, right_buttons);
1122 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1123 (XtPointer) instance);
1124 return widget;
1127 static Widget
1128 make_menubar (widget_instance* instance)
1130 return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
1133 static void
1134 remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
1136 XmRowColumnWidget menu = (XmRowColumnWidget) closure;
1137 XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
1140 static Widget
1141 make_popup_menu (widget_instance* instance)
1143 Widget parent = instance->parent;
1144 Window parent_window = parent->core.window;
1145 Widget result;
1147 /* sets the parent window to 0 to fool Motif into not generating a grab */
1148 parent->core.window = 0;
1149 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1150 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1151 (XtPointer)result);
1152 parent->core.window = parent_window;
1153 return result;
1156 \f/* Table of functions to create widgets */
1158 #ifdef ENERGIZE
1160 /* interface with the XDesigner generated functions */
1161 typedef Widget (*widget_maker) (Widget);
1162 extern Widget create_project_p_sheet (Widget parent);
1163 extern Widget create_debugger_p_sheet (Widget parent);
1164 extern Widget create_breaklist_p_sheet (Widget parent);
1165 extern Widget create_le_browser_p_sheet (Widget parent);
1166 extern Widget create_class_browser_p_sheet (Widget parent);
1167 extern Widget create_call_browser_p_sheet (Widget parent);
1168 extern Widget create_build_dialog (Widget parent);
1169 extern Widget create_editmode_dialog (Widget parent);
1170 extern Widget create_search_dialog (Widget parent);
1171 extern Widget create_project_display_dialog (Widget parent);
1173 static Widget
1174 make_one (widget_instance* instance, widget_maker fn)
1176 Widget result;
1177 Arg al [64];
1178 int ac = 0;
1180 if (instance->pop_up_p)
1182 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1183 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1184 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1185 (XtPointer) instance);
1186 (*fn) (result);
1188 else
1190 result = (*fn) (instance->parent);
1191 XtRealizeWidget (result);
1193 return result;
1196 static Widget
1197 make_project_p_sheet (widget_instance* instance)
1199 return make_one (instance, create_project_p_sheet);
1202 static Widget
1203 make_debugger_p_sheet (widget_instance* instance)
1205 return make_one (instance, create_debugger_p_sheet);
1208 static Widget
1209 make_breaklist_p_sheet (widget_instance* instance)
1211 return make_one (instance, create_breaklist_p_sheet);
1214 static Widget
1215 make_le_browser_p_sheet (widget_instance* instance)
1217 return make_one (instance, create_le_browser_p_sheet);
1220 static Widget
1221 make_class_browser_p_sheet (widget_instance* instance)
1223 return make_one (instance, create_class_browser_p_sheet);
1226 static Widget
1227 make_call_browser_p_sheet (widget_instance* instance)
1229 return make_one (instance, create_call_browser_p_sheet);
1232 static Widget
1233 make_build_dialog (widget_instance* instance)
1235 return make_one (instance, create_build_dialog);
1238 static Widget
1239 make_editmode_dialog (widget_instance* instance)
1241 return make_one (instance, create_editmode_dialog);
1244 static Widget
1245 make_search_dialog (widget_instance* instance)
1247 return make_one (instance, create_search_dialog);
1250 static Widget
1251 make_project_display_dialog (widget_instance* instance)
1253 return make_one (instance, create_project_display_dialog);
1256 #endif /* ENERGIZE */
1258 widget_creation_entry
1259 xm_creation_table [] =
1261 {"menubar", make_menubar},
1262 {"popup", make_popup_menu},
1263 #ifdef ENERGIZE
1264 {"project_p_sheet", make_project_p_sheet},
1265 {"debugger_p_sheet", make_debugger_p_sheet},
1266 {"breaklist_psheet", make_breaklist_p_sheet},
1267 {"leb_psheet", make_le_browser_p_sheet},
1268 {"class_browser_psheet", make_class_browser_p_sheet},
1269 {"ctree_browser_psheet", make_call_browser_p_sheet},
1270 {"build", make_build_dialog},
1271 {"editmode", make_editmode_dialog},
1272 {"search", make_search_dialog},
1273 {"project_display", make_project_display_dialog},
1274 #endif /* ENERGIZE */
1275 {NULL, NULL}
1278 \f/* Destruction of instances */
1279 void
1280 xm_destroy_instance (widget_instance* instance)
1282 Widget widget = instance->widget;
1283 /* recycle the dialog boxes */
1284 /* Disable the recycling until we can find a way to have the dialog box
1285 get reasonable layout after we modify its contents. */
1286 if (0
1287 && XtClass (widget) == xmDialogShellWidgetClass)
1289 destroyed_instance* dead_instance =
1290 make_destroyed_instance (instance->info->name,
1291 instance->info->type,
1292 instance->widget,
1293 instance->parent,
1294 instance->pop_up_p);
1295 dead_instance->next = all_destroyed_instances;
1296 all_destroyed_instances = dead_instance;
1297 XtUnmanageChild (first_child (instance->widget));
1298 XFlush (XtDisplay (instance->widget));
1299 XtAddCallback (instance->parent, XtNdestroyCallback,
1300 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1302 else
1304 /* This might not be necessary now that the nosel is attached to
1305 popdown instead of destroy, but it can't hurt. */
1306 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1307 xm_nosel_callback, (XtPointer)instance);
1308 XtDestroyWidget (instance->widget);
1312 \f/* popup utility */
1313 void
1314 xm_popup_menu (Widget widget)
1316 XButtonPressedEvent dummy;
1317 XEvent* event;
1319 dummy.type = ButtonPress;
1320 dummy.serial = 0;
1321 dummy.send_event = 0;
1322 dummy.display = XtDisplay (widget);
1323 dummy.window = XtWindow (XtParent (widget));
1324 dummy.time = 0;
1325 dummy.button = 0;
1326 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1327 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1328 &dummy.x, &dummy.y, &dummy.state);
1329 event = (XEvent *) &dummy;
1331 if (event->type == ButtonPress || event->type == ButtonRelease)
1333 /* This is so totally ridiculous: there's NO WAY to tell Motif
1334 that *any* button can select a menu item. Only one button
1335 can have that honor.
1337 char *trans = 0;
1338 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1339 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1340 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1341 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1342 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1343 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1344 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1346 XtManageChild (widget);
1349 static void
1350 set_min_dialog_size (Widget w)
1352 short width;
1353 short height;
1354 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1355 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1358 void
1359 xm_pop_instance (widget_instance* instance, Boolean up)
1361 Widget widget = instance->widget;
1363 if (XtClass (widget) == xmDialogShellWidgetClass)
1365 Widget widget_to_manage = first_child (widget);
1366 if (up)
1368 XtManageChild (widget_to_manage);
1369 set_min_dialog_size (widget);
1370 XtSetKeyboardFocus (instance->parent, widget);
1372 else
1373 XtUnmanageChild (widget_to_manage);
1375 else
1377 if (up)
1378 XtManageChild (widget);
1379 else
1380 XtUnmanageChild (widget);
1385 /* motif callback */
1387 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1389 static void
1390 do_call (Widget widget, XtPointer closure, enum do_call_type type)
1392 Arg al [256];
1393 int ac;
1394 XtPointer user_data;
1395 widget_instance* instance = (widget_instance*)closure;
1396 Widget instance_widget;
1397 LWLIB_ID id;
1399 if (!instance)
1400 return;
1401 if (widget->core.being_destroyed)
1402 return;
1404 instance_widget = instance->widget;
1405 if (!instance_widget)
1406 return;
1408 id = instance->info->id;
1409 ac = 0;
1410 user_data = NULL;
1411 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1412 XtGetValues (widget, al, ac);
1413 switch (type)
1415 case pre_activate:
1416 if (instance->info->pre_activate_cb)
1417 instance->info->pre_activate_cb (widget, id, user_data);
1418 break;
1419 case selection:
1420 if (instance->info->selection_cb)
1421 instance->info->selection_cb (widget, id, user_data);
1422 break;
1423 case no_selection:
1424 if (instance->info->selection_cb)
1425 instance->info->selection_cb (widget, id, (XtPointer) -1);
1426 break;
1427 case post_activate:
1428 if (instance->info->post_activate_cb)
1429 instance->info->post_activate_cb (widget, id, user_data);
1430 break;
1431 default:
1432 abort ();
1436 /* Like lw_internal_update_other_instances except that it does not do
1437 anything if its shell parent is not managed. This is to protect
1438 lw_internal_update_other_instances to dereference freed memory
1439 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1440 list */
1441 static void
1442 xm_internal_update_other_instances (Widget widget, XtPointer closure,
1443 XtPointer call_data)
1445 Widget parent;
1446 for (parent = widget; parent; parent = XtParent (parent))
1447 if (XtIsShell (parent))
1448 break;
1449 else if (!XtIsManaged (parent))
1450 return;
1451 lw_internal_update_other_instances (widget, closure, call_data);
1454 static void
1455 xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
1457 lw_internal_update_other_instances (widget, closure, call_data);
1458 do_call (widget, closure, selection);
1461 static void
1462 xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
1464 /* This callback is only called when a dialog box is dismissed with the wm's
1465 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1466 in that case, not just unmapped, so that it releases its keyboard grabs.
1467 But there are problems with running our callbacks while the widget is in
1468 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1469 instead of XmDESTROY and then destroy it ourself after having run the
1470 callback.
1472 do_call (widget, closure, no_selection);
1473 XtDestroyWidget (widget);
1476 static void
1477 xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1479 do_call (widget, closure, pre_activate);
1482 static void
1483 xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1485 do_call (widget, closure, post_activate);
1489 /* set the keyboard focus */
1490 void
1491 xm_set_keyboard_focus (Widget parent, Widget w)
1493 XmProcessTraversal (w, 0);
1494 XtSetKeyboardFocus (parent, w);