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>
64 #if defined __STDC__ || defined PROTOTYPES
70 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
73 \f/* Structures to keep destroyed instances */
74 typedef struct _destroyed_instance
81 struct _destroyed_instance
* next
;
84 static destroyed_instance
*make_destroyed_instance
P_ ((char *, char *,
87 static void free_destroyed_instance
P_ ((destroyed_instance
*));
88 Widget first_child
P_ ((Widget
));
89 Boolean lw_motif_widget_p
P_ ((Widget
));
90 static XmString resource_motif_string
P_ ((Widget
, char *));
91 static void destroy_all_children
P_ ((Widget
, int));
92 static void xm_update_label
P_ ((widget_instance
*, Widget
, widget_value
*));
93 static void xm_update_list
P_ ((widget_instance
*, Widget
, widget_value
*));
94 static void xm_update_pushbutton
P_ ((widget_instance
*, Widget
,
96 static void xm_update_cascadebutton
P_ ((widget_instance
*, Widget
,
98 static void xm_update_toggle
P_ ((widget_instance
*, Widget
, widget_value
*));
99 static void xm_update_radiobox
P_ ((widget_instance
*, Widget
, widget_value
*));
100 static void make_menu_in_widget
P_ ((widget_instance
*, Widget
,
101 widget_value
*, int));
102 static void update_one_menu_entry
P_ ((widget_instance
*, Widget
,
103 widget_value
*, Boolean
));
104 static void xm_update_menu
P_ ((widget_instance
*, Widget
, widget_value
*,
106 static void xm_update_text
P_ ((widget_instance
*, Widget
, widget_value
*));
107 static void xm_update_text_field
P_ ((widget_instance
*, Widget
,
109 void xm_update_one_value
P_ ((widget_instance
*, Widget
, widget_value
*));
110 static void activate_button
P_ ((Widget
, XtPointer
, XtPointer
));
111 static Widget make_dialog
P_ ((char *, Widget
, Boolean
, char *, char *,
112 Boolean
, Boolean
, Boolean
, int, int));
113 static destroyed_instance
* find_matching_instance
P_ ((widget_instance
*));
114 static void mark_dead_instance_destroyed
P_ ((Widget
, XtPointer
, XtPointer
));
115 static void recenter_widget
P_ ((Widget
));
116 static Widget recycle_instance
P_ ((destroyed_instance
*));
117 Widget xm_create_dialog
P_ ((widget_instance
*));
118 static Widget make_menubar
P_ ((widget_instance
*));
119 static void remove_grabs
P_ ((Widget
, XtPointer
, XtPointer
));
120 static Widget make_popup_menu
P_ ((widget_instance
*));
121 static Widget make_main
P_ ((widget_instance
*));
122 void xm_destroy_instance
P_ ((widget_instance
*));
123 void xm_popup_menu
P_ ((Widget
, XEvent
*));
124 static void set_min_dialog_size
P_ ((Widget
));
125 static void do_call
P_ ((Widget
, XtPointer
, enum do_call_type
));
126 static void xm_generic_callback
P_ ((Widget
, XtPointer
, XtPointer
));
127 static void xm_nosel_callback
P_ ((Widget
, XtPointer
, XtPointer
));
128 static void xm_pull_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
129 static void xm_pop_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
130 void xm_set_keyboard_focus
P_ ((Widget
, Widget
));
131 void xm_set_main_areas
P_ ((Widget
, Widget
, Widget
));
132 static void xm_internal_update_other_instances
P_ ((Widget
, XtPointer
,
134 static void xm_arm_callback
P_ ((Widget
, XtPointer
, XtPointer
));
137 void xm_update_one_widget
P_ ((widget_instance
*, Widget
, widget_value
*,
139 void xm_pop_instance
P_ ((widget_instance
*, Boolean
));
140 void xm_manage_resizing
P_ ((Widget
, Boolean
));
146 /* Print the complete X resource name of widget WIDGET to stderr.
147 This is sometimes handy to have available. */
150 x_print_complete_resource_name (widget
)
156 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
158 names
[i
] = XtName (widget
);
159 widget
= XtParent (widget
);
162 for (--i
; i
>= 1; --i
)
163 fprintf (stderr
, "%s.", names
[i
]);
164 fprintf (stderr
, "%s\n", names
[0]);
170 static destroyed_instance
*all_destroyed_instances
= NULL
;
172 static destroyed_instance
*
173 make_destroyed_instance (name
, type
, widget
, parent
, pop_up_p
)
180 destroyed_instance
* instance
=
181 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
182 instance
->name
= safe_strdup (name
);
183 instance
->type
= safe_strdup (type
);
184 instance
->widget
= widget
;
185 instance
->parent
= parent
;
186 instance
->pop_up_p
= pop_up_p
;
187 instance
->next
= NULL
;
192 free_destroyed_instance (instance
)
193 destroyed_instance
* instance
;
195 free (instance
->name
);
196 free (instance
->type
);
200 \f/* motif utility functions */
205 return ((CompositeWidget
)widget
)->composite
.children
[0];
209 lw_motif_widget_p (widget
)
213 XtClass (widget
) == xmDialogShellWidgetClass
214 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
218 resource_motif_string (widget
, name
)
225 resource
.resource_name
= name
;
226 resource
.resource_class
= XmCXmString
;
227 resource
.resource_type
= XmRXmString
;
228 resource
.resource_size
= sizeof (XmString
);
229 resource
.resource_offset
= 0;
230 resource
.default_type
= XtRImmediate
;
231 resource
.default_addr
= 0;
233 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
234 "DialogString", &resource
, 1, NULL
, 0);
238 /* Destroy all of the children of WIDGET
239 starting with number FIRST_CHILD_TO_DESTROY. */
242 destroy_all_children (widget
, first_child_to_destroy
)
244 int first_child_to_destroy
;
250 children
= XtCompositeChildren (widget
, &number
);
253 XtUnmanageChildren (children
+ first_child_to_destroy
,
254 number
- first_child_to_destroy
);
256 /* Unmanage all children and destroy them. They will only be
257 really destroyed when we get out of DispatchEvent. */
258 for (i
= first_child_to_destroy
; i
< number
; i
++)
262 /* Cascade buttons have submenus,and these submenus
263 need to be freed. But they are not included in
264 XtCompositeChildren. So get it out of the cascade button
265 and free it. If this child is not a cascade button,
266 then submenu should remain unchanged. */
267 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
268 XtGetValues (children
[i
], al
, 1);
270 XtDestroyWidget (submenu
);
271 XtDestroyWidget (children
[i
]);
274 XtFree ((char *) children
);
280 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
281 menu. CLIENT_DATA contains a pointer to the widget_value
282 corresponding to widget W. CALL_DATA contains a
283 XmPushButtonCallbackStruct containing the reason why the callback
287 xm_arm_callback (w
, client_data
, call_data
)
289 XtPointer client_data
, call_data
;
291 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
292 widget_value
*wv
= (widget_value
*) client_data
;
293 widget_instance
*instance
;
295 /* Get the id of the menu bar or popup menu this widget is in. */
298 if (XmIsRowColumn (w
))
300 unsigned char type
= 0xff;
302 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
303 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
312 instance
= lw_get_widget_instance (w
);
313 if (instance
&& instance
->info
->highlight_cb
)
315 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
316 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
323 /* Update the label of widget WIDGET. WIDGET must be a Label widget
324 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
329 Emacs fills VAL->name with the text to display in the menu, and
330 sets VAL->value to null. Function make_menu_in_widget creates
331 widgets with VAL->name as resource name. This works because the
332 Label widget uses its resource name for display if no
333 XmNlabelString is set.
337 VAL->name is again set to the resource name, but VAL->value is
338 not null, and contains the label string to display. */
341 xm_update_label (instance
, widget
, val
)
342 widget_instance
* instance
;
346 XmString res_string
= 0;
347 XmString built_string
= 0;
348 XmString key_string
= 0;
356 /* A label string is specified, i.e. we are in a dialog. First
357 see if it is overridden by something from the resource file. */
358 res_string
= resource_motif_string (widget
, val
->value
);
362 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
367 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
368 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
371 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
376 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
377 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
381 XtSetValues (widget
, al
, ac
);
384 XmStringFree (built_string
);
387 XmStringFree (key_string
);
390 \f/* update of list */
392 xm_update_list (instance
, widget
, val
)
393 widget_instance
* instance
;
399 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
400 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
402 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
405 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
407 XmListAddItem (widget
, xmstr
, 0);
409 XmListSelectPos (widget
, i
, False
);
410 XmStringFree (xmstr
);
414 \f/* update of buttons */
416 xm_update_pushbutton (instance
, widget
, val
)
417 widget_instance
* instance
;
421 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
422 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
423 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
427 xm_update_cascadebutton (instance
, widget
, val
)
428 widget_instance
* instance
;
432 /* Should also rebuild the menu by calling ...update_menu... */
433 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
434 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
438 \f/* update toggle and radiobox */
440 xm_update_toggle (instance
, widget
, val
)
441 widget_instance
* instance
;
445 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
446 XtAddCallback (widget
, XmNvalueChangedCallback
,
447 xm_generic_callback
, instance
);
448 XtVaSetValues (widget
, XmNset
, val
->selected
,
449 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
453 xm_update_radiobox (instance
, widget
, val
)
454 widget_instance
* instance
;
462 /* update the callback */
463 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
464 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
466 /* first update all the toggles */
467 /* Energize kernel interface is currently bad. It sets the selected widget
468 with the selected flag but returns it by its name. So we currently
469 have to support both setting the selection with the selected slot
470 of val contents and setting it with the "value" slot of val. The latter
471 has a higher priority. This to be removed when the kernel is fixed. */
472 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
474 toggle
= XtNameToWidget (widget
, cur
->value
);
477 XtSetSensitive (toggle
, cur
->enabled
);
478 if (!val
->value
&& cur
->selected
)
479 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
480 if (val
->value
&& strcmp (val
->value
, cur
->value
))
481 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
485 /* The selected was specified by the value slot */
488 toggle
= XtNameToWidget (widget
, val
->value
);
490 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
495 /* update a popup menu, pulldown menu or a menubar */
497 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
500 make_menu_in_widget (instance
, widget
, val
, keep_first_children
)
501 widget_instance
* instance
;
504 int keep_first_children
;
506 Widget
* children
= 0;
518 Widget
* old_children
;
519 unsigned int old_num_children
;
521 old_children
= XtCompositeChildren (widget
, &old_num_children
);
523 /* Allocate the children array */
524 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
526 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
528 /* WIDGET should be a RowColumn. */
529 if (!XmIsRowColumn (widget
))
532 /* Determine whether WIDGET is a menu bar. */
534 XtSetArg (al
[0], XmNrowColumnType
, &type
);
535 XtGetValues (widget
, al
, 1);
536 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
538 menubar_p
= type
== XmMENU_BAR
;
540 /* Add a callback to popups and pulldowns that is called when
541 it is made invisible again. */
543 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
544 xm_pop_down_callback
, (XtPointer
)instance
);
546 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
547 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
548 child_index
++, cur
= cur
->next
)
549 children
[child_index
] = old_children
[child_index
];
551 /* Check that those are all we have
552 (the caller should have deleted the rest). */
553 if (old_num_children
!= keep_first_children
)
556 /* Create the rest. */
557 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
559 enum menu_separator separator
;
562 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
563 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
564 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
566 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
567 && !lw_separator_p (cur
->name
, &separator
, 1))
570 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
571 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
573 else if (lw_separator_p (cur
->name
, &separator
, 1))
576 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
577 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
579 else if (!cur
->contents
)
582 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
583 else if (!cur
->call_data
)
584 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
585 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
586 || cur
->button_type
== BUTTON_TYPE_RADIO
)
588 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
589 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
590 XtSetArg (al
[ac
], XmNindicatorType
,
591 (cur
->button_type
== BUTTON_TYPE_TOGGLE
592 ? XmN_OF_MANY
: XmONE_OF_MANY
));
594 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
595 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
596 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
600 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
601 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
602 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
605 xm_update_label (instance
, button
, cur
);
607 /* Add a callback that is called when the button is
608 selected. Toggle buttons don't support
609 XmNactivateCallback, we use XmNvalueChangedCallback in
610 that case. Don't add a callback to a simple label. */
611 if (cur
->button_type
)
612 xm_update_toggle (instance
, button
, cur
);
613 else if (cur
->call_data
)
614 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
615 (XtPointer
)instance
);
619 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
621 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
622 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
623 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
625 xm_update_label (instance
, button
, cur
);
627 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
628 (XtPointer
)instance
);
631 children
[child_index
] = button
;
634 /* Last entry is the help button. The original comment read "Has to
635 be done after managing the buttons otherwise the menubar is only
636 4 pixels high." This is no longer true, and to make
637 XmNmenuHelpWidget work, we need to set it before managing the
638 children.. --gerd. */
640 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
643 XtManageChildren (children
, num_children
);
645 XtFree ((char *) children
);
647 XtFree ((char *) old_children
);
651 update_one_menu_entry (instance
, widget
, val
, deep_p
)
652 widget_instance
* instance
;
660 widget_value
* contents
;
662 if (val
->this_one_change
== NO_CHANGE
)
665 /* update the sensitivity and userdata */
666 /* Common to all widget types */
667 XtSetSensitive (widget
, val
->enabled
);
668 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
670 /* update the menu button as a label. */
671 if (val
->this_one_change
>= VISIBLE_CHANGE
)
673 xm_update_label (instance
, widget
, val
);
674 if (val
->button_type
)
675 xm_update_toggle (instance
, widget
, val
);
678 /* update the pulldown/pullaside as needed */
681 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
682 XtGetValues (widget
, al
, ac
);
684 contents
= val
->contents
;
690 unsigned int old_num_children
, i
;
694 parent
= XtParent (widget
);
695 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
697 /* Find the widget position within the parent's widget list. */
698 for (i
= 0; i
< old_num_children
; i
++)
699 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
701 if (i
== old_num_children
)
703 if (XmIsCascadeButton (widget_list
[i
]))
705 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
706 make_menu_in_widget (instance
, menu
, contents
, 0);
708 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
709 XtSetValues (widget
, al
, ac
);
715 /* The current menuitem is a XmPushButtonGadget, it
716 needs to be replaced by a CascadeButtonGadget */
717 XtDestroyWidget (widget_list
[i
]);
718 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
719 make_menu_in_widget (instance
, menu
, contents
, 0);
721 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
722 /* Non-zero values don't work reliably in
723 conjunction with Emacs' event loop */
724 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
725 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
726 /* Tell Motif to put it in the right place */
727 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
729 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
730 xm_update_label (instance
, button
, val
);
732 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
733 (XtPointer
)instance
);
734 XtManageChild (button
);
741 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
742 XtSetValues (widget
, al
, ac
);
743 XtDestroyWidget (menu
);
745 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
746 xm_update_menu (instance
, menu
, val
, 1);
750 xm_update_menu (instance
, widget
, val
, deep_p
)
751 widget_instance
* instance
;
757 unsigned int num_children
;
758 int num_children_to_keep
= 0;
762 children
= XtCompositeChildren (widget
, &num_children
);
764 /* Widget is a RowColumn widget whose contents have to be updated
765 * to reflect the list of items in val->contents */
767 /* See how many buttons we can keep, and how many we
768 must completely replace. */
769 if (val
->contents
== 0)
770 num_children_to_keep
= 0;
771 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
775 for (i
= 0, cur
= val
->contents
;
777 && cur
); /* how else to ditch unwanted children ?? - mgd */
778 i
++, cur
= cur
->next
)
780 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
784 num_children_to_keep
= i
;
788 num_children_to_keep
= num_children
;
790 /* Update all the buttons of the RowColumn, in order,
791 except for those we are going to replace entirely. */
794 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
798 num_children_to_keep
= i
;
801 if (children
[i
]->core
.being_destroyed
802 || strcmp (XtName (children
[i
]), cur
->name
))
804 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
809 /* Now replace from scratch all the buttons after the last
810 place that the top-level structure changed. */
811 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
813 destroy_all_children (widget
, num_children_to_keep
);
814 make_menu_in_widget (instance
, widget
, val
->contents
,
815 num_children_to_keep
);
818 XtFree ((char *) children
);
822 /* update text widgets */
825 xm_update_text (instance
, widget
, val
)
826 widget_instance
* instance
;
830 XmTextSetString (widget
, val
->value
? val
->value
: "");
831 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
832 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
833 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
834 XtAddCallback (widget
, XmNvalueChangedCallback
,
835 xm_internal_update_other_instances
, instance
);
839 xm_update_text_field (instance
, widget
, val
)
840 widget_instance
* instance
;
844 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
845 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
846 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
847 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
848 XtAddCallback (widget
, XmNvalueChangedCallback
,
849 xm_internal_update_other_instances
, instance
);
853 /* update a motif widget */
856 xm_update_one_widget (instance
, widget
, val
, deep_p
)
857 widget_instance
* instance
;
864 /* Mark as not edited */
867 /* Common to all widget types */
868 XtSetSensitive (widget
, val
->enabled
);
869 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
871 /* Common to all label like widgets */
872 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
873 xm_update_label (instance
, widget
, val
);
875 class = XtClass (widget
);
876 /* Class specific things */
877 if (class == xmPushButtonWidgetClass
||
878 class == xmArrowButtonWidgetClass
)
880 xm_update_pushbutton (instance
, widget
, val
);
882 else if (class == xmCascadeButtonWidgetClass
)
884 xm_update_cascadebutton (instance
, widget
, val
);
886 else if (class == xmToggleButtonWidgetClass
887 || class == xmToggleButtonGadgetClass
)
889 xm_update_toggle (instance
, widget
, val
);
891 else if (class == xmRowColumnWidgetClass
)
893 Boolean radiobox
= 0;
897 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
898 XtGetValues (widget
, al
, ac
);
901 xm_update_radiobox (instance
, widget
, val
);
903 xm_update_menu (instance
, widget
, val
, deep_p
);
905 else if (class == xmTextWidgetClass
)
907 xm_update_text (instance
, widget
, val
);
909 else if (class == xmTextFieldWidgetClass
)
911 xm_update_text_field (instance
, widget
, val
);
913 else if (class == xmListWidgetClass
)
915 xm_update_list (instance
, widget
, val
);
919 \f/* getting the value back */
921 xm_update_one_value (instance
, widget
, val
)
922 widget_instance
* instance
;
926 WidgetClass
class = XtClass (widget
);
927 widget_value
*old_wv
;
929 /* copy the call_data slot into the "return" widget_value */
930 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
931 if (!strcmp (val
->name
, old_wv
->name
))
933 val
->call_data
= old_wv
->call_data
;
937 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
939 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
942 else if (class == xmTextWidgetClass
)
946 val
->value
= XmTextGetString (widget
);
949 else if (class == xmTextFieldWidgetClass
)
953 val
->value
= XmTextFieldGetString (widget
);
956 else if (class == xmRowColumnWidgetClass
)
958 Boolean radiobox
= 0;
962 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
963 XtGetValues (widget
, al
, ac
);
967 CompositeWidget radio
= (CompositeWidget
)widget
;
969 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
972 Widget toggle
= radio
->composite
.children
[i
];
974 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
979 val
->value
= safe_strdup (XtName (toggle
));
985 else if (class == xmListWidgetClass
)
989 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
993 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
997 cur
->selected
= False
;
999 for (j
= 0; j
< pos_cnt
; j
++)
1000 if (pos_list
[j
] == i
)
1002 cur
->selected
= True
;
1003 val
->value
= safe_strdup (cur
->name
);
1007 XtFree ((char *) pos_list
);
1013 /* This function is for activating a button from a program. It's wrong because
1014 we pass a NULL argument in the call_data which is not Motif compatible.
1015 This is used from the XmNdefaultAction callback of the List widgets to
1016 have a double-click put down a dialog box like the button would do.
1017 I could not find a way to do that with accelerators.
1020 activate_button (widget
, closure
, call_data
)
1023 XtPointer call_data
;
1025 Widget button
= (Widget
)closure
;
1026 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1029 /* creation functions */
1033 make_dialog (name
, parent
, pop_up_p
, shell_title
, icon_name
, text_input_slot
,
1034 radio_box
, list
, left_buttons
, right_buttons
)
1040 Boolean text_input_slot
;
1050 Widget icon_separator
;
1055 Widget children
[16]; /* for the final XtManageChildren */
1057 Arg al
[64]; /* Arg List */
1058 int ac
; /* Arg Count */
1064 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1065 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1066 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1067 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1069 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1070 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1071 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1072 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1077 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1078 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1079 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1083 n_children
= left_buttons
+ right_buttons
+ 1;
1085 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1086 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1087 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1088 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1089 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1090 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1091 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1092 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1093 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1094 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1095 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1096 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1097 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1098 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1099 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1100 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1101 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1102 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1103 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1106 for (i
= 0; i
< left_buttons
; i
++)
1108 char button_name
[16];
1109 sprintf (button_name
, "button%d", i
+ 1);
1113 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1114 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1116 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1117 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1118 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1122 button
= children
[n_children
];
1124 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1125 XtSetValues (row
, al
, ac
);
1131 /* invisible separator button */
1133 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1134 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1137 for (i
= 0; i
< right_buttons
; i
++)
1139 char button_name
[16];
1140 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1142 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1143 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1144 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1145 if (! button
) button
= children
[n_children
];
1149 XtManageChildren (children
, n_children
);
1152 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1153 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1154 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1155 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1156 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1157 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1158 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1159 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1160 separator
= XmCreateSeparator (form
, "", al
, ac
);
1163 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1164 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1165 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1166 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1167 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1168 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1169 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1170 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1173 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1174 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1175 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1176 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1177 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1178 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1179 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1180 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1181 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1182 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1184 if (text_input_slot
)
1187 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1188 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1189 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1190 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1191 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1192 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1193 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1194 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1195 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1196 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1197 value
= XmCreateTextField (form
, "value", al
, ac
);
1203 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1204 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1205 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1206 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1207 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1208 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1209 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1210 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1211 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1212 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1213 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1214 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1215 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1216 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1219 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1220 children
[i
++] = radio_butt
;
1221 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1222 children
[i
++] = radio_butt
;
1223 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1224 children
[i
++] = radio_butt
;
1225 XtManageChildren (children
, i
);
1230 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1231 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1232 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1233 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1234 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1235 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1236 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1237 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1238 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1239 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1240 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1242 /* this is the easiest way I found to have the dble click in the
1243 list activate the default button */
1244 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1248 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1249 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1250 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1251 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1252 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1253 XtSetArg(al
[ac
], XmNbottomWidget
,
1254 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1255 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1256 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1257 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1258 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1259 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1260 message
= XmCreateLabel (form
, "message", al
, ac
);
1263 XtManageChild (value
);
1266 children
[i
] = row
; i
++;
1267 children
[i
] = separator
; i
++;
1268 if (text_input_slot
|| radio_box
)
1270 children
[i
] = value
; i
++;
1272 children
[i
] = message
; i
++;
1273 children
[i
] = icon
; i
++;
1274 children
[i
] = icon_separator
; i
++;
1275 XtManageChildren (children
, i
);
1277 if (text_input_slot
|| list
)
1279 XtInstallAccelerators (value
, button
);
1280 XtSetKeyboardFocus (result
, value
);
1284 XtInstallAccelerators (form
, button
);
1285 XtSetKeyboardFocus (result
, button
);
1291 static destroyed_instance
*
1292 find_matching_instance (instance
)
1293 widget_instance
* instance
;
1295 destroyed_instance
* cur
;
1296 destroyed_instance
* prev
;
1297 char* type
= instance
->info
->type
;
1298 char* name
= instance
->info
->name
;
1300 for (prev
= NULL
, cur
= all_destroyed_instances
;
1302 prev
= cur
, cur
= cur
->next
)
1304 if (!strcmp (cur
->name
, name
)
1305 && !strcmp (cur
->type
, type
)
1306 && cur
->parent
== instance
->parent
1307 && cur
->pop_up_p
== instance
->pop_up_p
)
1310 prev
->next
= cur
->next
;
1312 all_destroyed_instances
= cur
->next
;
1315 /* do some cleanup */
1316 else if (!cur
->widget
)
1319 prev
->next
= cur
->next
;
1321 all_destroyed_instances
= cur
->next
;
1322 free_destroyed_instance (cur
);
1323 cur
= prev
? prev
: all_destroyed_instances
;
1330 mark_dead_instance_destroyed (widget
, closure
, call_data
)
1333 XtPointer call_data
;
1335 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1336 instance
->widget
= NULL
;
1340 recenter_widget (widget
)
1343 Widget parent
= XtParent (widget
);
1344 Screen
* screen
= XtScreen (widget
);
1345 Dimension screen_width
= WidthOfScreen (screen
);
1346 Dimension screen_height
= HeightOfScreen (screen
);
1347 Dimension parent_width
= 0;
1348 Dimension parent_height
= 0;
1349 Dimension child_width
= 0;
1350 Dimension child_height
= 0;
1354 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1355 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1358 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1359 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1361 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1363 if (x
+ child_width
> screen_width
)
1364 x
= screen_width
- child_width
;
1368 if (y
+ child_height
> screen_height
)
1369 y
= screen_height
- child_height
;
1373 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1377 recycle_instance (instance
)
1378 destroyed_instance
* instance
;
1380 Widget widget
= instance
->widget
;
1382 /* widget is NULL if the parent was destroyed. */
1388 /* Remove the destroy callback as the instance is not in the list
1390 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1391 mark_dead_instance_destroyed
,
1392 (XtPointer
)instance
);
1394 /* Give the focus to the initial item */
1395 focus
= XtNameToWidget (widget
, "*value");
1397 focus
= XtNameToWidget (widget
, "*button1");
1399 XtSetKeyboardFocus (widget
, focus
);
1401 /* shrink the separator label back to their original size */
1402 separator
= XtNameToWidget (widget
, "*separator_button");
1404 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1406 /* Center the dialog in its parent */
1407 recenter_widget (widget
);
1409 free_destroyed_instance (instance
);
1414 xm_create_dialog (instance
)
1415 widget_instance
* instance
;
1417 char* name
= instance
->info
->type
;
1418 Widget parent
= instance
->parent
;
1420 Boolean pop_up_p
= instance
->pop_up_p
;
1421 char* shell_name
= 0;
1422 char* icon_name
= 0;
1423 Boolean text_input_slot
= False
;
1424 Boolean radio_box
= False
;
1425 Boolean list
= False
;
1427 int left_buttons
= 0;
1428 int right_buttons
= 1;
1429 destroyed_instance
* dead_one
;
1431 /* try to find a widget to recycle */
1432 dead_one
= find_matching_instance (instance
);
1435 Widget recycled_widget
= recycle_instance (dead_one
);
1436 if (recycled_widget
)
1437 return recycled_widget
;
1442 icon_name
= "dbox-error";
1443 shell_name
= "Error";
1447 icon_name
= "dbox-info";
1448 shell_name
= "Information";
1453 icon_name
= "dbox-question";
1454 shell_name
= "Prompt";
1458 text_input_slot
= True
;
1459 icon_name
= "dbox-question";
1460 shell_name
= "Prompt";
1464 icon_name
= "dbox-question";
1465 shell_name
= "Question";
1469 total_buttons
= name
[1] - '0';
1471 if (name
[3] == 'T' || name
[3] == 't')
1473 text_input_slot
= False
;
1477 right_buttons
= name
[4] - '0';
1479 left_buttons
= total_buttons
- right_buttons
;
1481 widget
= make_dialog (name
, parent
, pop_up_p
,
1482 shell_name
, icon_name
, text_input_slot
, radio_box
,
1483 list
, left_buttons
, right_buttons
);
1485 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1486 (XtPointer
) instance
);
1490 /* Create a menu bar. We turn off the f10 key
1491 because we have not yet managed to make it work right in Motif. */
1494 make_menubar (instance
)
1495 widget_instance
* instance
;
1501 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1502 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1506 remove_grabs (shell
, closure
, call_data
)
1509 XtPointer call_data
;
1511 Widget menu
= (Widget
) closure
;
1512 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1516 make_popup_menu (instance
)
1517 widget_instance
* instance
;
1519 Widget parent
= instance
->parent
;
1520 Window parent_window
= parent
->core
.window
;
1523 /* sets the parent window to 0 to fool Motif into not generating a grab */
1524 parent
->core
.window
= 0;
1525 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1526 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1528 parent
->core
.window
= parent_window
;
1533 make_main (instance
)
1534 widget_instance
* instance
;
1536 Widget parent
= instance
->parent
;
1542 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1543 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1544 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1548 \f/* Table of functions to create widgets */
1552 /* interface with the XDesigner generated functions */
1553 typedef Widget (*widget_maker
) (Widget
);
1554 extern Widget
create_project_p_sheet (Widget parent
);
1555 extern Widget
create_debugger_p_sheet (Widget parent
);
1556 extern Widget
create_breaklist_p_sheet (Widget parent
);
1557 extern Widget
create_le_browser_p_sheet (Widget parent
);
1558 extern Widget
create_class_browser_p_sheet (Widget parent
);
1559 extern Widget
create_call_browser_p_sheet (Widget parent
);
1560 extern Widget
create_build_dialog (Widget parent
);
1561 extern Widget
create_editmode_dialog (Widget parent
);
1562 extern Widget
create_search_dialog (Widget parent
);
1563 extern Widget
create_project_display_dialog (Widget parent
);
1566 make_one (widget_instance
* instance
, widget_maker fn
)
1572 if (instance
->pop_up_p
)
1574 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1575 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1576 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1577 (XtPointer
) instance
);
1582 result
= (*fn
) (instance
->parent
);
1583 XtRealizeWidget (result
);
1589 make_project_p_sheet (widget_instance
* instance
)
1591 return make_one (instance
, create_project_p_sheet
);
1595 make_debugger_p_sheet (widget_instance
* instance
)
1597 return make_one (instance
, create_debugger_p_sheet
);
1601 make_breaklist_p_sheet (widget_instance
* instance
)
1603 return make_one (instance
, create_breaklist_p_sheet
);
1607 make_le_browser_p_sheet (widget_instance
* instance
)
1609 return make_one (instance
, create_le_browser_p_sheet
);
1613 make_class_browser_p_sheet (widget_instance
* instance
)
1615 return make_one (instance
, create_class_browser_p_sheet
);
1619 make_call_browser_p_sheet (widget_instance
* instance
)
1621 return make_one (instance
, create_call_browser_p_sheet
);
1625 make_build_dialog (widget_instance
* instance
)
1627 return make_one (instance
, create_build_dialog
);
1631 make_editmode_dialog (widget_instance
* instance
)
1633 return make_one (instance
, create_editmode_dialog
);
1637 make_search_dialog (widget_instance
* instance
)
1639 return make_one (instance
, create_search_dialog
);
1643 make_project_display_dialog (widget_instance
* instance
)
1645 return make_one (instance
, create_project_display_dialog
);
1648 #endif /* ENERGIZE */
1650 widget_creation_entry
1651 xm_creation_table
[] =
1653 {"menubar", make_menubar
},
1654 {"popup", make_popup_menu
},
1655 {"main", make_main
},
1657 {"project_p_sheet", make_project_p_sheet
},
1658 {"debugger_p_sheet", make_debugger_p_sheet
},
1659 {"breaklist_psheet", make_breaklist_p_sheet
},
1660 {"leb_psheet", make_le_browser_p_sheet
},
1661 {"class_browser_psheet", make_class_browser_p_sheet
},
1662 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1663 {"build", make_build_dialog
},
1664 {"editmode", make_editmode_dialog
},
1665 {"search", make_search_dialog
},
1666 {"project_display", make_project_display_dialog
},
1667 #endif /* ENERGIZE */
1671 \f/* Destruction of instances */
1673 xm_destroy_instance (instance
)
1674 widget_instance
* instance
;
1676 Widget widget
= instance
->widget
;
1677 /* recycle the dialog boxes */
1678 /* Disable the recycling until we can find a way to have the dialog box
1679 get reasonable layout after we modify its contents. */
1681 && XtClass (widget
) == xmDialogShellWidgetClass
)
1683 destroyed_instance
* dead_instance
=
1684 make_destroyed_instance (instance
->info
->name
,
1685 instance
->info
->type
,
1688 instance
->pop_up_p
);
1689 dead_instance
->next
= all_destroyed_instances
;
1690 all_destroyed_instances
= dead_instance
;
1691 XtUnmanageChild (first_child (instance
->widget
));
1692 XFlush (XtDisplay (instance
->widget
));
1693 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1694 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1698 /* This might not be necessary now that the nosel is attached to
1699 popdown instead of destroy, but it can't hurt. */
1700 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1701 xm_nosel_callback
, (XtPointer
)instance
);
1702 XtDestroyWidget (instance
->widget
);
1706 \f/* popup utility */
1708 xm_popup_menu (widget
, event
)
1712 XButtonPressedEvent dummy
;
1716 dummy
.type
= ButtonPress
;
1718 dummy
.send_event
= 0;
1719 dummy
.display
= XtDisplay (widget
);
1720 dummy
.window
= XtWindow (XtParent (widget
));
1723 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1724 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1725 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1726 event
= (XEvent
*) &dummy
;
1729 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1731 /* Setting the menuPost resource only required by Motif 1.1 and
1732 LessTif 0.84 and earlier. With later versions of LessTif,
1733 setting menuPost is unnecessary and may cause problems, so
1735 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1737 /* This is so totally ridiculous: there's NO WAY to tell Motif
1738 that *any* button can select a menu item. Only one button
1739 can have that honor. */
1742 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1743 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1744 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1745 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1746 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1747 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1751 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1754 XtManageChild (widget
);
1758 set_min_dialog_size (w
)
1763 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1764 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1768 xm_pop_instance (instance
, up
)
1769 widget_instance
* instance
;
1772 Widget widget
= instance
->widget
;
1774 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1776 Widget widget_to_manage
= first_child (widget
);
1779 XtManageChild (widget_to_manage
);
1780 set_min_dialog_size (widget
);
1781 XtSetKeyboardFocus (instance
->parent
, widget
);
1784 XtUnmanageChild (widget_to_manage
);
1789 XtManageChild (widget
);
1791 XtUnmanageChild (widget
);
1796 /* motif callback */
1799 do_call (widget
, closure
, type
)
1802 enum do_call_type type
;
1806 XtPointer user_data
;
1807 widget_instance
* instance
= (widget_instance
*)closure
;
1808 Widget instance_widget
;
1813 if (widget
->core
.being_destroyed
)
1816 instance_widget
= instance
->widget
;
1817 if (!instance_widget
)
1820 id
= instance
->info
->id
;
1823 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1824 XtGetValues (widget
, al
, ac
);
1829 if (instance
->info
->pre_activate_cb
)
1830 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1834 if (instance
->info
->selection_cb
)
1835 instance
->info
->selection_cb (widget
, id
, user_data
);
1839 if (instance
->info
->selection_cb
)
1840 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1844 if (instance
->info
->post_activate_cb
)
1845 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1853 /* Like lw_internal_update_other_instances except that it does not do
1854 anything if its shell parent is not managed. This is to protect
1855 lw_internal_update_other_instances to dereference freed memory
1856 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1859 xm_internal_update_other_instances (widget
, closure
, call_data
)
1862 XtPointer call_data
;
1865 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1866 if (XtIsShell (parent
))
1868 else if (!XtIsManaged (parent
))
1870 lw_internal_update_other_instances (widget
, closure
, call_data
);
1874 xm_generic_callback (widget
, closure
, call_data
)
1877 XtPointer call_data
;
1879 lw_internal_update_other_instances (widget
, closure
, call_data
);
1880 do_call (widget
, closure
, selection
);
1884 xm_nosel_callback (widget
, closure
, call_data
)
1887 XtPointer call_data
;
1889 /* This callback is only called when a dialog box is dismissed with
1890 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1891 box to be destroyed in that case, not just unmapped, so that it
1892 releases its keyboard grabs. But there are problems with running
1893 our callbacks while the widget is in the process of being
1894 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1895 XmDESTROY and then destroy it ourself after having run the
1897 do_call (widget
, closure
, no_selection
);
1898 XtDestroyWidget (widget
);
1902 xm_pull_down_callback (widget
, closure
, call_data
)
1905 XtPointer call_data
;
1907 Widget parent
= XtParent (widget
);
1909 if (XmIsRowColumn (parent
))
1911 unsigned char type
= 0xff;
1912 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1913 if (type
== XmMENU_BAR
)
1914 do_call (widget
, closure
, pre_activate
);
1919 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1920 CLOSURE is a pointer to the widget_instance of the shell,
1922 Note that this callback is called for each cascade button in a
1923 menu, whether or not its submenu is visible. */
1926 xm_pop_down_callback (widget
, closure
, call_data
)
1929 XtPointer call_data
;
1931 widget_instance
*instance
= (widget_instance
*) closure
;
1933 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1934 || XtParent (widget
) == instance
->parent
)
1935 do_call (widget
, closure
, post_activate
);
1939 /* set the keyboard focus */
1941 xm_set_keyboard_focus (parent
, w
)
1945 XmProcessTraversal (w
, 0);
1946 XtSetKeyboardFocus (parent
, w
);
1949 /* Motif hack to set the main window areas. */
1951 xm_set_main_areas (parent
, menubar
, work_area
)
1956 XmMainWindowSetAreas (parent
,
1957 menubar
, /* menubar (maybe 0) */
1958 0, /* command area (psheets) */
1959 0, /* horizontal scroll */
1960 0, /* vertical scroll */
1961 work_area
); /* work area */
1964 /* Motif hack to control resizing on the menubar. */
1966 xm_manage_resizing (w
, flag
)
1970 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);