1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2016 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
6 This file is part of the Lucid Widget Library.
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)
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.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
37 #include "lwlib-utils.h"
39 #include <Xm/BulletinB.h>
40 #include <Xm/CascadeB.h>
41 #include <Xm/CascadeBG.h>
42 #include <Xm/DrawingA.h>
43 #include <Xm/FileSB.h>
47 #include <Xm/MenuShell.h>
48 #include <Xm/MessageB.h>
49 #include <Xm/PanedW.h>
51 #include <Xm/PushBG.h>
52 #include <Xm/ArrowB.h>
53 #include <Xm/SelectioB.h>
56 #include <Xm/ToggleB.h>
57 #include <Xm/ToggleBG.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/ScrolledW.h>
60 #include <Xm/Separator.h>
61 #include <Xm/DialogS.h>
64 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
67 \f/* Structures to keep destroyed instances */
68 typedef struct _destroyed_instance
75 struct _destroyed_instance
* next
;
78 static destroyed_instance
*make_destroyed_instance (char *, char *,
81 static void free_destroyed_instance (destroyed_instance
*);
82 Widget
first_child (Widget
);
83 static XmString
resource_motif_string (Widget
, char *);
84 static void destroy_all_children (Widget
, int);
85 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
86 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
87 static void xm_update_pushbutton (widget_instance
*, Widget
,
89 static void xm_update_cascadebutton (widget_instance
*, Widget
,
91 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
92 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
93 static void make_menu_in_widget (widget_instance
*, Widget
,
95 static void update_one_menu_entry (widget_instance
*, Widget
,
96 widget_value
*, Boolean
);
97 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
99 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
100 static void xm_update_text_field (widget_instance
*, Widget
,
102 static void activate_button (Widget
, XtPointer
, XtPointer
);
103 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
104 Boolean
, Boolean
, Boolean
, int, int);
105 static destroyed_instance
* find_matching_instance (widget_instance
*);
106 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
107 static void recenter_widget (Widget
);
108 static Widget
recycle_instance (destroyed_instance
*);
109 static Widget
make_menubar (widget_instance
*);
110 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
111 static Widget
make_popup_menu (widget_instance
*);
112 static Widget
make_main (widget_instance
*);
113 static void set_min_dialog_size (Widget
);
114 static void do_call (Widget
, XtPointer
, enum do_call_type
);
115 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
116 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
117 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
118 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
119 static void xm_internal_update_other_instances (Widget
, XtPointer
,
121 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
124 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
126 void xm_pop_instance (widget_instance
*, Boolean
);
127 void xm_manage_resizing (Widget
, Boolean
);
133 /* Print the complete X resource name of widget WIDGET to stderr.
134 This is sometimes handy to have available. */
137 x_print_complete_resource_name (Widget widget
)
142 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
144 names
[i
] = XtName (widget
);
145 widget
= XtParent (widget
);
148 for (--i
; i
>= 1; --i
)
149 fprintf (stderr
, "%s.", names
[i
]);
150 fprintf (stderr
, "%s\n", names
[0]);
156 static destroyed_instance
*all_destroyed_instances
= NULL
;
158 static destroyed_instance
*
159 make_destroyed_instance (char* name
,
165 destroyed_instance
* instance
=
166 (destroyed_instance
*) xmalloc (sizeof (destroyed_instance
));
167 instance
->name
= xstrdup (name
);
168 instance
->type
= xstrdup (type
);
169 instance
->widget
= widget
;
170 instance
->parent
= parent
;
171 instance
->pop_up_p
= pop_up_p
;
172 instance
->next
= NULL
;
177 free_destroyed_instance (destroyed_instance
* instance
)
179 xfree (instance
->name
);
180 xfree (instance
->type
);
184 \f/* motif utility functions */
186 first_child (Widget widget
)
188 return ((CompositeWidget
)widget
)->composite
.children
[0];
192 lw_motif_widget_p (Widget widget
)
195 XtClass (widget
) == xmDialogShellWidgetClass
196 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
200 resource_motif_string (Widget widget
,
206 resource
.resource_name
= name
;
207 resource
.resource_class
= XmCXmString
;
208 resource
.resource_type
= XmRXmString
;
209 resource
.resource_size
= sizeof (XmString
);
210 resource
.resource_offset
= 0;
211 resource
.default_type
= XtRImmediate
;
212 resource
.default_addr
= 0;
214 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
215 "DialogString", &resource
, 1, NULL
, 0);
219 /* Destroy all of the children of WIDGET
220 starting with number FIRST_CHILD_TO_DESTROY. */
223 destroy_all_children (Widget widget
,
224 int first_child_to_destroy
)
230 children
= XtCompositeChildren (widget
, &number
);
233 XtUnmanageChildren (children
+ first_child_to_destroy
,
234 number
- first_child_to_destroy
);
236 /* Unmanage all children and destroy them. They will only be
237 really destroyed when we get out of DispatchEvent. */
238 for (i
= first_child_to_destroy
; i
< number
; i
++)
242 /* Cascade buttons have submenus,and these submenus
243 need to be freed. But they are not included in
244 XtCompositeChildren. So get it out of the cascade button
245 and free it. If this child is not a cascade button,
246 then submenu should remain unchanged. */
247 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
248 XtGetValues (children
[i
], al
, 1);
251 destroy_all_children (submenu
, 0);
252 XtDestroyWidget (submenu
);
254 XtDestroyWidget (children
[i
]);
257 XtFree ((char *) children
);
263 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
264 menu. CLIENT_DATA contains a pointer to the widget_value
265 corresponding to widget W. CALL_DATA contains a
266 XmPushButtonCallbackStruct containing the reason why the callback
270 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
272 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
273 widget_value
*wv
= (widget_value
*) client_data
;
274 widget_instance
*instance
;
276 /* Get the id of the menu bar or popup menu this widget is in. */
279 if (XmIsRowColumn (w
))
281 unsigned char type
= 0xff;
283 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
284 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
293 instance
= lw_get_widget_instance (w
);
294 if (instance
&& instance
->info
->highlight_cb
)
296 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
297 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
304 /* Update the label of widget WIDGET. WIDGET must be a Label widget
305 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
310 Emacs fills VAL->name with the text to display in the menu, and
311 sets VAL->value to null. Function make_menu_in_widget creates
312 widgets with VAL->name as resource name. This works because the
313 Label widget uses its resource name for display if no
314 XmNlabelString is set.
318 VAL->name is again set to the resource name, but VAL->value is
319 not null, and contains the label string to display. */
322 xm_update_label (widget_instance
* instance
,
326 XmString res_string
= 0;
327 XmString built_string
= 0;
328 XmString key_string
= 0;
336 /* A label string is specified, i.e. we are in a dialog. First
337 see if it is overridden by something from the resource file. */
338 res_string
= resource_motif_string (widget
, val
->value
);
342 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
347 XmStringCreateLocalized (val
->value
);
348 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
351 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
356 key_string
= XmStringCreateLocalized (val
->key
);
357 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
361 XtSetValues (widget
, al
, ac
);
364 XmStringFree (built_string
);
367 XmStringFree (key_string
);
370 \f/* update of list */
372 xm_update_list (widget_instance
* instance
,
378 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
379 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
381 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
384 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
386 XmListAddItem (widget
, xmstr
, 0);
388 XmListSelectPos (widget
, i
, False
);
389 XmStringFree (xmstr
);
393 \f/* update of buttons */
395 xm_update_pushbutton (widget_instance
* instance
,
399 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
400 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
401 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
405 xm_update_cascadebutton (widget_instance
* instance
,
409 /* Should also rebuild the menu by calling ...update_menu... */
410 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
411 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
415 \f/* update toggle and radiobox */
417 xm_update_toggle (widget_instance
* instance
,
421 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
422 XtAddCallback (widget
, XmNvalueChangedCallback
,
423 xm_generic_callback
, instance
);
424 XtVaSetValues (widget
, XmNset
, val
->selected
,
425 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
429 xm_update_radiobox (widget_instance
* instance
,
437 /* update the callback */
438 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
439 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
441 /* first update all the toggles */
442 /* Energize kernel interface is currently bad. It sets the selected widget
443 with the selected flag but returns it by its name. So we currently
444 have to support both setting the selection with the selected slot
445 of val contents and setting it with the "value" slot of val. The latter
446 has a higher priority. This to be removed when the kernel is fixed. */
447 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
449 toggle
= XtNameToWidget (widget
, cur
->value
);
452 XtSetSensitive (toggle
, cur
->enabled
);
453 if (!val
->value
&& cur
->selected
)
454 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
455 if (val
->value
&& strcmp (val
->value
, cur
->value
))
456 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
460 /* The selected was specified by the value slot */
463 toggle
= XtNameToWidget (widget
, val
->value
);
465 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
470 /* update a popup menu, pulldown menu or a menubar */
472 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
475 make_menu_in_widget (widget_instance
* instance
,
478 int keep_first_children
)
480 Widget
* children
= 0;
491 Widget
* old_children
;
492 unsigned int old_num_children
;
494 /* Disable drag and drop for labels in menu bar. */
495 static char overrideTrans
[] = "<Btn2Down>: Noop()";
496 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
498 old_children
= XtCompositeChildren (widget
, &old_num_children
);
500 /* Allocate the children array */
501 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
503 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
505 /* WIDGET should be a RowColumn. */
506 if (!XmIsRowColumn (widget
))
509 /* Determine whether WIDGET is a menu bar. */
511 XtSetArg (al
[0], XmNrowColumnType
, &type
);
512 XtGetValues (widget
, al
, 1);
513 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
515 menubar_p
= type
== XmMENU_BAR
;
517 /* Add a callback to popups and pulldowns that is called when
518 it is made invisible again. */
520 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
521 xm_pop_down_callback
, (XtPointer
)instance
);
523 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
524 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
525 child_index
++, cur
= cur
->next
)
526 children
[child_index
] = old_children
[child_index
];
528 /* Check that those are all we have
529 (the caller should have deleted the rest). */
530 if (old_num_children
!= keep_first_children
)
533 /* Create the rest. */
534 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
536 enum menu_separator separator
;
539 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
540 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
541 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
543 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
544 && !lw_separator_p (cur
->name
, &separator
, 1))
547 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
548 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
550 else if (lw_separator_p (cur
->name
, &separator
, 1))
553 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
554 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
556 else if (!cur
->contents
)
559 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
560 else if (!cur
->call_data
)
561 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
562 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
563 || cur
->button_type
== BUTTON_TYPE_RADIO
)
565 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
566 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
567 XtSetArg (al
[ac
], XmNindicatorType
,
568 (cur
->button_type
== BUTTON_TYPE_TOGGLE
569 ? XmN_OF_MANY
: XmONE_OF_MANY
));
571 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
572 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
573 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
577 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
578 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
579 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
582 xm_update_label (instance
, button
, cur
);
584 /* Add a callback that is called when the button is
585 selected. Toggle buttons don't support
586 XmNactivateCallback, we use XmNvalueChangedCallback in
587 that case. Don't add a callback to a simple label. */
588 if (cur
->button_type
)
589 xm_update_toggle (instance
, button
, cur
);
590 else if (cur
->call_data
)
591 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
592 (XtPointer
)instance
);
596 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
598 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
599 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
600 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
602 xm_update_label (instance
, button
, cur
);
604 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
605 (XtPointer
)instance
);
606 XtOverrideTranslations (button
, override
);
610 children
[child_index
] = button
;
613 /* Last entry is the help button. The original comment read "Has to
614 be done after managing the buttons otherwise the menubar is only
615 4 pixels high." This is no longer true, and to make
616 XmNmenuHelpWidget work, we need to set it before managing the
617 children.. --gerd. */
619 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
622 XtManageChildren (children
, num_children
);
624 XtFree ((char *) children
);
626 XtFree ((char *) old_children
);
630 update_one_menu_entry (widget_instance
* instance
,
638 widget_value
* contents
;
640 if (val
->this_one_change
== NO_CHANGE
)
643 /* update the sensitivity and userdata */
644 /* Common to all widget types */
645 XtSetSensitive (widget
, val
->enabled
);
646 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
648 /* update the menu button as a label. */
649 if (val
->this_one_change
>= VISIBLE_CHANGE
)
651 xm_update_label (instance
, widget
, val
);
652 if (val
->button_type
)
653 xm_update_toggle (instance
, widget
, val
);
656 /* update the pulldown/pullaside as needed */
659 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
660 XtGetValues (widget
, al
, ac
);
662 contents
= val
->contents
;
668 unsigned int old_num_children
, i
;
672 parent
= XtParent (widget
);
673 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
675 /* Find the widget position within the parent's widget list. */
676 for (i
= 0; i
< old_num_children
; i
++)
677 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
679 if (i
== old_num_children
)
681 if (XmIsCascadeButton (widget_list
[i
]))
683 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
684 make_menu_in_widget (instance
, menu
, contents
, 0);
686 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
687 XtSetValues (widget
, al
, ac
);
693 /* The current menuitem is a XmPushButtonGadget, it
694 needs to be replaced by a CascadeButtonGadget */
695 XtDestroyWidget (widget_list
[i
]);
696 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
697 make_menu_in_widget (instance
, menu
, contents
, 0);
699 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
700 /* Non-zero values don't work reliably in
701 conjunction with Emacs' event loop */
702 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
703 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
704 /* Tell Motif to put it in the right place */
705 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
707 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
708 xm_update_label (instance
, button
, val
);
710 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
711 (XtPointer
)instance
);
712 XtManageChild (button
);
716 XtFree ((char*) widget_list
);
722 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
723 XtSetValues (widget
, al
, ac
);
724 XtDestroyWidget (menu
);
726 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
727 xm_update_menu (instance
, menu
, val
, 1);
731 xm_update_menu (widget_instance
* instance
,
737 unsigned int num_children
;
738 int num_children_to_keep
= 0;
742 children
= XtCompositeChildren (widget
, &num_children
);
744 /* Widget is a RowColumn widget whose contents have to be updated
745 * to reflect the list of items in val->contents */
747 /* See how many buttons we can keep, and how many we
748 must completely replace. */
749 if (val
->contents
== 0)
750 num_children_to_keep
= 0;
751 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
755 for (i
= 0, cur
= val
->contents
;
757 && cur
); /* how else to ditch unwanted children ?? - mgd */
758 i
++, cur
= cur
->next
)
760 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
764 num_children_to_keep
= i
;
768 num_children_to_keep
= num_children
;
770 /* Update all the buttons of the RowColumn, in order,
771 except for those we are going to replace entirely. */
774 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
778 num_children_to_keep
= i
;
781 if (children
[i
]->core
.being_destroyed
782 || strcmp (XtName (children
[i
]), cur
->name
))
784 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
789 /* Now replace from scratch all the buttons after the last
790 place that the top-level structure changed. */
791 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
793 destroy_all_children (widget
, num_children_to_keep
);
794 make_menu_in_widget (instance
, widget
, val
->contents
,
795 num_children_to_keep
);
798 XtFree ((char *) children
);
802 /* update text widgets */
805 xm_update_text (widget_instance
* instance
,
809 XmTextSetString (widget
, val
->value
? val
->value
: "");
810 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
811 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
812 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
813 XtAddCallback (widget
, XmNvalueChangedCallback
,
814 xm_internal_update_other_instances
, instance
);
818 xm_update_text_field (widget_instance
* instance
,
822 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
823 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
824 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
825 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
826 XtAddCallback (widget
, XmNvalueChangedCallback
,
827 xm_internal_update_other_instances
, instance
);
831 /* update a motif widget */
834 xm_update_one_widget (widget_instance
* instance
,
841 /* Mark as not edited */
844 /* Common to all widget types */
845 XtSetSensitive (widget
, val
->enabled
);
846 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
848 /* Common to all label like widgets */
849 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
850 xm_update_label (instance
, widget
, val
);
852 class = XtClass (widget
);
853 /* Class specific things */
854 if (class == xmPushButtonWidgetClass
||
855 class == xmArrowButtonWidgetClass
)
857 xm_update_pushbutton (instance
, widget
, val
);
859 else if (class == xmCascadeButtonWidgetClass
)
861 xm_update_cascadebutton (instance
, widget
, val
);
863 else if (class == xmToggleButtonWidgetClass
864 || class == xmToggleButtonGadgetClass
)
866 xm_update_toggle (instance
, widget
, val
);
868 else if (class == xmRowColumnWidgetClass
)
870 Boolean radiobox
= 0;
874 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
875 XtGetValues (widget
, al
, ac
);
878 xm_update_radiobox (instance
, widget
, val
);
880 xm_update_menu (instance
, widget
, val
, deep_p
);
882 else if (class == xmTextWidgetClass
)
884 xm_update_text (instance
, widget
, val
);
886 else if (class == xmTextFieldWidgetClass
)
888 xm_update_text_field (instance
, widget
, val
);
890 else if (class == xmListWidgetClass
)
892 xm_update_list (instance
, widget
, val
);
896 \f/* getting the value back */
898 xm_update_one_value (widget_instance
* instance
,
902 WidgetClass
class = XtClass (widget
);
903 widget_value
*old_wv
;
905 /* copy the call_data slot into the "return" widget_value */
906 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
907 if (!strcmp (val
->name
, old_wv
->name
))
909 val
->call_data
= old_wv
->call_data
;
913 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
915 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
918 else if (class == xmTextWidgetClass
)
921 val
->value
= XmTextGetString (widget
);
924 else if (class == xmTextFieldWidgetClass
)
927 val
->value
= XmTextFieldGetString (widget
);
930 else if (class == xmRowColumnWidgetClass
)
932 Boolean radiobox
= 0;
936 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
937 XtGetValues (widget
, al
, ac
);
941 CompositeWidget radio
= (CompositeWidget
)widget
;
943 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
946 Widget toggle
= radio
->composite
.children
[i
];
948 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
950 dupstring (&val
->value
, XtName (toggle
));
955 else if (class == xmListWidgetClass
)
959 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
963 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
967 cur
->selected
= False
;
969 for (j
= 0; j
< pos_cnt
; j
++)
970 if (pos_list
[j
] == i
)
972 cur
->selected
= True
;
973 val
->value
= xstrdup (cur
->name
);
977 XtFree ((char *) pos_list
);
983 /* This function is for activating a button from a program. It's wrong because
984 we pass a NULL argument in the call_data which is not Motif compatible.
985 This is used from the XmNdefaultAction callback of the List widgets to
986 have a double-click put down a dialog box like the button would do.
987 I could not find a way to do that with accelerators.
990 activate_button (Widget widget
,
994 Widget button
= (Widget
)closure
;
995 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
998 /* creation functions */
1000 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1002 dialog_key_cb (Widget widget
,
1005 Boolean
*continue_to_dispatch
)
1008 Modifiers modif_ret
;
1010 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1013 if (sym
== osfXK_Cancel
)
1015 Widget w
= *((Widget
*) closure
);
1017 while (w
&& ! XtIsShell (w
))
1020 if (XtIsShell (w
)) XtPopdown (w
);
1023 *continue_to_dispatch
= TRUE
;
1028 make_dialog (char* name
,
1033 Boolean text_input_slot
,
1043 Widget icon_separator
;
1044 Widget message_label
;
1048 Widget children
[16]; /* for the final XtManageChildren */
1050 Arg al
[64]; /* Arg List */
1051 int ac
; /* Arg Count */
1057 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1058 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1059 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1060 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1062 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1063 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1064 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1065 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1070 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1071 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1072 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1076 n_children
= left_buttons
+ right_buttons
+ 1;
1078 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1079 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1080 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1081 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1082 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1083 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1084 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1085 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1086 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1087 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1088 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1089 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1090 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1091 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1092 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1093 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1094 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1095 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1096 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1099 for (i
= 0; i
< left_buttons
; i
++)
1101 char button_name
[16];
1102 sprintf (button_name
, "button%d", i
+ 1);
1106 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1107 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1109 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1110 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1111 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1112 XtAddEventHandler (children
[n_children
],
1113 KeyPressMask
, False
, dialog_key_cb
, result
);
1117 button
= children
[n_children
];
1119 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1120 XtSetValues (row
, al
, ac
);
1126 /* invisible separator button */
1128 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1129 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1132 for (i
= 0; i
< right_buttons
; i
++)
1134 char button_name
[16];
1135 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1137 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1138 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1139 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1140 XtAddEventHandler (children
[n_children
],
1141 KeyPressMask
, False
, dialog_key_cb
, result
);
1143 if (! button
) button
= children
[n_children
];
1147 XtManageChildren (children
, n_children
);
1150 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1151 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1152 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1153 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1154 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1155 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1156 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1157 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1158 separator
= XmCreateSeparator (form
, "", al
, ac
);
1161 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1162 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1163 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1164 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1165 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1167 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1168 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1171 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1172 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1173 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1174 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1175 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1176 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1177 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1178 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1179 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1180 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1182 if (text_input_slot
)
1185 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1186 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1187 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1188 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1189 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1190 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1191 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1192 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1193 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1194 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1195 value
= XmCreateTextField (form
, "value", al
, ac
);
1201 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1202 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1203 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1204 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1205 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1206 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1207 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1208 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1209 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1210 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1211 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1212 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1213 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1214 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1217 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1218 children
[i
++] = radio_butt
;
1219 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1220 children
[i
++] = radio_butt
;
1221 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1222 children
[i
++] = radio_butt
;
1223 XtManageChildren (children
, i
);
1228 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1229 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1230 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1231 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1232 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1233 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1234 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1235 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1236 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1237 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1238 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1240 /* this is the easiest way I found to have the dble click in the
1241 list activate the default button */
1242 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1246 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1247 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1248 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1249 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1250 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1251 XtSetArg(al
[ac
], XmNbottomWidget
,
1252 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1253 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1254 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1255 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1256 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1257 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1258 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1261 XtManageChild (value
);
1264 children
[i
] = row
; i
++;
1265 children
[i
] = separator
; i
++;
1266 if (text_input_slot
|| radio_box
)
1268 children
[i
] = value
; i
++;
1270 children
[i
] = message_label
; i
++;
1271 children
[i
] = icon
; i
++;
1272 children
[i
] = icon_separator
; i
++;
1273 XtManageChildren (children
, i
);
1275 if (text_input_slot
|| list
)
1277 XtInstallAccelerators (value
, button
);
1278 XtSetKeyboardFocus (result
, value
);
1282 XtInstallAccelerators (form
, button
);
1283 XtSetKeyboardFocus (result
, button
);
1289 static destroyed_instance
*
1290 find_matching_instance (widget_instance
* instance
)
1292 destroyed_instance
* cur
;
1293 destroyed_instance
* prev
;
1294 char* type
= instance
->info
->type
;
1295 char* name
= instance
->info
->name
;
1297 for (prev
= NULL
, cur
= all_destroyed_instances
;
1299 prev
= cur
, cur
= cur
->next
)
1301 if (!strcmp (cur
->name
, name
)
1302 && !strcmp (cur
->type
, type
)
1303 && cur
->parent
== instance
->parent
1304 && cur
->pop_up_p
== instance
->pop_up_p
)
1307 prev
->next
= cur
->next
;
1309 all_destroyed_instances
= cur
->next
;
1312 /* do some cleanup */
1313 else if (!cur
->widget
)
1316 prev
->next
= cur
->next
;
1318 all_destroyed_instances
= cur
->next
;
1319 free_destroyed_instance (cur
);
1320 cur
= prev
? prev
: all_destroyed_instances
;
1327 mark_dead_instance_destroyed (Widget widget
,
1329 XtPointer call_data
)
1331 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1332 instance
->widget
= NULL
;
1336 recenter_widget (Widget widget
)
1338 Widget parent
= XtParent (widget
);
1339 Screen
* screen
= XtScreen (widget
);
1340 Dimension screen_width
= WidthOfScreen (screen
);
1341 Dimension screen_height
= HeightOfScreen (screen
);
1342 Dimension parent_width
= 0;
1343 Dimension parent_height
= 0;
1344 Dimension child_width
= 0;
1345 Dimension child_height
= 0;
1349 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1350 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1353 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1354 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1356 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1358 if (x
+ child_width
> screen_width
)
1359 x
= screen_width
- child_width
;
1363 if (y
+ child_height
> screen_height
)
1364 y
= screen_height
- child_height
;
1368 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1372 recycle_instance (destroyed_instance
* instance
)
1374 Widget widget
= instance
->widget
;
1376 /* widget is NULL if the parent was destroyed. */
1382 /* Remove the destroy callback as the instance is not in the list
1384 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1385 mark_dead_instance_destroyed
,
1386 (XtPointer
)instance
);
1388 /* Give the focus to the initial item */
1389 focus
= XtNameToWidget (widget
, "*value");
1391 focus
= XtNameToWidget (widget
, "*button1");
1393 XtSetKeyboardFocus (widget
, focus
);
1395 /* shrink the separator label back to their original size */
1396 separator
= XtNameToWidget (widget
, "*separator_button");
1398 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1400 /* Center the dialog in its parent */
1401 recenter_widget (widget
);
1403 free_destroyed_instance (instance
);
1408 xm_create_dialog (widget_instance
* instance
)
1410 char* name
= instance
->info
->type
;
1411 Widget parent
= instance
->parent
;
1413 Boolean pop_up_p
= instance
->pop_up_p
;
1414 char* shell_name
= 0;
1415 char* icon_name
= 0;
1416 Boolean text_input_slot
= False
;
1417 Boolean radio_box
= False
;
1418 Boolean list
= False
;
1420 int left_buttons
= 0;
1421 int right_buttons
= 1;
1422 destroyed_instance
* dead_one
;
1424 /* try to find a widget to recycle */
1425 dead_one
= find_matching_instance (instance
);
1428 Widget recycled_widget
= recycle_instance (dead_one
);
1429 if (recycled_widget
)
1430 return recycled_widget
;
1435 icon_name
= "dbox-error";
1436 shell_name
= "Error";
1440 icon_name
= "dbox-info";
1441 shell_name
= "Information";
1446 icon_name
= "dbox-question";
1447 shell_name
= "Prompt";
1451 text_input_slot
= True
;
1452 icon_name
= "dbox-question";
1453 shell_name
= "Prompt";
1457 icon_name
= "dbox-question";
1458 shell_name
= "Question";
1462 total_buttons
= name
[1] - '0';
1464 if (name
[3] == 'T' || name
[3] == 't')
1466 text_input_slot
= False
;
1470 right_buttons
= name
[4] - '0';
1472 left_buttons
= total_buttons
- right_buttons
;
1474 widget
= make_dialog (name
, parent
, pop_up_p
,
1475 shell_name
, icon_name
, text_input_slot
, radio_box
,
1476 list
, left_buttons
, right_buttons
);
1478 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1479 (XtPointer
) instance
);
1484 /* Create a menu bar. We turn off the f10 key
1485 because we have not yet managed to make it work right in Motif. */
1488 make_menubar (widget_instance
* instance
)
1494 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1495 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1499 remove_grabs (Widget shell
,
1501 XtPointer call_data
)
1503 Widget menu
= (Widget
) closure
;
1504 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1508 make_popup_menu (widget_instance
* instance
)
1510 Widget parent
= instance
->parent
;
1511 Window parent_window
= parent
->core
.window
;
1514 /* sets the parent window to 0 to fool Motif into not generating a grab */
1515 parent
->core
.window
= 0;
1516 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1517 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1519 parent
->core
.window
= parent_window
;
1524 make_main (widget_instance
* instance
)
1526 Widget parent
= instance
->parent
;
1532 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1533 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1534 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1538 \f/* Table of functions to create widgets */
1542 /* interface with the XDesigner generated functions */
1543 typedef Widget (*widget_maker
) (Widget
);
1544 extern Widget
create_project_p_sheet (Widget parent
);
1545 extern Widget
create_debugger_p_sheet (Widget parent
);
1546 extern Widget
create_breaklist_p_sheet (Widget parent
);
1547 extern Widget
create_le_browser_p_sheet (Widget parent
);
1548 extern Widget
create_class_browser_p_sheet (Widget parent
);
1549 extern Widget
create_call_browser_p_sheet (Widget parent
);
1550 extern Widget
create_build_dialog (Widget parent
);
1551 extern Widget
create_editmode_dialog (Widget parent
);
1552 extern Widget
create_search_dialog (Widget parent
);
1553 extern Widget
create_project_display_dialog (Widget parent
);
1556 make_one (widget_instance
* instance
, widget_maker fn
)
1562 if (instance
->pop_up_p
)
1564 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1565 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1566 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1567 (XtPointer
) instance
);
1572 result
= (*fn
) (instance
->parent
);
1573 XtRealizeWidget (result
);
1579 make_project_p_sheet (widget_instance
* instance
)
1581 return make_one (instance
, create_project_p_sheet
);
1585 make_debugger_p_sheet (widget_instance
* instance
)
1587 return make_one (instance
, create_debugger_p_sheet
);
1591 make_breaklist_p_sheet (widget_instance
* instance
)
1593 return make_one (instance
, create_breaklist_p_sheet
);
1597 make_le_browser_p_sheet (widget_instance
* instance
)
1599 return make_one (instance
, create_le_browser_p_sheet
);
1603 make_class_browser_p_sheet (widget_instance
* instance
)
1605 return make_one (instance
, create_class_browser_p_sheet
);
1609 make_call_browser_p_sheet (widget_instance
* instance
)
1611 return make_one (instance
, create_call_browser_p_sheet
);
1615 make_build_dialog (widget_instance
* instance
)
1617 return make_one (instance
, create_build_dialog
);
1621 make_editmode_dialog (widget_instance
* instance
)
1623 return make_one (instance
, create_editmode_dialog
);
1627 make_search_dialog (widget_instance
* instance
)
1629 return make_one (instance
, create_search_dialog
);
1633 make_project_display_dialog (widget_instance
* instance
)
1635 return make_one (instance
, create_project_display_dialog
);
1638 #endif /* ENERGIZE */
1640 widget_creation_entry
1641 xm_creation_table
[] =
1643 {"menubar", make_menubar
},
1644 {"popup", make_popup_menu
},
1645 {"main", make_main
},
1647 {"project_p_sheet", make_project_p_sheet
},
1648 {"debugger_p_sheet", make_debugger_p_sheet
},
1649 {"breaklist_psheet", make_breaklist_p_sheet
},
1650 {"leb_psheet", make_le_browser_p_sheet
},
1651 {"class_browser_psheet", make_class_browser_p_sheet
},
1652 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1653 {"build", make_build_dialog
},
1654 {"editmode", make_editmode_dialog
},
1655 {"search", make_search_dialog
},
1656 {"project_display", make_project_display_dialog
},
1657 #endif /* ENERGIZE */
1661 \f/* Destruction of instances */
1663 xm_destroy_instance ( widget_instance
* instance
)
1665 Widget widget
= instance
->widget
;
1666 /* recycle the dialog boxes */
1667 /* Disable the recycling until we can find a way to have the dialog box
1668 get reasonable layout after we modify its contents. */
1670 && XtClass (widget
) == xmDialogShellWidgetClass
)
1672 destroyed_instance
* dead_instance
=
1673 make_destroyed_instance (instance
->info
->name
,
1674 instance
->info
->type
,
1677 instance
->pop_up_p
);
1678 dead_instance
->next
= all_destroyed_instances
;
1679 all_destroyed_instances
= dead_instance
;
1680 XtUnmanageChild (first_child (instance
->widget
));
1681 XFlush (XtDisplay (instance
->widget
));
1682 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1683 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1687 /* This might not be necessary now that the nosel is attached to
1688 popdown instead of destroy, but it can't hurt. */
1689 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1690 xm_nosel_callback
, (XtPointer
)instance
);
1691 XtDestroyWidget (instance
->widget
);
1695 \f/* popup utility */
1697 xm_popup_menu (Widget widget
, XEvent
*event
)
1699 XButtonPressedEvent dummy
;
1703 dummy
.type
= ButtonPress
;
1705 dummy
.send_event
= 0;
1706 dummy
.display
= XtDisplay (widget
);
1707 dummy
.window
= XtWindow (XtParent (widget
));
1710 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1711 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1712 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1713 event
= (XEvent
*) &dummy
;
1716 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1718 /* Setting the menuPost resource only required by Motif 1.1 and
1719 LessTif 0.84 and earlier. With later versions of LessTif,
1720 setting menuPost is unnecessary and may cause problems, so
1722 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1724 /* This is so totally ridiculous: there's NO WAY to tell Motif
1725 that *any* button can select a menu item. Only one button
1726 can have that honor. */
1729 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1730 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1731 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1732 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1733 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1734 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1738 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1741 XtManageChild (widget
);
1745 set_min_dialog_size (Widget w
)
1749 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1750 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1754 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1756 Widget widget
= instance
->widget
;
1758 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1760 Widget widget_to_manage
= first_child (widget
);
1763 XtManageChild (widget_to_manage
);
1764 set_min_dialog_size (widget
);
1765 XtSetKeyboardFocus (instance
->parent
, widget
);
1768 XtUnmanageChild (widget_to_manage
);
1773 XtManageChild (widget
);
1775 XtUnmanageChild (widget
);
1780 /* motif callback */
1783 do_call (Widget widget
,
1785 enum do_call_type type
)
1789 XtPointer user_data
;
1790 widget_instance
* instance
= (widget_instance
*)closure
;
1791 Widget instance_widget
;
1796 if (widget
->core
.being_destroyed
)
1799 instance_widget
= instance
->widget
;
1800 if (!instance_widget
)
1803 id
= instance
->info
->id
;
1806 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1807 XtGetValues (widget
, al
, ac
);
1812 if (instance
->info
->pre_activate_cb
)
1813 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1817 if (instance
->info
->selection_cb
)
1818 instance
->info
->selection_cb (widget
, id
, user_data
);
1822 if (instance
->info
->selection_cb
)
1823 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1827 if (instance
->info
->post_activate_cb
)
1828 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1836 /* Like lw_internal_update_other_instances except that it does not do
1837 anything if its shell parent is not managed. This is to protect
1838 lw_internal_update_other_instances to dereference freed memory
1839 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1842 xm_internal_update_other_instances (Widget widget
,
1844 XtPointer call_data
)
1847 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1848 if (XtIsShell (parent
))
1850 else if (!XtIsManaged (parent
))
1852 lw_internal_update_other_instances (widget
, closure
, call_data
);
1856 xm_generic_callback (Widget widget
,
1858 XtPointer call_data
)
1860 lw_internal_update_other_instances (widget
, closure
, call_data
);
1861 do_call (widget
, closure
, selection
);
1865 xm_nosel_callback (Widget widget
,
1867 XtPointer call_data
)
1869 /* This callback is only called when a dialog box is dismissed with
1870 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1871 box to be destroyed in that case, not just unmapped, so that it
1872 releases its keyboard grabs. But there are problems with running
1873 our callbacks while the widget is in the process of being
1874 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1875 XmDESTROY and then destroy it ourself after having run the
1877 do_call (widget
, closure
, no_selection
);
1878 XtDestroyWidget (widget
);
1882 xm_pull_down_callback (Widget widget
,
1884 XtPointer call_data
)
1886 Widget parent
= XtParent (widget
);
1888 if (XmIsRowColumn (parent
))
1890 unsigned char type
= 0xff;
1891 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1892 if (type
== XmMENU_BAR
)
1893 do_call (widget
, closure
, pre_activate
);
1898 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1899 CLOSURE is a pointer to the widget_instance of the shell,
1901 Note that this callback is called for each cascade button in a
1902 menu, whether or not its submenu is visible. */
1905 xm_pop_down_callback (Widget widget
,
1907 XtPointer call_data
)
1909 widget_instance
*instance
= (widget_instance
*) closure
;
1911 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1912 || XtParent (widget
) == instance
->parent
)
1913 do_call (widget
, closure
, post_activate
);
1917 /* set the keyboard focus */
1919 xm_set_keyboard_focus (Widget parent
, Widget w
)
1921 XmProcessTraversal (w
, 0);
1922 XtSetKeyboardFocus (parent
, w
);
1925 /* Motif hack to set the main window areas. */
1927 xm_set_main_areas (Widget parent
,
1931 XmMainWindowSetAreas (parent
,
1932 menubar
, /* menubar (maybe 0) */
1933 0, /* command area (psheets) */
1934 0, /* horizontal scroll */
1935 0, /* vertical scroll */
1936 work_area
); /* work area */
1939 /* Motif hack to control resizing on the menubar. */
1941 xm_manage_resizing (Widget w
, Boolean flag
)
1943 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);