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);
271 XtDestroyWidget (submenu
);
272 XtDestroyWidget (children
[i
]);
275 XtFree ((char *) children
);
281 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
282 menu. CLIENT_DATA contains a pointer to the widget_value
283 corresponding to widget W. CALL_DATA contains a
284 XmPushButtonCallbackStruct containing the reason why the callback
288 xm_arm_callback (w
, client_data
, call_data
)
290 XtPointer client_data
, call_data
;
292 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
293 widget_value
*wv
= (widget_value
*) client_data
;
294 widget_instance
*instance
;
296 /* Get the id of the menu bar or popup menu this widget is in. */
299 if (XmIsRowColumn (w
))
301 unsigned char type
= 0xff;
303 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
304 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
313 instance
= lw_get_widget_instance (w
);
314 if (instance
&& instance
->info
->highlight_cb
)
316 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
317 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
324 /* Update the label of widget WIDGET. WIDGET must be a Label widget
325 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
330 Emacs fills VAL->name with the text to display in the menu, and
331 sets VAL->value to null. Function make_menu_in_widget creates
332 widgets with VAL->name as resource name. This works because the
333 Label widget uses its resource name for display if no
334 XmNlabelString is set.
338 VAL->name is again set to the resource name, but VAL->value is
339 not null, and contains the label string to display. */
342 xm_update_label (instance
, widget
, val
)
343 widget_instance
* instance
;
347 XmString res_string
= 0;
348 XmString built_string
= 0;
349 XmString key_string
= 0;
357 /* A label string is specified, i.e. we are in a dialog. First
358 see if it is overridden by something from the resource file. */
359 res_string
= resource_motif_string (widget
, val
->value
);
363 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
368 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
369 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
372 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
377 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
378 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
382 XtSetValues (widget
, al
, ac
);
385 XmStringFree (built_string
);
388 XmStringFree (key_string
);
391 \f/* update of list */
393 xm_update_list (instance
, widget
, val
)
394 widget_instance
* instance
;
400 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
401 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
403 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
406 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
408 XmListAddItem (widget
, xmstr
, 0);
410 XmListSelectPos (widget
, i
, False
);
411 XmStringFree (xmstr
);
415 \f/* update of buttons */
417 xm_update_pushbutton (instance
, widget
, val
)
418 widget_instance
* instance
;
422 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
423 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
424 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
428 xm_update_cascadebutton (instance
, widget
, val
)
429 widget_instance
* instance
;
433 /* Should also rebuild the menu by calling ...update_menu... */
434 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
435 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
439 \f/* update toggle and radiobox */
441 xm_update_toggle (instance
, widget
, val
)
442 widget_instance
* instance
;
446 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
447 XtAddCallback (widget
, XmNvalueChangedCallback
,
448 xm_generic_callback
, instance
);
449 XtVaSetValues (widget
, XmNset
, val
->selected
,
450 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
454 xm_update_radiobox (instance
, widget
, val
)
455 widget_instance
* instance
;
463 /* update the callback */
464 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
465 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
467 /* first update all the toggles */
468 /* Energize kernel interface is currently bad. It sets the selected widget
469 with the selected flag but returns it by its name. So we currently
470 have to support both setting the selection with the selected slot
471 of val contents and setting it with the "value" slot of val. The latter
472 has a higher priority. This to be removed when the kernel is fixed. */
473 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
475 toggle
= XtNameToWidget (widget
, cur
->value
);
478 XtSetSensitive (toggle
, cur
->enabled
);
479 if (!val
->value
&& cur
->selected
)
480 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
481 if (val
->value
&& strcmp (val
->value
, cur
->value
))
482 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
486 /* The selected was specified by the value slot */
489 toggle
= XtNameToWidget (widget
, val
->value
);
491 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
496 /* update a popup menu, pulldown menu or a menubar */
498 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
501 make_menu_in_widget (instance
, widget
, val
, keep_first_children
)
502 widget_instance
* instance
;
505 int keep_first_children
;
507 Widget
* children
= 0;
519 Widget
* old_children
;
520 unsigned int old_num_children
;
522 old_children
= XtCompositeChildren (widget
, &old_num_children
);
524 /* Allocate the children array */
525 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
527 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
529 /* WIDGET should be a RowColumn. */
530 if (!XmIsRowColumn (widget
))
533 /* Determine whether WIDGET is a menu bar. */
535 XtSetArg (al
[0], XmNrowColumnType
, &type
);
536 XtGetValues (widget
, al
, 1);
537 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
539 menubar_p
= type
== XmMENU_BAR
;
541 /* Add a callback to popups and pulldowns that is called when
542 it is made invisible again. */
544 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
545 xm_pop_down_callback
, (XtPointer
)instance
);
547 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
548 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
549 child_index
++, cur
= cur
->next
)
550 children
[child_index
] = old_children
[child_index
];
552 /* Check that those are all we have
553 (the caller should have deleted the rest). */
554 if (old_num_children
!= keep_first_children
)
557 /* Create the rest. */
558 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
560 enum menu_separator separator
;
563 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
564 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
565 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
567 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
568 && !lw_separator_p (cur
->name
, &separator
, 1))
571 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
572 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
574 else if (lw_separator_p (cur
->name
, &separator
, 1))
577 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
578 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
580 else if (!cur
->contents
)
583 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
584 else if (!cur
->call_data
)
585 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
586 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
587 || cur
->button_type
== BUTTON_TYPE_RADIO
)
589 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
590 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
591 XtSetArg (al
[ac
], XmNindicatorType
,
592 (cur
->button_type
== BUTTON_TYPE_TOGGLE
593 ? XmN_OF_MANY
: XmONE_OF_MANY
));
595 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
596 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
597 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
601 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
602 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
603 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
606 xm_update_label (instance
, button
, cur
);
608 /* Add a callback that is called when the button is
609 selected. Toggle buttons don't support
610 XmNactivateCallback, we use XmNvalueChangedCallback in
611 that case. Don't add a callback to a simple label. */
612 if (cur
->button_type
)
613 xm_update_toggle (instance
, button
, cur
);
614 else if (cur
->call_data
)
615 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
616 (XtPointer
)instance
);
620 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
622 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
623 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
624 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
626 xm_update_label (instance
, button
, cur
);
628 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
629 (XtPointer
)instance
);
632 children
[child_index
] = button
;
635 /* Last entry is the help button. The original comment read "Has to
636 be done after managing the buttons otherwise the menubar is only
637 4 pixels high." This is no longer true, and to make
638 XmNmenuHelpWidget work, we need to set it before managing the
639 children.. --gerd. */
641 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
644 XtManageChildren (children
, num_children
);
646 XtFree ((char *) children
);
648 XtFree ((char *) old_children
);
652 update_one_menu_entry (instance
, widget
, val
, deep_p
)
653 widget_instance
* instance
;
661 widget_value
* contents
;
663 if (val
->this_one_change
== NO_CHANGE
)
666 /* update the sensitivity and userdata */
667 /* Common to all widget types */
668 XtSetSensitive (widget
, val
->enabled
);
669 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
671 /* update the menu button as a label. */
672 if (val
->this_one_change
>= VISIBLE_CHANGE
)
674 xm_update_label (instance
, widget
, val
);
675 if (val
->button_type
)
676 xm_update_toggle (instance
, widget
, val
);
679 /* update the pulldown/pullaside as needed */
682 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
683 XtGetValues (widget
, al
, ac
);
685 contents
= val
->contents
;
691 unsigned int old_num_children
, i
;
695 parent
= XtParent (widget
);
696 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
698 /* Find the widget position within the parent's widget list. */
699 for (i
= 0; i
< old_num_children
; i
++)
700 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
702 if (i
== old_num_children
)
704 if (XmIsCascadeButton (widget_list
[i
]))
706 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
707 make_menu_in_widget (instance
, menu
, contents
, 0);
709 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
710 XtSetValues (widget
, al
, ac
);
716 /* The current menuitem is a XmPushButtonGadget, it
717 needs to be replaced by a CascadeButtonGadget */
718 XtDestroyWidget (widget_list
[i
]);
719 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
720 make_menu_in_widget (instance
, menu
, contents
, 0);
722 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
723 /* Non-zero values don't work reliably in
724 conjunction with Emacs' event loop */
725 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
726 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
727 /* Tell Motif to put it in the right place */
728 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
730 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
731 xm_update_label (instance
, button
, val
);
733 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
734 (XtPointer
)instance
);
735 XtManageChild (button
);
742 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
743 XtSetValues (widget
, al
, ac
);
744 XtDestroyWidget (menu
);
746 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
747 xm_update_menu (instance
, menu
, val
, 1);
751 xm_update_menu (instance
, widget
, val
, deep_p
)
752 widget_instance
* instance
;
758 unsigned int num_children
;
759 int num_children_to_keep
= 0;
763 children
= XtCompositeChildren (widget
, &num_children
);
765 /* Widget is a RowColumn widget whose contents have to be updated
766 * to reflect the list of items in val->contents */
768 /* See how many buttons we can keep, and how many we
769 must completely replace. */
770 if (val
->contents
== 0)
771 num_children_to_keep
= 0;
772 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
776 for (i
= 0, cur
= val
->contents
;
778 && cur
); /* how else to ditch unwanted children ?? - mgd */
779 i
++, cur
= cur
->next
)
781 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
785 num_children_to_keep
= i
;
789 num_children_to_keep
= num_children
;
791 /* Update all the buttons of the RowColumn, in order,
792 except for those we are going to replace entirely. */
795 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
799 num_children_to_keep
= i
;
802 if (children
[i
]->core
.being_destroyed
803 || strcmp (XtName (children
[i
]), cur
->name
))
805 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
810 /* Now replace from scratch all the buttons after the last
811 place that the top-level structure changed. */
812 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
814 destroy_all_children (widget
, num_children_to_keep
);
815 make_menu_in_widget (instance
, widget
, val
->contents
,
816 num_children_to_keep
);
819 XtFree ((char *) children
);
823 /* update text widgets */
826 xm_update_text (instance
, widget
, val
)
827 widget_instance
* instance
;
831 XmTextSetString (widget
, val
->value
? val
->value
: "");
832 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
833 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
834 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
835 XtAddCallback (widget
, XmNvalueChangedCallback
,
836 xm_internal_update_other_instances
, instance
);
840 xm_update_text_field (instance
, widget
, val
)
841 widget_instance
* instance
;
845 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
846 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
847 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
848 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
849 XtAddCallback (widget
, XmNvalueChangedCallback
,
850 xm_internal_update_other_instances
, instance
);
854 /* update a motif widget */
857 xm_update_one_widget (instance
, widget
, val
, deep_p
)
858 widget_instance
* instance
;
865 /* Mark as not edited */
868 /* Common to all widget types */
869 XtSetSensitive (widget
, val
->enabled
);
870 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
872 /* Common to all label like widgets */
873 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
874 xm_update_label (instance
, widget
, val
);
876 class = XtClass (widget
);
877 /* Class specific things */
878 if (class == xmPushButtonWidgetClass
||
879 class == xmArrowButtonWidgetClass
)
881 xm_update_pushbutton (instance
, widget
, val
);
883 else if (class == xmCascadeButtonWidgetClass
)
885 xm_update_cascadebutton (instance
, widget
, val
);
887 else if (class == xmToggleButtonWidgetClass
888 || class == xmToggleButtonGadgetClass
)
890 xm_update_toggle (instance
, widget
, val
);
892 else if (class == xmRowColumnWidgetClass
)
894 Boolean radiobox
= 0;
898 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
899 XtGetValues (widget
, al
, ac
);
902 xm_update_radiobox (instance
, widget
, val
);
904 xm_update_menu (instance
, widget
, val
, deep_p
);
906 else if (class == xmTextWidgetClass
)
908 xm_update_text (instance
, widget
, val
);
910 else if (class == xmTextFieldWidgetClass
)
912 xm_update_text_field (instance
, widget
, val
);
914 else if (class == xmListWidgetClass
)
916 xm_update_list (instance
, widget
, val
);
920 \f/* getting the value back */
922 xm_update_one_value (instance
, widget
, val
)
923 widget_instance
* instance
;
927 WidgetClass
class = XtClass (widget
);
928 widget_value
*old_wv
;
930 /* copy the call_data slot into the "return" widget_value */
931 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
932 if (!strcmp (val
->name
, old_wv
->name
))
934 val
->call_data
= old_wv
->call_data
;
938 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
940 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
943 else if (class == xmTextWidgetClass
)
947 val
->value
= XmTextGetString (widget
);
950 else if (class == xmTextFieldWidgetClass
)
954 val
->value
= XmTextFieldGetString (widget
);
957 else if (class == xmRowColumnWidgetClass
)
959 Boolean radiobox
= 0;
963 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
964 XtGetValues (widget
, al
, ac
);
968 CompositeWidget radio
= (CompositeWidget
)widget
;
970 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
973 Widget toggle
= radio
->composite
.children
[i
];
975 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
980 val
->value
= safe_strdup (XtName (toggle
));
986 else if (class == xmListWidgetClass
)
990 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
994 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
998 cur
->selected
= False
;
1000 for (j
= 0; j
< pos_cnt
; j
++)
1001 if (pos_list
[j
] == i
)
1003 cur
->selected
= True
;
1004 val
->value
= safe_strdup (cur
->name
);
1008 XtFree ((char *) pos_list
);
1014 /* This function is for activating a button from a program. It's wrong because
1015 we pass a NULL argument in the call_data which is not Motif compatible.
1016 This is used from the XmNdefaultAction callback of the List widgets to
1017 have a double-click put down a dialog box like the button would do.
1018 I could not find a way to do that with accelerators.
1021 activate_button (widget
, closure
, call_data
)
1024 XtPointer call_data
;
1026 Widget button
= (Widget
)closure
;
1027 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1030 /* creation functions */
1034 make_dialog (name
, parent
, pop_up_p
, shell_title
, icon_name
, text_input_slot
,
1035 radio_box
, list
, left_buttons
, right_buttons
)
1041 Boolean text_input_slot
;
1051 Widget icon_separator
;
1056 Widget children
[16]; /* for the final XtManageChildren */
1058 Arg al
[64]; /* Arg List */
1059 int ac
; /* Arg Count */
1065 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1066 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1067 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1068 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1070 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1071 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1072 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1073 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1078 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1079 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1080 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1084 n_children
= left_buttons
+ right_buttons
+ 1;
1086 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1087 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1088 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1089 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1090 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1091 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1092 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1093 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1094 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1095 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1096 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1097 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1098 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1099 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1100 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1101 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1102 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1103 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1104 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1107 for (i
= 0; i
< left_buttons
; i
++)
1109 char button_name
[16];
1110 sprintf (button_name
, "button%d", i
+ 1);
1114 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1115 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1117 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1118 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1119 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1123 button
= children
[n_children
];
1125 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1126 XtSetValues (row
, al
, ac
);
1132 /* invisible separator button */
1134 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1135 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1138 for (i
= 0; i
< right_buttons
; i
++)
1140 char button_name
[16];
1141 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1143 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1144 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1145 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1146 if (! button
) button
= children
[n_children
];
1150 XtManageChildren (children
, n_children
);
1153 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1154 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1155 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1156 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1157 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1158 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1159 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1160 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1161 separator
= XmCreateSeparator (form
, "", al
, ac
);
1164 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1165 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1167 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1168 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1169 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1170 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1171 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1174 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1175 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1176 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1177 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1178 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1179 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1180 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1181 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1182 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1183 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1185 if (text_input_slot
)
1188 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1189 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1190 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1191 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1192 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1193 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1194 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1195 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1196 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1197 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1198 value
= XmCreateTextField (form
, "value", al
, ac
);
1204 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1205 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1206 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1207 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1208 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1209 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1210 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1211 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1212 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1213 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1214 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1215 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1216 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1217 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1220 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1221 children
[i
++] = radio_butt
;
1222 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1223 children
[i
++] = radio_butt
;
1224 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1225 children
[i
++] = radio_butt
;
1226 XtManageChildren (children
, i
);
1231 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1232 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1233 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1234 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1235 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1236 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1237 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1238 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1239 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1240 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1241 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1243 /* this is the easiest way I found to have the dble click in the
1244 list activate the default button */
1245 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1249 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1250 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1251 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1252 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1253 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1254 XtSetArg(al
[ac
], XmNbottomWidget
,
1255 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1256 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1257 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1258 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1259 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1260 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1261 message
= XmCreateLabel (form
, "message", al
, ac
);
1264 XtManageChild (value
);
1267 children
[i
] = row
; i
++;
1268 children
[i
] = separator
; i
++;
1269 if (text_input_slot
|| radio_box
)
1271 children
[i
] = value
; i
++;
1273 children
[i
] = message
; i
++;
1274 children
[i
] = icon
; i
++;
1275 children
[i
] = icon_separator
; i
++;
1276 XtManageChildren (children
, i
);
1278 if (text_input_slot
|| list
)
1280 XtInstallAccelerators (value
, button
);
1281 XtSetKeyboardFocus (result
, value
);
1285 XtInstallAccelerators (form
, button
);
1286 XtSetKeyboardFocus (result
, button
);
1292 static destroyed_instance
*
1293 find_matching_instance (instance
)
1294 widget_instance
* instance
;
1296 destroyed_instance
* cur
;
1297 destroyed_instance
* prev
;
1298 char* type
= instance
->info
->type
;
1299 char* name
= instance
->info
->name
;
1301 for (prev
= NULL
, cur
= all_destroyed_instances
;
1303 prev
= cur
, cur
= cur
->next
)
1305 if (!strcmp (cur
->name
, name
)
1306 && !strcmp (cur
->type
, type
)
1307 && cur
->parent
== instance
->parent
1308 && cur
->pop_up_p
== instance
->pop_up_p
)
1311 prev
->next
= cur
->next
;
1313 all_destroyed_instances
= cur
->next
;
1316 /* do some cleanup */
1317 else if (!cur
->widget
)
1320 prev
->next
= cur
->next
;
1322 all_destroyed_instances
= cur
->next
;
1323 free_destroyed_instance (cur
);
1324 cur
= prev
? prev
: all_destroyed_instances
;
1331 mark_dead_instance_destroyed (widget
, closure
, call_data
)
1334 XtPointer call_data
;
1336 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1337 instance
->widget
= NULL
;
1341 recenter_widget (widget
)
1344 Widget parent
= XtParent (widget
);
1345 Screen
* screen
= XtScreen (widget
);
1346 Dimension screen_width
= WidthOfScreen (screen
);
1347 Dimension screen_height
= HeightOfScreen (screen
);
1348 Dimension parent_width
= 0;
1349 Dimension parent_height
= 0;
1350 Dimension child_width
= 0;
1351 Dimension child_height
= 0;
1355 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1356 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1359 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1360 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1362 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1364 if (x
+ child_width
> screen_width
)
1365 x
= screen_width
- child_width
;
1369 if (y
+ child_height
> screen_height
)
1370 y
= screen_height
- child_height
;
1374 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1378 recycle_instance (instance
)
1379 destroyed_instance
* instance
;
1381 Widget widget
= instance
->widget
;
1383 /* widget is NULL if the parent was destroyed. */
1389 /* Remove the destroy callback as the instance is not in the list
1391 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1392 mark_dead_instance_destroyed
,
1393 (XtPointer
)instance
);
1395 /* Give the focus to the initial item */
1396 focus
= XtNameToWidget (widget
, "*value");
1398 focus
= XtNameToWidget (widget
, "*button1");
1400 XtSetKeyboardFocus (widget
, focus
);
1402 /* shrink the separator label back to their original size */
1403 separator
= XtNameToWidget (widget
, "*separator_button");
1405 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1407 /* Center the dialog in its parent */
1408 recenter_widget (widget
);
1410 free_destroyed_instance (instance
);
1415 xm_create_dialog (instance
)
1416 widget_instance
* instance
;
1418 char* name
= instance
->info
->type
;
1419 Widget parent
= instance
->parent
;
1421 Boolean pop_up_p
= instance
->pop_up_p
;
1422 char* shell_name
= 0;
1423 char* icon_name
= 0;
1424 Boolean text_input_slot
= False
;
1425 Boolean radio_box
= False
;
1426 Boolean list
= False
;
1428 int left_buttons
= 0;
1429 int right_buttons
= 1;
1430 destroyed_instance
* dead_one
;
1432 /* try to find a widget to recycle */
1433 dead_one
= find_matching_instance (instance
);
1436 Widget recycled_widget
= recycle_instance (dead_one
);
1437 if (recycled_widget
)
1438 return recycled_widget
;
1443 icon_name
= "dbox-error";
1444 shell_name
= "Error";
1448 icon_name
= "dbox-info";
1449 shell_name
= "Information";
1454 icon_name
= "dbox-question";
1455 shell_name
= "Prompt";
1459 text_input_slot
= True
;
1460 icon_name
= "dbox-question";
1461 shell_name
= "Prompt";
1465 icon_name
= "dbox-question";
1466 shell_name
= "Question";
1470 total_buttons
= name
[1] - '0';
1472 if (name
[3] == 'T' || name
[3] == 't')
1474 text_input_slot
= False
;
1478 right_buttons
= name
[4] - '0';
1480 left_buttons
= total_buttons
- right_buttons
;
1482 widget
= make_dialog (name
, parent
, pop_up_p
,
1483 shell_name
, icon_name
, text_input_slot
, radio_box
,
1484 list
, left_buttons
, right_buttons
);
1486 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1487 (XtPointer
) instance
);
1491 /* Create a menu bar. We turn off the f10 key
1492 because we have not yet managed to make it work right in Motif. */
1495 make_menubar (instance
)
1496 widget_instance
* instance
;
1502 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1503 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1507 remove_grabs (shell
, closure
, call_data
)
1510 XtPointer call_data
;
1512 Widget menu
= (Widget
) closure
;
1513 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1517 make_popup_menu (instance
)
1518 widget_instance
* instance
;
1520 Widget parent
= instance
->parent
;
1521 Window parent_window
= parent
->core
.window
;
1524 /* sets the parent window to 0 to fool Motif into not generating a grab */
1525 parent
->core
.window
= 0;
1526 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1527 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1529 parent
->core
.window
= parent_window
;
1534 make_main (instance
)
1535 widget_instance
* instance
;
1537 Widget parent
= instance
->parent
;
1543 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1544 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1545 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1549 \f/* Table of functions to create widgets */
1553 /* interface with the XDesigner generated functions */
1554 typedef Widget (*widget_maker
) (Widget
);
1555 extern Widget
create_project_p_sheet (Widget parent
);
1556 extern Widget
create_debugger_p_sheet (Widget parent
);
1557 extern Widget
create_breaklist_p_sheet (Widget parent
);
1558 extern Widget
create_le_browser_p_sheet (Widget parent
);
1559 extern Widget
create_class_browser_p_sheet (Widget parent
);
1560 extern Widget
create_call_browser_p_sheet (Widget parent
);
1561 extern Widget
create_build_dialog (Widget parent
);
1562 extern Widget
create_editmode_dialog (Widget parent
);
1563 extern Widget
create_search_dialog (Widget parent
);
1564 extern Widget
create_project_display_dialog (Widget parent
);
1567 make_one (widget_instance
* instance
, widget_maker fn
)
1573 if (instance
->pop_up_p
)
1575 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1576 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1577 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1578 (XtPointer
) instance
);
1583 result
= (*fn
) (instance
->parent
);
1584 XtRealizeWidget (result
);
1590 make_project_p_sheet (widget_instance
* instance
)
1592 return make_one (instance
, create_project_p_sheet
);
1596 make_debugger_p_sheet (widget_instance
* instance
)
1598 return make_one (instance
, create_debugger_p_sheet
);
1602 make_breaklist_p_sheet (widget_instance
* instance
)
1604 return make_one (instance
, create_breaklist_p_sheet
);
1608 make_le_browser_p_sheet (widget_instance
* instance
)
1610 return make_one (instance
, create_le_browser_p_sheet
);
1614 make_class_browser_p_sheet (widget_instance
* instance
)
1616 return make_one (instance
, create_class_browser_p_sheet
);
1620 make_call_browser_p_sheet (widget_instance
* instance
)
1622 return make_one (instance
, create_call_browser_p_sheet
);
1626 make_build_dialog (widget_instance
* instance
)
1628 return make_one (instance
, create_build_dialog
);
1632 make_editmode_dialog (widget_instance
* instance
)
1634 return make_one (instance
, create_editmode_dialog
);
1638 make_search_dialog (widget_instance
* instance
)
1640 return make_one (instance
, create_search_dialog
);
1644 make_project_display_dialog (widget_instance
* instance
)
1646 return make_one (instance
, create_project_display_dialog
);
1649 #endif /* ENERGIZE */
1651 widget_creation_entry
1652 xm_creation_table
[] =
1654 {"menubar", make_menubar
},
1655 {"popup", make_popup_menu
},
1656 {"main", make_main
},
1658 {"project_p_sheet", make_project_p_sheet
},
1659 {"debugger_p_sheet", make_debugger_p_sheet
},
1660 {"breaklist_psheet", make_breaklist_p_sheet
},
1661 {"leb_psheet", make_le_browser_p_sheet
},
1662 {"class_browser_psheet", make_class_browser_p_sheet
},
1663 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1664 {"build", make_build_dialog
},
1665 {"editmode", make_editmode_dialog
},
1666 {"search", make_search_dialog
},
1667 {"project_display", make_project_display_dialog
},
1668 #endif /* ENERGIZE */
1672 \f/* Destruction of instances */
1674 xm_destroy_instance (instance
)
1675 widget_instance
* instance
;
1677 Widget widget
= instance
->widget
;
1678 /* recycle the dialog boxes */
1679 /* Disable the recycling until we can find a way to have the dialog box
1680 get reasonable layout after we modify its contents. */
1682 && XtClass (widget
) == xmDialogShellWidgetClass
)
1684 destroyed_instance
* dead_instance
=
1685 make_destroyed_instance (instance
->info
->name
,
1686 instance
->info
->type
,
1689 instance
->pop_up_p
);
1690 dead_instance
->next
= all_destroyed_instances
;
1691 all_destroyed_instances
= dead_instance
;
1692 XtUnmanageChild (first_child (instance
->widget
));
1693 XFlush (XtDisplay (instance
->widget
));
1694 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1695 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1699 /* This might not be necessary now that the nosel is attached to
1700 popdown instead of destroy, but it can't hurt. */
1701 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1702 xm_nosel_callback
, (XtPointer
)instance
);
1703 XtDestroyWidget (instance
->widget
);
1707 \f/* popup utility */
1709 xm_popup_menu (widget
, event
)
1713 XButtonPressedEvent dummy
;
1717 dummy
.type
= ButtonPress
;
1719 dummy
.send_event
= 0;
1720 dummy
.display
= XtDisplay (widget
);
1721 dummy
.window
= XtWindow (XtParent (widget
));
1724 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1725 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1726 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1727 event
= (XEvent
*) &dummy
;
1730 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1732 /* Setting the menuPost resource only required by Motif 1.1 and
1733 LessTif 0.84 and earlier. With later versions of LessTif,
1734 setting menuPost is unnecessary and may cause problems, so
1736 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1738 /* This is so totally ridiculous: there's NO WAY to tell Motif
1739 that *any* button can select a menu item. Only one button
1740 can have that honor. */
1743 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1744 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1745 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1746 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1747 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1748 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1752 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1755 XtManageChild (widget
);
1759 set_min_dialog_size (w
)
1764 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1765 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1769 xm_pop_instance (instance
, up
)
1770 widget_instance
* instance
;
1773 Widget widget
= instance
->widget
;
1775 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1777 Widget widget_to_manage
= first_child (widget
);
1780 XtManageChild (widget_to_manage
);
1781 set_min_dialog_size (widget
);
1782 XtSetKeyboardFocus (instance
->parent
, widget
);
1785 XtUnmanageChild (widget_to_manage
);
1790 XtManageChild (widget
);
1792 XtUnmanageChild (widget
);
1797 /* motif callback */
1800 do_call (widget
, closure
, type
)
1803 enum do_call_type type
;
1807 XtPointer user_data
;
1808 widget_instance
* instance
= (widget_instance
*)closure
;
1809 Widget instance_widget
;
1814 if (widget
->core
.being_destroyed
)
1817 instance_widget
= instance
->widget
;
1818 if (!instance_widget
)
1821 id
= instance
->info
->id
;
1824 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1825 XtGetValues (widget
, al
, ac
);
1830 if (instance
->info
->pre_activate_cb
)
1831 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1835 if (instance
->info
->selection_cb
)
1836 instance
->info
->selection_cb (widget
, id
, user_data
);
1840 if (instance
->info
->selection_cb
)
1841 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1845 if (instance
->info
->post_activate_cb
)
1846 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1854 /* Like lw_internal_update_other_instances except that it does not do
1855 anything if its shell parent is not managed. This is to protect
1856 lw_internal_update_other_instances to dereference freed memory
1857 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1860 xm_internal_update_other_instances (widget
, closure
, call_data
)
1863 XtPointer call_data
;
1866 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1867 if (XtIsShell (parent
))
1869 else if (!XtIsManaged (parent
))
1871 lw_internal_update_other_instances (widget
, closure
, call_data
);
1875 xm_generic_callback (widget
, closure
, call_data
)
1878 XtPointer call_data
;
1880 lw_internal_update_other_instances (widget
, closure
, call_data
);
1881 do_call (widget
, closure
, selection
);
1885 xm_nosel_callback (widget
, closure
, call_data
)
1888 XtPointer call_data
;
1890 /* This callback is only called when a dialog box is dismissed with
1891 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1892 box to be destroyed in that case, not just unmapped, so that it
1893 releases its keyboard grabs. But there are problems with running
1894 our callbacks while the widget is in the process of being
1895 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1896 XmDESTROY and then destroy it ourself after having run the
1898 do_call (widget
, closure
, no_selection
);
1899 XtDestroyWidget (widget
);
1903 xm_pull_down_callback (widget
, closure
, call_data
)
1906 XtPointer call_data
;
1908 Widget parent
= XtParent (widget
);
1910 if (XmIsRowColumn (parent
))
1912 unsigned char type
= 0xff;
1913 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1914 if (type
== XmMENU_BAR
)
1915 do_call (widget
, closure
, pre_activate
);
1920 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1921 CLOSURE is a pointer to the widget_instance of the shell,
1923 Note that this callback is called for each cascade button in a
1924 menu, whether or not its submenu is visible. */
1927 xm_pop_down_callback (widget
, closure
, call_data
)
1930 XtPointer call_data
;
1932 widget_instance
*instance
= (widget_instance
*) closure
;
1934 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1935 || XtParent (widget
) == instance
->parent
)
1936 do_call (widget
, closure
, post_activate
);
1940 /* set the keyboard focus */
1942 xm_set_keyboard_focus (parent
, w
)
1946 XmProcessTraversal (w
, 0);
1947 XtSetKeyboardFocus (parent
, w
);
1950 /* Motif hack to set the main window areas. */
1952 xm_set_main_areas (parent
, menubar
, work_area
)
1957 XmMainWindowSetAreas (parent
,
1958 menubar
, /* menubar (maybe 0) */
1959 0, /* command area (psheets) */
1960 0, /* horizontal scroll */
1961 0, /* vertical scroll */
1962 work_area
); /* work area */
1965 /* Motif hack to control resizing on the menubar. */
1967 xm_manage_resizing (w
, flag
)
1971 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);