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)
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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
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>
34 #include "../src/lisp.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>
65 #if defined __STDC__ || defined PROTOTYPES
71 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
74 \f/* Structures to keep destroyed instances */
75 typedef struct _destroyed_instance
82 struct _destroyed_instance
* next
;
85 static destroyed_instance
*make_destroyed_instance
P_ ((char *, char *,
88 static void free_destroyed_instance
P_ ((destroyed_instance
*));
89 Widget first_child
P_ ((Widget
));
90 Boolean lw_motif_widget_p
P_ ((Widget
));
91 static XmString resource_motif_string
P_ ((Widget
, char *));
92 static void destroy_all_children
P_ ((Widget
, int));
93 static void xm_update_label
P_ ((widget_instance
*, Widget
, widget_value
*));
94 static void xm_update_list
P_ ((widget_instance
*, Widget
, widget_value
*));
95 static void xm_update_pushbutton
P_ ((widget_instance
*, Widget
,
97 static void xm_update_cascadebutton
P_ ((widget_instance
*, Widget
,
99 static void xm_update_toggle
P_ ((widget_instance
*, Widget
, widget_value
*));
100 static void xm_update_radiobox
P_ ((widget_instance
*, Widget
, widget_value
*));
101 static void make_menu_in_widget
P_ ((widget_instance
*, Widget
,
102 widget_value
*, int));
103 static void update_one_menu_entry
P_ ((widget_instance
*, Widget
,
104 widget_value
*, Boolean
));
105 static void xm_update_menu
P_ ((widget_instance
*, Widget
, widget_value
*,
107 static void xm_update_text
P_ ((widget_instance
*, Widget
, widget_value
*));
108 static void xm_update_text_field
P_ ((widget_instance
*, Widget
,
110 void xm_update_one_value
P_ ((widget_instance
*, Widget
, widget_value
*));
111 static void activate_button
P_ ((Widget
, XtPointer
, XtPointer
));
112 static Widget make_dialog
P_ ((char *, Widget
, Boolean
, char *, char *,
113 Boolean
, Boolean
, Boolean
, int, int));
114 static destroyed_instance
* find_matching_instance
P_ ((widget_instance
*));
115 static void mark_dead_instance_destroyed
P_ ((Widget
, XtPointer
, XtPointer
));
116 static void recenter_widget
P_ ((Widget
));
117 static Widget recycle_instance
P_ ((destroyed_instance
*));
118 Widget xm_create_dialog
P_ ((widget_instance
*));
119 static Widget make_menubar
P_ ((widget_instance
*));
120 static void remove_grabs
P_ ((Widget
, XtPointer
, XtPointer
));
121 static Widget make_popup_menu
P_ ((widget_instance
*));
122 static Widget make_main
P_ ((widget_instance
*));
123 void xm_destroy_instance
P_ ((widget_instance
*));
124 void xm_popup_menu
P_ ((Widget
, XEvent
*));
125 static void set_min_dialog_size
P_ ((Widget
));
126 static void do_call
P_ ((Widget
, XtPointer
, enum do_call_type
));
127 static void xm_generic_callback
P_ ((Widget
, XtPointer
, XtPointer
));
128 static void xm_nosel_callback
P_ ((Widget
, XtPointer
, XtPointer
));
129 static void xm_pull_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
130 static void xm_pop_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
131 void xm_set_keyboard_focus
P_ ((Widget
, Widget
));
132 void xm_set_main_areas
P_ ((Widget
, Widget
, Widget
));
133 static void xm_internal_update_other_instances
P_ ((Widget
, XtPointer
,
135 static void xm_arm_callback
P_ ((Widget
, XtPointer
, XtPointer
));
138 void xm_update_one_widget
P_ ((widget_instance
*, Widget
, widget_value
*,
140 void xm_pop_instance
P_ ((widget_instance
*, Boolean
));
141 void xm_manage_resizing
P_ ((Widget
, Boolean
));
147 /* Print the complete X resource name of widget WIDGET to stderr.
148 This is sometimes handy to have available. */
151 x_print_complete_resource_name (widget
)
157 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
159 names
[i
] = XtName (widget
);
160 widget
= XtParent (widget
);
163 for (--i
; i
>= 1; --i
)
164 fprintf (stderr
, "%s.", names
[i
]);
165 fprintf (stderr
, "%s\n", names
[0]);
171 static destroyed_instance
*all_destroyed_instances
= NULL
;
173 static destroyed_instance
*
174 make_destroyed_instance (name
, type
, widget
, parent
, pop_up_p
)
181 destroyed_instance
* instance
=
182 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
183 instance
->name
= safe_strdup (name
);
184 instance
->type
= safe_strdup (type
);
185 instance
->widget
= widget
;
186 instance
->parent
= parent
;
187 instance
->pop_up_p
= pop_up_p
;
188 instance
->next
= NULL
;
193 free_destroyed_instance (instance
)
194 destroyed_instance
* instance
;
196 free (instance
->name
);
197 free (instance
->type
);
201 \f/* motif utility functions */
206 return ((CompositeWidget
)widget
)->composite
.children
[0];
210 lw_motif_widget_p (widget
)
214 XtClass (widget
) == xmDialogShellWidgetClass
215 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
219 resource_motif_string (widget
, name
)
226 resource
.resource_name
= name
;
227 resource
.resource_class
= XmCXmString
;
228 resource
.resource_type
= XmRXmString
;
229 resource
.resource_size
= sizeof (XmString
);
230 resource
.resource_offset
= 0;
231 resource
.default_type
= XtRImmediate
;
232 resource
.default_addr
= 0;
234 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
235 "DialogString", &resource
, 1, NULL
, 0);
239 /* Destroy all of the children of WIDGET
240 starting with number FIRST_CHILD_TO_DESTROY. */
243 destroy_all_children (widget
, first_child_to_destroy
)
245 int first_child_to_destroy
;
251 children
= XtCompositeChildren (widget
, &number
);
254 XtUnmanageChildren (children
+ first_child_to_destroy
,
255 number
- first_child_to_destroy
);
257 /* Unmanage all children and destroy them. They will only be
258 really destroyed when we get out of DispatchEvent. */
259 for (i
= first_child_to_destroy
; i
< number
; i
++)
263 /* Cascade buttons have submenus,and these submenus
264 need to be freed. But they are not included in
265 XtCompositeChildren. So get it out of the cascade button
266 and free it. If this child is not a cascade button,
267 then submenu should remain unchanged. */
268 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
269 XtGetValues (children
[i
], al
, 1);
272 destroy_all_children (submenu
, 0);
273 XtDestroyWidget (submenu
);
275 XtDestroyWidget (children
[i
]);
278 XtFree ((char *) children
);
284 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
285 menu. CLIENT_DATA contains a pointer to the widget_value
286 corresponding to widget W. CALL_DATA contains a
287 XmPushButtonCallbackStruct containing the reason why the callback
291 xm_arm_callback (w
, client_data
, call_data
)
293 XtPointer client_data
, call_data
;
295 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
296 widget_value
*wv
= (widget_value
*) client_data
;
297 widget_instance
*instance
;
299 /* Get the id of the menu bar or popup menu this widget is in. */
302 if (XmIsRowColumn (w
))
304 unsigned char type
= 0xff;
306 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
307 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
316 instance
= lw_get_widget_instance (w
);
317 if (instance
&& instance
->info
->highlight_cb
)
319 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
320 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
327 /* Update the label of widget WIDGET. WIDGET must be a Label widget
328 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
333 Emacs fills VAL->name with the text to display in the menu, and
334 sets VAL->value to null. Function make_menu_in_widget creates
335 widgets with VAL->name as resource name. This works because the
336 Label widget uses its resource name for display if no
337 XmNlabelString is set.
341 VAL->name is again set to the resource name, but VAL->value is
342 not null, and contains the label string to display. */
345 xm_update_label (instance
, widget
, val
)
346 widget_instance
* instance
;
350 XmString res_string
= 0;
351 XmString built_string
= 0;
352 XmString key_string
= 0;
360 /* A label string is specified, i.e. we are in a dialog. First
361 see if it is overridden by something from the resource file. */
362 res_string
= resource_motif_string (widget
, val
->value
);
366 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
371 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
372 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
375 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
380 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
381 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
385 XtSetValues (widget
, al
, ac
);
388 XmStringFree (built_string
);
391 XmStringFree (key_string
);
394 \f/* update of list */
396 xm_update_list (instance
, widget
, val
)
397 widget_instance
* instance
;
403 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
404 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
406 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
409 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
411 XmListAddItem (widget
, xmstr
, 0);
413 XmListSelectPos (widget
, i
, False
);
414 XmStringFree (xmstr
);
418 \f/* update of buttons */
420 xm_update_pushbutton (instance
, widget
, val
)
421 widget_instance
* instance
;
425 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
426 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
427 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
431 xm_update_cascadebutton (instance
, widget
, val
)
432 widget_instance
* instance
;
436 /* Should also rebuild the menu by calling ...update_menu... */
437 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
438 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
442 \f/* update toggle and radiobox */
444 xm_update_toggle (instance
, widget
, val
)
445 widget_instance
* instance
;
449 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
450 XtAddCallback (widget
, XmNvalueChangedCallback
,
451 xm_generic_callback
, instance
);
452 XtVaSetValues (widget
, XmNset
, val
->selected
,
453 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
457 xm_update_radiobox (instance
, widget
, val
)
458 widget_instance
* instance
;
466 /* update the callback */
467 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
468 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
470 /* first update all the toggles */
471 /* Energize kernel interface is currently bad. It sets the selected widget
472 with the selected flag but returns it by its name. So we currently
473 have to support both setting the selection with the selected slot
474 of val contents and setting it with the "value" slot of val. The latter
475 has a higher priority. This to be removed when the kernel is fixed. */
476 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
478 toggle
= XtNameToWidget (widget
, cur
->value
);
481 XtSetSensitive (toggle
, cur
->enabled
);
482 if (!val
->value
&& cur
->selected
)
483 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
484 if (val
->value
&& strcmp (val
->value
, cur
->value
))
485 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
489 /* The selected was specified by the value slot */
492 toggle
= XtNameToWidget (widget
, val
->value
);
494 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
499 /* update a popup menu, pulldown menu or a menubar */
501 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
504 make_menu_in_widget (instance
, widget
, val
, keep_first_children
)
505 widget_instance
* instance
;
508 int keep_first_children
;
510 Widget
* children
= 0;
522 Widget
* old_children
;
523 unsigned int old_num_children
;
525 old_children
= XtCompositeChildren (widget
, &old_num_children
);
527 /* Allocate the children array */
528 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
530 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
532 /* WIDGET should be a RowColumn. */
533 if (!XmIsRowColumn (widget
))
536 /* Determine whether WIDGET is a menu bar. */
538 XtSetArg (al
[0], XmNrowColumnType
, &type
);
539 XtGetValues (widget
, al
, 1);
540 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
542 menubar_p
= type
== XmMENU_BAR
;
544 /* Add a callback to popups and pulldowns that is called when
545 it is made invisible again. */
547 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
548 xm_pop_down_callback
, (XtPointer
)instance
);
550 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
551 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
552 child_index
++, cur
= cur
->next
)
553 children
[child_index
] = old_children
[child_index
];
555 /* Check that those are all we have
556 (the caller should have deleted the rest). */
557 if (old_num_children
!= keep_first_children
)
560 /* Create the rest. */
561 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
563 enum menu_separator separator
;
566 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
567 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
568 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
570 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
571 && !lw_separator_p (cur
->name
, &separator
, 1))
574 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
575 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
577 else if (lw_separator_p (cur
->name
, &separator
, 1))
580 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
581 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
583 else if (!cur
->contents
)
586 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
587 else if (!cur
->call_data
)
588 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
589 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
590 || cur
->button_type
== BUTTON_TYPE_RADIO
)
592 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
593 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
594 XtSetArg (al
[ac
], XmNindicatorType
,
595 (cur
->button_type
== BUTTON_TYPE_TOGGLE
596 ? XmN_OF_MANY
: XmONE_OF_MANY
));
598 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
599 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
600 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
604 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
605 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
606 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
609 xm_update_label (instance
, button
, cur
);
611 /* Add a callback that is called when the button is
612 selected. Toggle buttons don't support
613 XmNactivateCallback, we use XmNvalueChangedCallback in
614 that case. Don't add a callback to a simple label. */
615 if (cur
->button_type
)
616 xm_update_toggle (instance
, button
, cur
);
617 else if (cur
->call_data
)
618 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
619 (XtPointer
)instance
);
623 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
625 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
626 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
627 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
629 xm_update_label (instance
, button
, cur
);
631 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
632 (XtPointer
)instance
);
635 children
[child_index
] = button
;
638 /* Last entry is the help button. The original comment read "Has to
639 be done after managing the buttons otherwise the menubar is only
640 4 pixels high." This is no longer true, and to make
641 XmNmenuHelpWidget work, we need to set it before managing the
642 children.. --gerd. */
644 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
647 XtManageChildren (children
, num_children
);
649 XtFree ((char *) children
);
651 XtFree ((char *) old_children
);
655 update_one_menu_entry (instance
, widget
, val
, deep_p
)
656 widget_instance
* instance
;
664 widget_value
* contents
;
666 if (val
->this_one_change
== NO_CHANGE
)
669 /* update the sensitivity and userdata */
670 /* Common to all widget types */
671 XtSetSensitive (widget
, val
->enabled
);
672 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
674 /* update the menu button as a label. */
675 if (val
->this_one_change
>= VISIBLE_CHANGE
)
677 xm_update_label (instance
, widget
, val
);
678 if (val
->button_type
)
679 xm_update_toggle (instance
, widget
, val
);
682 /* update the pulldown/pullaside as needed */
685 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
686 XtGetValues (widget
, al
, ac
);
688 contents
= val
->contents
;
694 unsigned int old_num_children
, i
;
698 parent
= XtParent (widget
);
699 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
701 /* Find the widget position within the parent's widget list. */
702 for (i
= 0; i
< old_num_children
; i
++)
703 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
705 if (i
== old_num_children
)
707 if (XmIsCascadeButton (widget_list
[i
]))
709 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
710 make_menu_in_widget (instance
, menu
, contents
, 0);
712 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
713 XtSetValues (widget
, al
, ac
);
719 /* The current menuitem is a XmPushButtonGadget, it
720 needs to be replaced by a CascadeButtonGadget */
721 XtDestroyWidget (widget_list
[i
]);
722 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
723 make_menu_in_widget (instance
, menu
, contents
, 0);
725 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
726 /* Non-zero values don't work reliably in
727 conjunction with Emacs' event loop */
728 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
729 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
730 /* Tell Motif to put it in the right place */
731 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
733 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
734 xm_update_label (instance
, button
, val
);
736 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
737 (XtPointer
)instance
);
738 XtManageChild (button
);
742 XtFree ((char*) widget_list
);
748 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
749 XtSetValues (widget
, al
, ac
);
750 XtDestroyWidget (menu
);
752 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
753 xm_update_menu (instance
, menu
, val
, 1);
757 xm_update_menu (instance
, widget
, val
, deep_p
)
758 widget_instance
* instance
;
764 unsigned int num_children
;
765 int num_children_to_keep
= 0;
769 children
= XtCompositeChildren (widget
, &num_children
);
771 /* Widget is a RowColumn widget whose contents have to be updated
772 * to reflect the list of items in val->contents */
774 /* See how many buttons we can keep, and how many we
775 must completely replace. */
776 if (val
->contents
== 0)
777 num_children_to_keep
= 0;
778 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
782 for (i
= 0, cur
= val
->contents
;
784 && cur
); /* how else to ditch unwanted children ?? - mgd */
785 i
++, cur
= cur
->next
)
787 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
791 num_children_to_keep
= i
;
795 num_children_to_keep
= num_children
;
797 /* Update all the buttons of the RowColumn, in order,
798 except for those we are going to replace entirely. */
801 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
805 num_children_to_keep
= i
;
808 if (children
[i
]->core
.being_destroyed
809 || strcmp (XtName (children
[i
]), cur
->name
))
811 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
816 /* Now replace from scratch all the buttons after the last
817 place that the top-level structure changed. */
818 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
820 destroy_all_children (widget
, num_children_to_keep
);
821 make_menu_in_widget (instance
, widget
, val
->contents
,
822 num_children_to_keep
);
825 XtFree ((char *) children
);
829 /* update text widgets */
832 xm_update_text (instance
, widget
, val
)
833 widget_instance
* instance
;
837 XmTextSetString (widget
, val
->value
? val
->value
: "");
838 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
839 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
840 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
841 XtAddCallback (widget
, XmNvalueChangedCallback
,
842 xm_internal_update_other_instances
, instance
);
846 xm_update_text_field (instance
, widget
, val
)
847 widget_instance
* instance
;
851 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
852 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
853 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
854 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
855 XtAddCallback (widget
, XmNvalueChangedCallback
,
856 xm_internal_update_other_instances
, instance
);
860 /* update a motif widget */
863 xm_update_one_widget (instance
, widget
, val
, deep_p
)
864 widget_instance
* instance
;
871 /* Mark as not edited */
874 /* Common to all widget types */
875 XtSetSensitive (widget
, val
->enabled
);
876 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
878 /* Common to all label like widgets */
879 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
880 xm_update_label (instance
, widget
, val
);
882 class = XtClass (widget
);
883 /* Class specific things */
884 if (class == xmPushButtonWidgetClass
||
885 class == xmArrowButtonWidgetClass
)
887 xm_update_pushbutton (instance
, widget
, val
);
889 else if (class == xmCascadeButtonWidgetClass
)
891 xm_update_cascadebutton (instance
, widget
, val
);
893 else if (class == xmToggleButtonWidgetClass
894 || class == xmToggleButtonGadgetClass
)
896 xm_update_toggle (instance
, widget
, val
);
898 else if (class == xmRowColumnWidgetClass
)
900 Boolean radiobox
= 0;
904 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
905 XtGetValues (widget
, al
, ac
);
908 xm_update_radiobox (instance
, widget
, val
);
910 xm_update_menu (instance
, widget
, val
, deep_p
);
912 else if (class == xmTextWidgetClass
)
914 xm_update_text (instance
, widget
, val
);
916 else if (class == xmTextFieldWidgetClass
)
918 xm_update_text_field (instance
, widget
, val
);
920 else if (class == xmListWidgetClass
)
922 xm_update_list (instance
, widget
, val
);
926 \f/* getting the value back */
928 xm_update_one_value (instance
, widget
, val
)
929 widget_instance
* instance
;
933 WidgetClass
class = XtClass (widget
);
934 widget_value
*old_wv
;
936 /* copy the call_data slot into the "return" widget_value */
937 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
938 if (!strcmp (val
->name
, old_wv
->name
))
940 val
->call_data
= old_wv
->call_data
;
944 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
946 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
949 else if (class == xmTextWidgetClass
)
953 val
->value
= XmTextGetString (widget
);
956 else if (class == xmTextFieldWidgetClass
)
960 val
->value
= XmTextFieldGetString (widget
);
963 else if (class == xmRowColumnWidgetClass
)
965 Boolean radiobox
= 0;
969 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
970 XtGetValues (widget
, al
, ac
);
974 CompositeWidget radio
= (CompositeWidget
)widget
;
976 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
979 Widget toggle
= radio
->composite
.children
[i
];
981 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
986 val
->value
= safe_strdup (XtName (toggle
));
992 else if (class == xmListWidgetClass
)
996 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
1000 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
1004 cur
->selected
= False
;
1006 for (j
= 0; j
< pos_cnt
; j
++)
1007 if (pos_list
[j
] == i
)
1009 cur
->selected
= True
;
1010 val
->value
= safe_strdup (cur
->name
);
1014 XtFree ((char *) pos_list
);
1020 /* This function is for activating a button from a program. It's wrong because
1021 we pass a NULL argument in the call_data which is not Motif compatible.
1022 This is used from the XmNdefaultAction callback of the List widgets to
1023 have a double-click put down a dialog box like the button would do.
1024 I could not find a way to do that with accelerators.
1027 activate_button (widget
, closure
, call_data
)
1030 XtPointer call_data
;
1032 Widget button
= (Widget
)closure
;
1033 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1036 /* creation functions */
1040 make_dialog (name
, parent
, pop_up_p
, shell_title
, icon_name
, text_input_slot
,
1041 radio_box
, list
, left_buttons
, right_buttons
)
1047 Boolean text_input_slot
;
1057 Widget icon_separator
;
1062 Widget children
[16]; /* for the final XtManageChildren */
1064 Arg al
[64]; /* Arg List */
1065 int ac
; /* Arg Count */
1071 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1072 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1073 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1074 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1076 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1077 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1078 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1079 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1084 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1085 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1086 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1090 n_children
= left_buttons
+ right_buttons
+ 1;
1092 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1093 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1094 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1095 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1096 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1097 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1098 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1099 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1100 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1101 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1102 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1103 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1104 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1105 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1106 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1107 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1108 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1109 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1110 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1113 for (i
= 0; i
< left_buttons
; i
++)
1115 char button_name
[16];
1116 sprintf (button_name
, "button%d", i
+ 1);
1120 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1121 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1123 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1124 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1125 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1129 button
= children
[n_children
];
1131 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1132 XtSetValues (row
, al
, ac
);
1138 /* invisible separator button */
1140 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1141 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1144 for (i
= 0; i
< right_buttons
; i
++)
1146 char button_name
[16];
1147 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1149 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1150 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1151 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1152 if (! button
) button
= children
[n_children
];
1156 XtManageChildren (children
, n_children
);
1159 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1160 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1161 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1162 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1163 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1164 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1165 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1167 separator
= XmCreateSeparator (form
, "", al
, ac
);
1170 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1171 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1172 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1173 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1174 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1175 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1176 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1177 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1180 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1181 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1182 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1183 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1184 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1185 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1186 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1187 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1188 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1189 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1191 if (text_input_slot
)
1194 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1195 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1196 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1197 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1198 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1199 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1200 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1201 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1202 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1203 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1204 value
= XmCreateTextField (form
, "value", al
, ac
);
1210 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1211 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1212 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1213 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1214 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1215 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1216 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1217 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1218 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1219 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1220 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1221 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1222 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1223 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1226 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1227 children
[i
++] = radio_butt
;
1228 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1229 children
[i
++] = radio_butt
;
1230 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1231 children
[i
++] = radio_butt
;
1232 XtManageChildren (children
, i
);
1237 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1238 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1239 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1240 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1241 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1242 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1243 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1244 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1245 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1246 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1247 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1249 /* this is the easiest way I found to have the dble click in the
1250 list activate the default button */
1251 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1255 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1256 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1257 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1258 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1259 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1260 XtSetArg(al
[ac
], XmNbottomWidget
,
1261 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1262 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1263 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1264 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1265 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1266 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1267 message
= XmCreateLabel (form
, "message", al
, ac
);
1270 XtManageChild (value
);
1273 children
[i
] = row
; i
++;
1274 children
[i
] = separator
; i
++;
1275 if (text_input_slot
|| radio_box
)
1277 children
[i
] = value
; i
++;
1279 children
[i
] = message
; i
++;
1280 children
[i
] = icon
; i
++;
1281 children
[i
] = icon_separator
; i
++;
1282 XtManageChildren (children
, i
);
1284 if (text_input_slot
|| list
)
1286 XtInstallAccelerators (value
, button
);
1287 XtSetKeyboardFocus (result
, value
);
1291 XtInstallAccelerators (form
, button
);
1292 XtSetKeyboardFocus (result
, button
);
1298 static destroyed_instance
*
1299 find_matching_instance (instance
)
1300 widget_instance
* instance
;
1302 destroyed_instance
* cur
;
1303 destroyed_instance
* prev
;
1304 char* type
= instance
->info
->type
;
1305 char* name
= instance
->info
->name
;
1307 for (prev
= NULL
, cur
= all_destroyed_instances
;
1309 prev
= cur
, cur
= cur
->next
)
1311 if (!strcmp (cur
->name
, name
)
1312 && !strcmp (cur
->type
, type
)
1313 && cur
->parent
== instance
->parent
1314 && cur
->pop_up_p
== instance
->pop_up_p
)
1317 prev
->next
= cur
->next
;
1319 all_destroyed_instances
= cur
->next
;
1322 /* do some cleanup */
1323 else if (!cur
->widget
)
1326 prev
->next
= cur
->next
;
1328 all_destroyed_instances
= cur
->next
;
1329 free_destroyed_instance (cur
);
1330 cur
= prev
? prev
: all_destroyed_instances
;
1337 mark_dead_instance_destroyed (widget
, closure
, call_data
)
1340 XtPointer call_data
;
1342 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1343 instance
->widget
= NULL
;
1347 recenter_widget (widget
)
1350 Widget parent
= XtParent (widget
);
1351 Screen
* screen
= XtScreen (widget
);
1352 Dimension screen_width
= WidthOfScreen (screen
);
1353 Dimension screen_height
= HeightOfScreen (screen
);
1354 Dimension parent_width
= 0;
1355 Dimension parent_height
= 0;
1356 Dimension child_width
= 0;
1357 Dimension child_height
= 0;
1361 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1362 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1365 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1366 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1368 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1370 if (x
+ child_width
> screen_width
)
1371 x
= screen_width
- child_width
;
1375 if (y
+ child_height
> screen_height
)
1376 y
= screen_height
- child_height
;
1380 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1384 recycle_instance (instance
)
1385 destroyed_instance
* instance
;
1387 Widget widget
= instance
->widget
;
1389 /* widget is NULL if the parent was destroyed. */
1395 /* Remove the destroy callback as the instance is not in the list
1397 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1398 mark_dead_instance_destroyed
,
1399 (XtPointer
)instance
);
1401 /* Give the focus to the initial item */
1402 focus
= XtNameToWidget (widget
, "*value");
1404 focus
= XtNameToWidget (widget
, "*button1");
1406 XtSetKeyboardFocus (widget
, focus
);
1408 /* shrink the separator label back to their original size */
1409 separator
= XtNameToWidget (widget
, "*separator_button");
1411 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1413 /* Center the dialog in its parent */
1414 recenter_widget (widget
);
1416 free_destroyed_instance (instance
);
1421 xm_create_dialog (instance
)
1422 widget_instance
* instance
;
1424 char* name
= instance
->info
->type
;
1425 Widget parent
= instance
->parent
;
1427 Boolean pop_up_p
= instance
->pop_up_p
;
1428 char* shell_name
= 0;
1429 char* icon_name
= 0;
1430 Boolean text_input_slot
= False
;
1431 Boolean radio_box
= False
;
1432 Boolean list
= False
;
1434 int left_buttons
= 0;
1435 int right_buttons
= 1;
1436 destroyed_instance
* dead_one
;
1438 /* try to find a widget to recycle */
1439 dead_one
= find_matching_instance (instance
);
1442 Widget recycled_widget
= recycle_instance (dead_one
);
1443 if (recycled_widget
)
1444 return recycled_widget
;
1449 icon_name
= "dbox-error";
1450 shell_name
= "Error";
1454 icon_name
= "dbox-info";
1455 shell_name
= "Information";
1460 icon_name
= "dbox-question";
1461 shell_name
= "Prompt";
1465 text_input_slot
= True
;
1466 icon_name
= "dbox-question";
1467 shell_name
= "Prompt";
1471 icon_name
= "dbox-question";
1472 shell_name
= "Question";
1476 total_buttons
= name
[1] - '0';
1478 if (name
[3] == 'T' || name
[3] == 't')
1480 text_input_slot
= False
;
1484 right_buttons
= name
[4] - '0';
1486 left_buttons
= total_buttons
- right_buttons
;
1488 widget
= make_dialog (name
, parent
, pop_up_p
,
1489 shell_name
, icon_name
, text_input_slot
, radio_box
,
1490 list
, left_buttons
, right_buttons
);
1492 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1493 (XtPointer
) instance
);
1497 /* Create a menu bar. We turn off the f10 key
1498 because we have not yet managed to make it work right in Motif. */
1501 make_menubar (instance
)
1502 widget_instance
* instance
;
1508 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1509 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1513 remove_grabs (shell
, closure
, call_data
)
1516 XtPointer call_data
;
1518 Widget menu
= (Widget
) closure
;
1519 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1523 make_popup_menu (instance
)
1524 widget_instance
* instance
;
1526 Widget parent
= instance
->parent
;
1527 Window parent_window
= parent
->core
.window
;
1530 /* sets the parent window to 0 to fool Motif into not generating a grab */
1531 parent
->core
.window
= 0;
1532 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1533 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1535 parent
->core
.window
= parent_window
;
1540 make_main (instance
)
1541 widget_instance
* instance
;
1543 Widget parent
= instance
->parent
;
1549 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1550 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1551 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1555 \f/* Table of functions to create widgets */
1559 /* interface with the XDesigner generated functions */
1560 typedef Widget (*widget_maker
) (Widget
);
1561 extern Widget
create_project_p_sheet (Widget parent
);
1562 extern Widget
create_debugger_p_sheet (Widget parent
);
1563 extern Widget
create_breaklist_p_sheet (Widget parent
);
1564 extern Widget
create_le_browser_p_sheet (Widget parent
);
1565 extern Widget
create_class_browser_p_sheet (Widget parent
);
1566 extern Widget
create_call_browser_p_sheet (Widget parent
);
1567 extern Widget
create_build_dialog (Widget parent
);
1568 extern Widget
create_editmode_dialog (Widget parent
);
1569 extern Widget
create_search_dialog (Widget parent
);
1570 extern Widget
create_project_display_dialog (Widget parent
);
1573 make_one (widget_instance
* instance
, widget_maker fn
)
1579 if (instance
->pop_up_p
)
1581 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1582 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1583 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1584 (XtPointer
) instance
);
1589 result
= (*fn
) (instance
->parent
);
1590 XtRealizeWidget (result
);
1596 make_project_p_sheet (widget_instance
* instance
)
1598 return make_one (instance
, create_project_p_sheet
);
1602 make_debugger_p_sheet (widget_instance
* instance
)
1604 return make_one (instance
, create_debugger_p_sheet
);
1608 make_breaklist_p_sheet (widget_instance
* instance
)
1610 return make_one (instance
, create_breaklist_p_sheet
);
1614 make_le_browser_p_sheet (widget_instance
* instance
)
1616 return make_one (instance
, create_le_browser_p_sheet
);
1620 make_class_browser_p_sheet (widget_instance
* instance
)
1622 return make_one (instance
, create_class_browser_p_sheet
);
1626 make_call_browser_p_sheet (widget_instance
* instance
)
1628 return make_one (instance
, create_call_browser_p_sheet
);
1632 make_build_dialog (widget_instance
* instance
)
1634 return make_one (instance
, create_build_dialog
);
1638 make_editmode_dialog (widget_instance
* instance
)
1640 return make_one (instance
, create_editmode_dialog
);
1644 make_search_dialog (widget_instance
* instance
)
1646 return make_one (instance
, create_search_dialog
);
1650 make_project_display_dialog (widget_instance
* instance
)
1652 return make_one (instance
, create_project_display_dialog
);
1655 #endif /* ENERGIZE */
1657 widget_creation_entry
1658 xm_creation_table
[] =
1660 {"menubar", make_menubar
},
1661 {"popup", make_popup_menu
},
1662 {"main", make_main
},
1664 {"project_p_sheet", make_project_p_sheet
},
1665 {"debugger_p_sheet", make_debugger_p_sheet
},
1666 {"breaklist_psheet", make_breaklist_p_sheet
},
1667 {"leb_psheet", make_le_browser_p_sheet
},
1668 {"class_browser_psheet", make_class_browser_p_sheet
},
1669 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1670 {"build", make_build_dialog
},
1671 {"editmode", make_editmode_dialog
},
1672 {"search", make_search_dialog
},
1673 {"project_display", make_project_display_dialog
},
1674 #endif /* ENERGIZE */
1678 \f/* Destruction of instances */
1680 xm_destroy_instance (instance
)
1681 widget_instance
* instance
;
1683 Widget widget
= instance
->widget
;
1684 /* recycle the dialog boxes */
1685 /* Disable the recycling until we can find a way to have the dialog box
1686 get reasonable layout after we modify its contents. */
1688 && XtClass (widget
) == xmDialogShellWidgetClass
)
1690 destroyed_instance
* dead_instance
=
1691 make_destroyed_instance (instance
->info
->name
,
1692 instance
->info
->type
,
1695 instance
->pop_up_p
);
1696 dead_instance
->next
= all_destroyed_instances
;
1697 all_destroyed_instances
= dead_instance
;
1698 XtUnmanageChild (first_child (instance
->widget
));
1699 XFlush (XtDisplay (instance
->widget
));
1700 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1701 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1705 /* This might not be necessary now that the nosel is attached to
1706 popdown instead of destroy, but it can't hurt. */
1707 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1708 xm_nosel_callback
, (XtPointer
)instance
);
1709 XtDestroyWidget (instance
->widget
);
1713 \f/* popup utility */
1715 xm_popup_menu (widget
, event
)
1719 XButtonPressedEvent dummy
;
1723 dummy
.type
= ButtonPress
;
1725 dummy
.send_event
= 0;
1726 dummy
.display
= XtDisplay (widget
);
1727 dummy
.window
= XtWindow (XtParent (widget
));
1730 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1731 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1732 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1733 event
= (XEvent
*) &dummy
;
1736 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1738 /* Setting the menuPost resource only required by Motif 1.1 and
1739 LessTif 0.84 and earlier. With later versions of LessTif,
1740 setting menuPost is unnecessary and may cause problems, so
1742 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1744 /* This is so totally ridiculous: there's NO WAY to tell Motif
1745 that *any* button can select a menu item. Only one button
1746 can have that honor. */
1749 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1750 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1751 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1752 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1753 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1754 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1758 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1761 XtManageChild (widget
);
1765 set_min_dialog_size (w
)
1770 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1771 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1775 xm_pop_instance (instance
, up
)
1776 widget_instance
* instance
;
1779 Widget widget
= instance
->widget
;
1781 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1783 Widget widget_to_manage
= first_child (widget
);
1786 XtManageChild (widget_to_manage
);
1787 set_min_dialog_size (widget
);
1788 XtSetKeyboardFocus (instance
->parent
, widget
);
1791 XtUnmanageChild (widget_to_manage
);
1796 XtManageChild (widget
);
1798 XtUnmanageChild (widget
);
1803 /* motif callback */
1806 do_call (widget
, closure
, type
)
1809 enum do_call_type type
;
1813 XtPointer user_data
;
1814 widget_instance
* instance
= (widget_instance
*)closure
;
1815 Widget instance_widget
;
1820 if (widget
->core
.being_destroyed
)
1823 instance_widget
= instance
->widget
;
1824 if (!instance_widget
)
1827 id
= instance
->info
->id
;
1830 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1831 XtGetValues (widget
, al
, ac
);
1836 if (instance
->info
->pre_activate_cb
)
1837 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1841 if (instance
->info
->selection_cb
)
1842 instance
->info
->selection_cb (widget
, id
, user_data
);
1846 if (instance
->info
->selection_cb
)
1847 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1851 if (instance
->info
->post_activate_cb
)
1852 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1860 /* Like lw_internal_update_other_instances except that it does not do
1861 anything if its shell parent is not managed. This is to protect
1862 lw_internal_update_other_instances to dereference freed memory
1863 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1866 xm_internal_update_other_instances (widget
, closure
, call_data
)
1869 XtPointer call_data
;
1872 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1873 if (XtIsShell (parent
))
1875 else if (!XtIsManaged (parent
))
1877 lw_internal_update_other_instances (widget
, closure
, call_data
);
1881 xm_generic_callback (widget
, closure
, call_data
)
1884 XtPointer call_data
;
1886 lw_internal_update_other_instances (widget
, closure
, call_data
);
1887 do_call (widget
, closure
, selection
);
1891 xm_nosel_callback (widget
, closure
, call_data
)
1894 XtPointer call_data
;
1896 /* This callback is only called when a dialog box is dismissed with
1897 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1898 box to be destroyed in that case, not just unmapped, so that it
1899 releases its keyboard grabs. But there are problems with running
1900 our callbacks while the widget is in the process of being
1901 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1902 XmDESTROY and then destroy it ourself after having run the
1904 do_call (widget
, closure
, no_selection
);
1905 XtDestroyWidget (widget
);
1909 xm_pull_down_callback (widget
, closure
, call_data
)
1912 XtPointer call_data
;
1914 Widget parent
= XtParent (widget
);
1916 if (XmIsRowColumn (parent
))
1918 unsigned char type
= 0xff;
1919 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1920 if (type
== XmMENU_BAR
)
1921 do_call (widget
, closure
, pre_activate
);
1926 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1927 CLOSURE is a pointer to the widget_instance of the shell,
1929 Note that this callback is called for each cascade button in a
1930 menu, whether or not its submenu is visible. */
1933 xm_pop_down_callback (widget
, closure
, call_data
)
1936 XtPointer call_data
;
1938 widget_instance
*instance
= (widget_instance
*) closure
;
1940 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1941 || XtParent (widget
) == instance
->parent
)
1942 do_call (widget
, closure
, post_activate
);
1946 /* set the keyboard focus */
1948 xm_set_keyboard_focus (parent
, w
)
1952 XmProcessTraversal (w
, 0);
1953 XtSetKeyboardFocus (parent
, w
);
1956 /* Motif hack to set the main window areas. */
1958 xm_set_main_areas (parent
, menubar
, work_area
)
1963 XmMainWindowSetAreas (parent
,
1964 menubar
, /* menubar (maybe 0) */
1965 0, /* command area (psheets) */
1966 0, /* horizontal scroll */
1967 0, /* vertical scroll */
1968 work_area
); /* work area */
1971 /* Motif hack to control resizing on the menubar. */
1973 xm_manage_resizing (w
, flag
)
1977 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);