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>
35 #include "lwlib-utils.h"
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
62 #if defined __STDC__ || defined PROTOTYPES
68 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
79 struct _destroyed_instance
* next
;
82 static destroyed_instance
*make_destroyed_instance
P_ ((char *, char *,
85 static void free_destroyed_instance
P_ ((destroyed_instance
*));
86 Widget first_child
P_ ((Widget
));
87 Boolean lw_motif_widget_p
P_ ((Widget
));
88 static XmString resource_motif_string
P_ ((Widget
, char *));
89 static void destroy_all_children
P_ ((Widget
, int));
90 static void xm_update_label
P_ ((widget_instance
*, Widget
, widget_value
*));
91 static void xm_update_list
P_ ((widget_instance
*, Widget
, widget_value
*));
92 static void xm_update_pushbutton
P_ ((widget_instance
*, Widget
,
94 static void xm_update_cascadebutton
P_ ((widget_instance
*, Widget
,
96 static void xm_update_toggle
P_ ((widget_instance
*, Widget
, widget_value
*));
97 static void xm_update_radiobox
P_ ((widget_instance
*, Widget
, widget_value
*));
98 static void make_menu_in_widget
P_ ((widget_instance
*, Widget
,
99 widget_value
*, int));
100 static void update_one_menu_entry
P_ ((widget_instance
*, Widget
,
101 widget_value
*, Boolean
));
102 static void xm_update_menu
P_ ((widget_instance
*, Widget
, widget_value
*,
104 static void xm_update_text
P_ ((widget_instance
*, Widget
, widget_value
*));
105 static void xm_update_text_field
P_ ((widget_instance
*, Widget
,
107 void xm_update_one_value
P_ ((widget_instance
*, Widget
, widget_value
*));
108 static void activate_button
P_ ((Widget
, XtPointer
, XtPointer
));
109 static Widget make_dialog
P_ ((char *, Widget
, Boolean
, char *, char *,
110 Boolean
, Boolean
, Boolean
, int, int));
111 static destroyed_instance
* find_matching_instance
P_ ((widget_instance
*));
112 static void mark_dead_instance_destroyed
P_ ((Widget
, XtPointer
, XtPointer
));
113 static void recenter_widget
P_ ((Widget
));
114 static Widget recycle_instance
P_ ((destroyed_instance
*));
115 Widget xm_create_dialog
P_ ((widget_instance
*));
116 static Widget make_menubar
P_ ((widget_instance
*));
117 static void remove_grabs
P_ ((Widget
, XtPointer
, XtPointer
));
118 static Widget make_popup_menu
P_ ((widget_instance
*));
119 static Widget make_main
P_ ((widget_instance
*));
120 void xm_destroy_instance
P_ ((widget_instance
*));
121 void xm_popup_menu
P_ ((Widget
, XEvent
*));
122 static void set_min_dialog_size
P_ ((Widget
));
123 static void do_call
P_ ((Widget
, XtPointer
, enum do_call_type
));
124 static void xm_generic_callback
P_ ((Widget
, XtPointer
, XtPointer
));
125 static void xm_nosel_callback
P_ ((Widget
, XtPointer
, XtPointer
));
126 static void xm_pull_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
127 static void xm_pop_down_callback
P_ ((Widget
, XtPointer
, XtPointer
));
128 static void xm_unmap_callback
P_ ((Widget
, XtPointer
, XtPointer
));
129 void xm_set_keyboard_focus
P_ ((Widget
, Widget
));
130 void xm_set_main_areas
P_ ((Widget
, Widget
, Widget
));
131 static void xm_internal_update_other_instances
P_ ((Widget
, XtPointer
,
133 static void xm_arm_callback
P_ ((Widget
, XtPointer
, XtPointer
));
136 void xm_update_one_widget
P_ ((widget_instance
*, Widget
, widget_value
*,
138 void xm_pop_instance
P_ ((widget_instance
*, Boolean
));
139 void xm_manage_resizing
P_ ((Widget
, Boolean
));
143 static destroyed_instance
*all_destroyed_instances
= NULL
;
145 static destroyed_instance
*
146 make_destroyed_instance (name
, type
, widget
, parent
, pop_up_p
)
153 destroyed_instance
* instance
=
154 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
155 instance
->name
= safe_strdup (name
);
156 instance
->type
= safe_strdup (type
);
157 instance
->widget
= widget
;
158 instance
->parent
= parent
;
159 instance
->pop_up_p
= pop_up_p
;
160 instance
->next
= NULL
;
165 free_destroyed_instance (instance
)
166 destroyed_instance
* instance
;
168 free (instance
->name
);
169 free (instance
->type
);
173 \f/* motif utility functions */
178 return ((CompositeWidget
)widget
)->composite
.children
[0];
182 lw_motif_widget_p (widget
)
186 XtClass (widget
) == xmDialogShellWidgetClass
187 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
191 resource_motif_string (widget
, name
)
198 resource
.resource_name
= name
;
199 resource
.resource_class
= XmCXmString
;
200 resource
.resource_type
= XmRXmString
;
201 resource
.resource_size
= sizeof (XmString
);
202 resource
.resource_offset
= 0;
203 resource
.default_type
= XtRImmediate
;
204 resource
.default_addr
= 0;
206 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
207 "DialogString", &resource
, 1, NULL
, 0);
211 /* Destroy all of the children of WIDGET
212 starting with number FIRST_CHILD_TO_DESTROY. */
215 destroy_all_children (widget
, first_child_to_destroy
)
217 int first_child_to_destroy
;
223 children
= XtCompositeChildren (widget
, &number
);
226 XtUnmanageChildren (children
+ first_child_to_destroy
,
227 number
- first_child_to_destroy
);
229 /* Unmanage all children and destroy them. They will only be
230 really destroyed when we get out of DispatchEvent. */
231 for (i
= first_child_to_destroy
; i
< number
; i
++)
235 /* Cascade buttons have submenus,and these submenus
236 need to be freed. But they are not included in
237 XtCompositeChildren. So get it out of the cascade button
238 and free it. If this child is not a cascade button,
239 then submenu should remain unchanged. */
240 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
241 XtGetValues (children
[i
], al
, 1);
243 XtDestroyWidget (submenu
);
244 XtDestroyWidget (children
[i
]);
247 XtFree ((char *) children
);
253 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
254 menu. CLIENT_DATA contains a pointer to the widget_value
255 corresponding to widget W. CALL_DATA contains a
256 XmPushButtonCallbackStruct containing the reason why the callback
260 xm_arm_callback (w
, client_data
, call_data
)
262 XtPointer client_data
, call_data
;
264 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
265 widget_value
*wv
= (widget_value
*) client_data
;
266 widget_instance
*instance
;
268 /* Get the id of the menu bar or popup menu this widget is in. */
271 if (XmIsRowColumn (w
))
273 unsigned char type
= 0xff;
275 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
276 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
285 instance
= lw_get_widget_instance (w
);
286 if (instance
&& instance
->info
->highlight_cb
)
288 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
289 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
296 /* Update the label of widget WIDGET. WIDGET must be a Label widget
297 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
302 Emacs fills VAL->name with the text to display in the menu, and
303 sets VAL->value to null. Function make_menu_in_widget creates
304 widgets with VAL->name as resource name. This works because the
305 Label widget uses its resource name for display if no
306 XmNlabelString is set.
310 VAL->name is again set to the resource name, but VAL->value is
311 not null, and contains the label string to display. */
314 xm_update_label (instance
, widget
, val
)
315 widget_instance
* instance
;
319 XmString res_string
= 0;
320 XmString built_string
= 0;
321 XmString key_string
= 0;
329 /* A label string is specified, i.e. we are in a dialog. First
330 see if it is overridden by something from the resource file. */
331 res_string
= resource_motif_string (widget
, val
->value
);
335 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
340 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
341 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
344 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
349 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
350 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
354 XtSetValues (widget
, al
, ac
);
357 XmStringFree (built_string
);
360 XmStringFree (key_string
);
363 \f/* update of list */
365 xm_update_list (instance
, widget
, val
)
366 widget_instance
* instance
;
372 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
373 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
375 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
378 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
380 XmListAddItem (widget
, xmstr
, 0);
382 XmListSelectPos (widget
, i
, False
);
383 XmStringFree (xmstr
);
387 \f/* update of buttons */
389 xm_update_pushbutton (instance
, widget
, val
)
390 widget_instance
* instance
;
394 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
395 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
396 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
400 xm_update_cascadebutton (instance
, widget
, val
)
401 widget_instance
* instance
;
405 /* Should also rebuild the menu by calling ...update_menu... */
406 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
407 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
411 \f/* update toggle and radiobox */
413 xm_update_toggle (instance
, widget
, val
)
414 widget_instance
* instance
;
418 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
419 XtAddCallback (widget
, XmNvalueChangedCallback
,
420 xm_generic_callback
, instance
);
421 XtVaSetValues (widget
, XmNset
, val
->selected
,
422 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
426 xm_update_radiobox (instance
, widget
, val
)
427 widget_instance
* instance
;
435 /* update the callback */
436 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
437 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
439 /* first update all the toggles */
440 /* Energize kernel interface is currently bad. It sets the selected widget
441 with the selected flag but returns it by its name. So we currently
442 have to support both setting the selection with the selected slot
443 of val contents and setting it with the "value" slot of val. The latter
444 has a higher priority. This to be removed when the kernel is fixed. */
445 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
447 toggle
= XtNameToWidget (widget
, cur
->value
);
450 XtVaSetValues (toggle
, XmNsensitive
, cur
->enabled
, NULL
);
451 if (!val
->value
&& cur
->selected
)
452 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
453 if (val
->value
&& strcmp (val
->value
, cur
->value
))
454 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
458 /* The selected was specified by the value slot */
461 toggle
= XtNameToWidget (widget
, val
->value
);
463 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
468 /* update a popup menu, pulldown menu or a menubar */
470 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
473 make_menu_in_widget (instance
, widget
, val
, keep_first_children
)
474 widget_instance
* instance
;
477 int keep_first_children
;
479 Widget
* children
= 0;
491 Widget
* old_children
;
492 unsigned int old_num_children
;
494 old_children
= XtCompositeChildren (widget
, &old_num_children
);
496 /* Allocate the children array */
497 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
);
498 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
500 /* WIDGET should be a RowColumn. */
501 if (!XmIsRowColumn (widget
))
504 /* Determine whether WIDGET is a menu bar. */
506 XtSetArg (al
[0], XmNrowColumnType
, &type
);
507 XtGetValues (widget
, al
, 1);
508 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
510 menubar_p
= type
== XmMENU_BAR
;
512 #if 0 /* This can't be used in LessTif as of 2000-01-24 because it's
513 impossible to decide from this plus the cascading callback if a
514 popup is still posted or not. When selecting cascade button A,
515 then B, then clicking on the frame, the sequence of callbacks is
516 `cascading A', cascading B', `popdown for all cascade buttons in
518 /* Add a callback to popups and pulldowns that is called when
519 it is made invisible again. */
521 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
522 xm_pop_down_callback
, (XtPointer
)instance
);
525 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
526 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
527 child_index
++, cur
= cur
->next
)
528 children
[child_index
] = old_children
[child_index
];
530 /* Check that those are all we have
531 (the caller should have deleted the rest). */
532 if (old_num_children
!= keep_first_children
)
535 /* Create the rest. */
536 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
538 enum menu_separator separator
;
541 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
542 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
543 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
545 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
546 && !lw_separator_p (cur
->name
, &separator
, 1))
549 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
550 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
552 else if (lw_separator_p (cur
->name
, &separator
, 1))
555 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
556 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
558 else if (!cur
->contents
)
561 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
562 else if (!cur
->call_data
)
563 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
564 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
565 || cur
->button_type
== BUTTON_TYPE_RADIO
)
567 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
568 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
569 XtSetArg (al
[ac
], XmNindicatorType
,
570 (cur
->button_type
== BUTTON_TYPE_TOGGLE
571 ? XmN_OF_MANY
: XmONE_OF_MANY
));
573 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
574 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
575 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
579 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
580 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
581 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
584 xm_update_label (instance
, button
, cur
);
586 /* Add a callback that is called when the button is
587 selected. Toggle buttons don't support
588 XmNactivateCallback, we use XmNvalueChangedCallback in
589 that case. Don't add a callback to a simple label. */
590 if (cur
->button_type
)
591 xm_update_toggle (instance
, button
, cur
);
592 else if (cur
->call_data
)
593 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
594 (XtPointer
)instance
);
598 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
600 /* XmNpopdownCallback is working strangely under LessTif.
601 Using XmNunmapCallback is the only way to go there. */
603 XtAddCallback (menu
, XmNunmapCallback
, xm_unmap_callback
,
604 (XtPointer
) instance
);
606 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
607 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
608 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
610 xm_update_label (instance
, button
, cur
);
612 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
613 (XtPointer
)instance
);
616 children
[child_index
] = button
;
619 /* Last entry is the help button. The original comment read "Has to
620 be done after managing the buttons otherwise the menubar is only
621 4 pixels high." This is no longer true, and to make
622 XmNmenuHelpWidget work, we need to set it before managing the
623 children.. --gerd. */
625 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
627 /* LessTif apparently doesn't recompute centered text when more
628 widgets are added. So, do it after all widgets have been
631 XtVaSetValues (title
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
634 XtManageChildren (children
, num_children
);
636 XtFree ((char *) children
);
638 XtFree ((char *) old_children
);
642 update_one_menu_entry (instance
, widget
, val
, deep_p
)
643 widget_instance
* instance
;
651 widget_value
* contents
;
653 if (val
->this_one_change
== NO_CHANGE
)
656 /* update the sensitivity and userdata */
657 /* Common to all widget types */
658 XtVaSetValues (widget
,
659 XmNsensitive
, val
->enabled
,
660 XmNuserData
, val
->call_data
,
663 /* update the menu button as a label. */
664 if (val
->this_one_change
>= VISIBLE_CHANGE
)
666 xm_update_label (instance
, widget
, val
);
667 if (val
->button_type
)
668 xm_update_toggle (instance
, widget
, val
);
671 /* update the pulldown/pullaside as needed */
674 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
675 XtGetValues (widget
, al
, ac
);
677 contents
= val
->contents
;
683 unsigned int old_num_children
, i
;
687 parent
= XtParent (widget
);
688 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
690 /* Find the widget position within the parent's widget list. */
691 for (i
= 0; i
< old_num_children
; i
++)
692 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
694 if (i
== old_num_children
)
696 if (XmIsCascadeButton (widget_list
[i
]))
698 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
699 make_menu_in_widget (instance
, menu
, contents
, 0);
701 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
702 XtSetValues (widget
, al
, ac
);
708 /* The current menuitem is a XmPushButtonGadget, it
709 needs to be replaced by a CascadeButtonGadget */
710 XtDestroyWidget (widget_list
[i
]);
711 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
712 make_menu_in_widget (instance
, menu
, contents
, 0);
714 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
715 /* Non-zero values don't work reliably in
716 conjunction with Emacs' event loop */
717 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
718 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
719 /* Tell Motif to put it in the right place */
720 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
722 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
723 xm_update_label (instance
, button
, val
);
725 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
726 (XtPointer
)instance
);
727 XtManageChild (button
);
734 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
735 XtSetValues (widget
, al
, ac
);
736 XtDestroyWidget (menu
);
738 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
739 xm_update_menu (instance
, menu
, val
, 1);
743 xm_update_menu (instance
, widget
, val
, deep_p
)
744 widget_instance
* instance
;
750 unsigned int num_children
;
751 int num_children_to_keep
= 0;
755 children
= XtCompositeChildren (widget
, &num_children
);
757 /* Widget is a RowColumn widget whose contents have to be updated
758 * to reflect the list of items in val->contents */
760 /* See how many buttons we can keep, and how many we
761 must completely replace. */
762 if (val
->contents
== 0)
763 num_children_to_keep
= 0;
764 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
768 for (i
= 0, cur
= val
->contents
;
770 && cur
); /* how else to ditch unwanted children ?? - mgd */
771 i
++, cur
= cur
->next
)
773 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
777 num_children_to_keep
= i
;
781 num_children_to_keep
= num_children
;
783 /* Update all the buttons of the RowColumn, in order,
784 except for those we are going to replace entirely. */
787 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
791 num_children_to_keep
= i
;
794 if (children
[i
]->core
.being_destroyed
795 || strcmp (XtName (children
[i
]), cur
->name
))
797 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
802 /* Now replace from scratch all the buttons after the last
803 place that the top-level structure changed. */
804 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
806 destroy_all_children (widget
, num_children_to_keep
);
807 make_menu_in_widget (instance
, widget
, val
->contents
,
808 num_children_to_keep
);
811 XtFree ((char *) children
);
815 /* update text widgets */
818 xm_update_text (instance
, widget
, val
)
819 widget_instance
* instance
;
823 XmTextSetString (widget
, val
->value
? val
->value
: "");
824 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
825 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
826 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
827 XtAddCallback (widget
, XmNvalueChangedCallback
,
828 xm_internal_update_other_instances
, instance
);
832 xm_update_text_field (instance
, widget
, val
)
833 widget_instance
* instance
;
837 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
838 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
839 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
840 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
841 XtAddCallback (widget
, XmNvalueChangedCallback
,
842 xm_internal_update_other_instances
, instance
);
846 /* update a motif widget */
849 xm_update_one_widget (instance
, widget
, val
, deep_p
)
850 widget_instance
* instance
;
857 /* Mark as not edited */
860 /* Common to all widget types */
861 XtVaSetValues (widget
,
862 XmNsensitive
, val
->enabled
,
863 XmNuserData
, val
->call_data
,
866 /* Common to all label like widgets */
867 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
868 xm_update_label (instance
, widget
, val
);
870 class = XtClass (widget
);
871 /* Class specific things */
872 if (class == xmPushButtonWidgetClass
||
873 class == xmArrowButtonWidgetClass
)
875 xm_update_pushbutton (instance
, widget
, val
);
877 else if (class == xmCascadeButtonWidgetClass
)
879 xm_update_cascadebutton (instance
, widget
, val
);
881 else if (class == xmToggleButtonWidgetClass
882 || class == xmToggleButtonGadgetClass
)
884 xm_update_toggle (instance
, widget
, val
);
886 else if (class == xmRowColumnWidgetClass
)
888 Boolean radiobox
= 0;
892 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
893 XtGetValues (widget
, al
, ac
);
896 xm_update_radiobox (instance
, widget
, val
);
898 xm_update_menu (instance
, widget
, val
, deep_p
);
900 else if (class == xmTextWidgetClass
)
902 xm_update_text (instance
, widget
, val
);
904 else if (class == xmTextFieldWidgetClass
)
906 xm_update_text_field (instance
, widget
, val
);
908 else if (class == xmListWidgetClass
)
910 xm_update_list (instance
, widget
, val
);
914 \f/* getting the value back */
916 xm_update_one_value (instance
, widget
, val
)
917 widget_instance
* instance
;
921 WidgetClass
class = XtClass (widget
);
922 widget_value
*old_wv
;
924 /* copy the call_data slot into the "return" widget_value */
925 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
926 if (!strcmp (val
->name
, old_wv
->name
))
928 val
->call_data
= old_wv
->call_data
;
932 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
934 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
937 else if (class == xmTextWidgetClass
)
941 val
->value
= XmTextGetString (widget
);
944 else if (class == xmTextFieldWidgetClass
)
948 val
->value
= XmTextFieldGetString (widget
);
951 else if (class == xmRowColumnWidgetClass
)
953 Boolean radiobox
= 0;
957 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
958 XtGetValues (widget
, al
, ac
);
962 CompositeWidget radio
= (CompositeWidget
)widget
;
964 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
967 Widget toggle
= radio
->composite
.children
[i
];
969 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
974 val
->value
= safe_strdup (XtName (toggle
));
980 else if (class == xmListWidgetClass
)
984 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
988 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
992 cur
->selected
= False
;
994 for (j
= 0; j
< pos_cnt
; j
++)
995 if (pos_list
[j
] == i
)
997 cur
->selected
= True
;
998 val
->value
= safe_strdup (cur
->name
);
1002 XtFree ((char *) pos_list
);
1008 /* This function is for activating a button from a program. It's wrong because
1009 we pass a NULL argument in the call_data which is not Motif compatible.
1010 This is used from the XmNdefaultAction callback of the List widgets to
1011 have a double-click put down a dialog box like the button would do.
1012 I could not find a way to do that with accelerators.
1015 activate_button (widget
, closure
, call_data
)
1018 XtPointer call_data
;
1020 Widget button
= (Widget
)closure
;
1021 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1024 /* creation functions */
1028 make_dialog (name
, parent
, pop_up_p
, shell_title
, icon_name
, text_input_slot
,
1029 radio_box
, list
, left_buttons
, right_buttons
)
1035 Boolean text_input_slot
;
1045 Widget icon_separator
;
1050 Widget children
[16]; /* for the final XtManageChildren */
1052 Arg al
[64]; /* Arg List */
1053 int ac
; /* Arg Count */
1059 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1060 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1061 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1062 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1064 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1065 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1066 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1067 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1072 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1073 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1074 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1078 n_children
= left_buttons
+ right_buttons
+ 1;
1080 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1081 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1082 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1083 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1084 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1085 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1086 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1087 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1088 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1089 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1090 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1091 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1092 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1093 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1094 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1095 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1096 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1097 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1098 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1101 for (i
= 0; i
< left_buttons
; i
++)
1103 char button_name
[16];
1104 sprintf (button_name
, "button%d", i
+ 1);
1108 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1109 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1111 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1112 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1113 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1117 button
= children
[n_children
];
1119 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1120 XtSetValues (row
, al
, ac
);
1126 /* invisible separator button */
1128 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1129 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1132 for (i
= 0; i
< right_buttons
; i
++)
1134 char button_name
[16];
1135 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1137 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1138 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1139 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1140 if (! button
) button
= children
[n_children
];
1144 XtManageChildren (children
, n_children
);
1147 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1148 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1149 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1150 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1151 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1152 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1153 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1154 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1155 separator
= XmCreateSeparator (form
, "", al
, ac
);
1158 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1159 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1160 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1161 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1162 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1163 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1164 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1165 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1168 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1169 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1170 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1171 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1172 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1173 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1174 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1175 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1176 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1177 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1179 if (text_input_slot
)
1182 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1183 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1184 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1185 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1186 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1187 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1188 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1189 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1190 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1191 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1192 value
= XmCreateTextField (form
, "value", al
, ac
);
1198 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1199 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1200 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1201 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1202 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1203 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1204 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1205 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1206 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1207 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1208 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1209 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1210 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1211 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1214 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1215 children
[i
++] = radio_butt
;
1216 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1217 children
[i
++] = radio_butt
;
1218 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1219 children
[i
++] = radio_butt
;
1220 XtManageChildren (children
, i
);
1225 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1226 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1227 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1228 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1229 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1230 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1231 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1232 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1233 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1234 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1235 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1237 /* this is the easiest way I found to have the dble click in the
1238 list activate the default button */
1239 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1243 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1244 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1245 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1246 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1247 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1248 XtSetArg(al
[ac
], XmNbottomWidget
,
1249 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1250 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1251 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1252 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1253 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1254 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1255 message
= XmCreateLabel (form
, "message", al
, ac
);
1258 XtManageChild (value
);
1261 children
[i
] = row
; i
++;
1262 children
[i
] = separator
; i
++;
1263 if (text_input_slot
|| radio_box
)
1265 children
[i
] = value
; i
++;
1267 children
[i
] = message
; i
++;
1268 children
[i
] = icon
; i
++;
1269 children
[i
] = icon_separator
; i
++;
1270 XtManageChildren (children
, i
);
1272 if (text_input_slot
|| list
)
1274 XtInstallAccelerators (value
, button
);
1275 XtSetKeyboardFocus (result
, value
);
1279 XtInstallAccelerators (form
, button
);
1280 XtSetKeyboardFocus (result
, button
);
1286 static destroyed_instance
*
1287 find_matching_instance (instance
)
1288 widget_instance
* instance
;
1290 destroyed_instance
* cur
;
1291 destroyed_instance
* prev
;
1292 char* type
= instance
->info
->type
;
1293 char* name
= instance
->info
->name
;
1295 for (prev
= NULL
, cur
= all_destroyed_instances
;
1297 prev
= cur
, cur
= cur
->next
)
1299 if (!strcmp (cur
->name
, name
)
1300 && !strcmp (cur
->type
, type
)
1301 && cur
->parent
== instance
->parent
1302 && cur
->pop_up_p
== instance
->pop_up_p
)
1305 prev
->next
= cur
->next
;
1307 all_destroyed_instances
= cur
->next
;
1310 /* do some cleanup */
1311 else if (!cur
->widget
)
1314 prev
->next
= cur
->next
;
1316 all_destroyed_instances
= cur
->next
;
1317 free_destroyed_instance (cur
);
1318 cur
= prev
? prev
: all_destroyed_instances
;
1325 mark_dead_instance_destroyed (widget
, closure
, call_data
)
1328 XtPointer call_data
;
1330 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1331 instance
->widget
= NULL
;
1335 recenter_widget (widget
)
1338 Widget parent
= XtParent (widget
);
1339 Screen
* screen
= XtScreen (widget
);
1340 Dimension screen_width
= WidthOfScreen (screen
);
1341 Dimension screen_height
= HeightOfScreen (screen
);
1342 Dimension parent_width
= 0;
1343 Dimension parent_height
= 0;
1344 Dimension child_width
= 0;
1345 Dimension child_height
= 0;
1349 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1350 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1353 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1354 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1356 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1358 if (x
+ child_width
> screen_width
)
1359 x
= screen_width
- child_width
;
1363 if (y
+ child_height
> screen_height
)
1364 y
= screen_height
- child_height
;
1368 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1372 recycle_instance (instance
)
1373 destroyed_instance
* instance
;
1375 Widget widget
= instance
->widget
;
1377 /* widget is NULL if the parent was destroyed. */
1383 /* Remove the destroy callback as the instance is not in the list
1385 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1386 mark_dead_instance_destroyed
,
1387 (XtPointer
)instance
);
1389 /* Give the focus to the initial item */
1390 focus
= XtNameToWidget (widget
, "*value");
1392 focus
= XtNameToWidget (widget
, "*button1");
1394 XtSetKeyboardFocus (widget
, focus
);
1396 /* shrink the separator label back to their original size */
1397 separator
= XtNameToWidget (widget
, "*separator_button");
1399 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1401 /* Center the dialog in its parent */
1402 recenter_widget (widget
);
1404 free_destroyed_instance (instance
);
1409 xm_create_dialog (instance
)
1410 widget_instance
* instance
;
1412 char* name
= instance
->info
->type
;
1413 Widget parent
= instance
->parent
;
1415 Boolean pop_up_p
= instance
->pop_up_p
;
1416 char* shell_name
= 0;
1418 Boolean text_input_slot
= False
;
1419 Boolean radio_box
= False
;
1420 Boolean list
= False
;
1422 int left_buttons
= 0;
1423 int right_buttons
= 1;
1424 destroyed_instance
* dead_one
;
1426 /* try to find a widget to recycle */
1427 dead_one
= find_matching_instance (instance
);
1430 Widget recycled_widget
= recycle_instance (dead_one
);
1431 if (recycled_widget
)
1432 return recycled_widget
;
1437 icon_name
= "dbox-error";
1438 shell_name
= "Error";
1442 icon_name
= "dbox-info";
1443 shell_name
= "Information";
1448 icon_name
= "dbox-question";
1449 shell_name
= "Prompt";
1453 text_input_slot
= True
;
1454 icon_name
= "dbox-question";
1455 shell_name
= "Prompt";
1459 icon_name
= "dbox-question";
1460 shell_name
= "Question";
1464 total_buttons
= name
[1] - '0';
1466 if (name
[3] == 'T' || name
[3] == 't')
1468 text_input_slot
= False
;
1472 right_buttons
= name
[4] - '0';
1474 left_buttons
= total_buttons
- right_buttons
;
1476 widget
= make_dialog (name
, parent
, pop_up_p
,
1477 shell_name
, icon_name
, text_input_slot
, radio_box
,
1478 list
, left_buttons
, right_buttons
);
1480 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1481 (XtPointer
) instance
);
1485 /* Create a menu bar. We turn off the f10 key
1486 because we have not yet managed to make it work right in Motif. */
1489 make_menubar (instance
)
1490 widget_instance
* instance
;
1496 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1499 /* As of 2000-01-17, the LessTif menu bar resizes to height 0 when
1500 all its children are removed, causing an annoying flickering
1501 behavior. Prevent that by not allowing resizing. */
1502 XtSetArg(al
[ac
], XmNresizeHeight
, False
); ++ac
;
1503 XtSetArg(al
[ac
], XmNresizeWidth
, False
); ++ac
;
1506 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1510 remove_grabs (shell
, closure
, call_data
)
1513 XtPointer call_data
;
1515 Widget menu
= (Widget
) closure
;
1516 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1520 make_popup_menu (instance
)
1521 widget_instance
* instance
;
1523 Widget parent
= instance
->parent
;
1524 Window parent_window
= parent
->core
.window
;
1527 /* sets the parent window to 0 to fool Motif into not generating a grab */
1528 parent
->core
.window
= 0;
1529 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1530 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1532 parent
->core
.window
= parent_window
;
1537 make_main (instance
)
1538 widget_instance
* instance
;
1540 Widget parent
= instance
->parent
;
1546 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1547 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1548 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1552 \f/* Table of functions to create widgets */
1556 /* interface with the XDesigner generated functions */
1557 typedef Widget (*widget_maker
) (Widget
);
1558 extern Widget
create_project_p_sheet (Widget parent
);
1559 extern Widget
create_debugger_p_sheet (Widget parent
);
1560 extern Widget
create_breaklist_p_sheet (Widget parent
);
1561 extern Widget
create_le_browser_p_sheet (Widget parent
);
1562 extern Widget
create_class_browser_p_sheet (Widget parent
);
1563 extern Widget
create_call_browser_p_sheet (Widget parent
);
1564 extern Widget
create_build_dialog (Widget parent
);
1565 extern Widget
create_editmode_dialog (Widget parent
);
1566 extern Widget
create_search_dialog (Widget parent
);
1567 extern Widget
create_project_display_dialog (Widget parent
);
1570 make_one (widget_instance
* instance
, widget_maker fn
)
1576 if (instance
->pop_up_p
)
1578 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1579 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1580 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1581 (XtPointer
) instance
);
1586 result
= (*fn
) (instance
->parent
);
1587 XtRealizeWidget (result
);
1593 make_project_p_sheet (widget_instance
* instance
)
1595 return make_one (instance
, create_project_p_sheet
);
1599 make_debugger_p_sheet (widget_instance
* instance
)
1601 return make_one (instance
, create_debugger_p_sheet
);
1605 make_breaklist_p_sheet (widget_instance
* instance
)
1607 return make_one (instance
, create_breaklist_p_sheet
);
1611 make_le_browser_p_sheet (widget_instance
* instance
)
1613 return make_one (instance
, create_le_browser_p_sheet
);
1617 make_class_browser_p_sheet (widget_instance
* instance
)
1619 return make_one (instance
, create_class_browser_p_sheet
);
1623 make_call_browser_p_sheet (widget_instance
* instance
)
1625 return make_one (instance
, create_call_browser_p_sheet
);
1629 make_build_dialog (widget_instance
* instance
)
1631 return make_one (instance
, create_build_dialog
);
1635 make_editmode_dialog (widget_instance
* instance
)
1637 return make_one (instance
, create_editmode_dialog
);
1641 make_search_dialog (widget_instance
* instance
)
1643 return make_one (instance
, create_search_dialog
);
1647 make_project_display_dialog (widget_instance
* instance
)
1649 return make_one (instance
, create_project_display_dialog
);
1652 #endif /* ENERGIZE */
1654 widget_creation_entry
1655 xm_creation_table
[] =
1657 {"menubar", make_menubar
},
1658 {"popup", make_popup_menu
},
1659 {"main", make_main
},
1661 {"project_p_sheet", make_project_p_sheet
},
1662 {"debugger_p_sheet", make_debugger_p_sheet
},
1663 {"breaklist_psheet", make_breaklist_p_sheet
},
1664 {"leb_psheet", make_le_browser_p_sheet
},
1665 {"class_browser_psheet", make_class_browser_p_sheet
},
1666 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1667 {"build", make_build_dialog
},
1668 {"editmode", make_editmode_dialog
},
1669 {"search", make_search_dialog
},
1670 {"project_display", make_project_display_dialog
},
1671 #endif /* ENERGIZE */
1675 \f/* Destruction of instances */
1677 xm_destroy_instance (instance
)
1678 widget_instance
* instance
;
1680 Widget widget
= instance
->widget
;
1681 /* recycle the dialog boxes */
1682 /* Disable the recycling until we can find a way to have the dialog box
1683 get reasonable layout after we modify its contents. */
1685 && XtClass (widget
) == xmDialogShellWidgetClass
)
1687 destroyed_instance
* dead_instance
=
1688 make_destroyed_instance (instance
->info
->name
,
1689 instance
->info
->type
,
1692 instance
->pop_up_p
);
1693 dead_instance
->next
= all_destroyed_instances
;
1694 all_destroyed_instances
= dead_instance
;
1695 XtUnmanageChild (first_child (instance
->widget
));
1696 XFlush (XtDisplay (instance
->widget
));
1697 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1698 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1702 /* This might not be necessary now that the nosel is attached to
1703 popdown instead of destroy, but it can't hurt. */
1704 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1705 xm_nosel_callback
, (XtPointer
)instance
);
1706 XtDestroyWidget (instance
->widget
);
1710 \f/* popup utility */
1712 xm_popup_menu (widget
, event
)
1716 XButtonPressedEvent dummy
;
1720 dummy
.type
= ButtonPress
;
1722 dummy
.send_event
= 0;
1723 dummy
.display
= XtDisplay (widget
);
1724 dummy
.window
= XtWindow (XtParent (widget
));
1727 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1728 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1729 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1730 event
= (XEvent
*) &dummy
;
1733 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1735 /* This is so totally ridiculous: there's NO WAY to tell Motif
1736 that *any* button can select a menu item. Only one button
1737 can have that honor.
1740 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1741 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1742 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1743 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1744 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1745 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1746 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1748 XtManageChild (widget
);
1752 set_min_dialog_size (w
)
1757 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1758 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1762 xm_pop_instance (instance
, up
)
1763 widget_instance
* instance
;
1766 Widget widget
= instance
->widget
;
1768 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1770 Widget widget_to_manage
= first_child (widget
);
1773 XtManageChild (widget_to_manage
);
1774 set_min_dialog_size (widget
);
1775 XtSetKeyboardFocus (instance
->parent
, widget
);
1778 XtUnmanageChild (widget_to_manage
);
1783 XtManageChild (widget
);
1785 XtUnmanageChild (widget
);
1790 /* motif callback */
1793 do_call (widget
, closure
, type
)
1796 enum do_call_type type
;
1800 XtPointer user_data
;
1801 widget_instance
* instance
= (widget_instance
*)closure
;
1802 Widget instance_widget
;
1807 if (widget
->core
.being_destroyed
)
1810 instance_widget
= instance
->widget
;
1811 if (!instance_widget
)
1814 id
= instance
->info
->id
;
1817 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1818 XtGetValues (widget
, al
, ac
);
1822 if (instance
->info
->pre_activate_cb
)
1823 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1826 if (instance
->info
->selection_cb
)
1827 instance
->info
->selection_cb (widget
, id
, user_data
);
1830 if (instance
->info
->selection_cb
)
1831 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1834 if (instance
->info
->post_activate_cb
)
1835 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1842 /* Like lw_internal_update_other_instances except that it does not do
1843 anything if its shell parent is not managed. This is to protect
1844 lw_internal_update_other_instances to dereference freed memory
1845 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1848 xm_internal_update_other_instances (widget
, closure
, call_data
)
1851 XtPointer call_data
;
1854 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1855 if (XtIsShell (parent
))
1857 else if (!XtIsManaged (parent
))
1859 lw_internal_update_other_instances (widget
, closure
, call_data
);
1863 xm_generic_callback (widget
, closure
, call_data
)
1866 XtPointer call_data
;
1868 lw_internal_update_other_instances (widget
, closure
, call_data
);
1869 do_call (widget
, closure
, selection
);
1873 xm_nosel_callback (widget
, closure
, call_data
)
1876 XtPointer call_data
;
1878 /* This callback is only called when a dialog box is dismissed with the wm's
1879 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1880 in that case, not just unmapped, so that it releases its keyboard grabs.
1881 But there are problems with running our callbacks while the widget is in
1882 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1883 instead of XmDESTROY and then destroy it ourself after having run the
1886 do_call (widget
, closure
, no_selection
);
1887 XtDestroyWidget (widget
);
1891 xm_pull_down_callback (widget
, closure
, call_data
)
1894 XtPointer call_data
;
1896 Widget parent
= XtParent (widget
);
1898 if (XmIsRowColumn (parent
))
1900 unsigned char type
= 0xff;
1901 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1902 if (type
== XmMENU_BAR
)
1903 do_call (widget
, closure
, pre_activate
);
1908 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1909 CLOSURE is a pointer to the widget_instance of the shell, CALL_DATA
1910 is always null under LessTif.
1912 2000-01-23: This callback is called for each cascade button in
1913 a menu, whether or not its submenu is visible. */
1916 xm_pop_down_callback (widget
, closure
, call_data
)
1919 XtPointer call_data
;
1921 widget_instance
*instance
= (widget_instance
*) closure
;
1923 if ((!instance
->pop_up_p
&& (XtParent (widget
) == instance
->widget
))
1924 || (XtParent (widget
) == instance
->parent
))
1925 do_call (widget
, closure
, post_activate
);
1929 xm_unmap_callback (widget
, closure
, call_data
)
1932 XtPointer call_data
;
1934 widget_instance
*instance
= (widget_instance
*) closure
;
1935 if (!instance
->pop_up_p
)
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
);