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 void xm_set_keyboard_focus
P_ ((Widget
, Widget
));
129 void xm_set_main_areas
P_ ((Widget
, Widget
, Widget
));
130 static void xm_internal_update_other_instances
P_ ((Widget
, XtPointer
,
132 static void xm_arm_callback
P_ ((Widget
, XtPointer
, XtPointer
));
135 void xm_update_one_widget
P_ ((widget_instance
*, Widget
, widget_value
*,
137 void xm_pop_instance
P_ ((widget_instance
*, Boolean
));
138 void xm_manage_resizing
P_ ((Widget
, Boolean
));
144 /* Print the complete X resource name of widget WIDGET to stderr.
145 This is sometimes handy to have available. */
148 x_print_complete_resource_name (widget
)
154 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
156 names
[i
] = XtName (widget
);
157 widget
= XtParent (widget
);
160 for (--i
; i
>= 1; --i
)
161 fprintf (stderr
, "%s.", names
[i
]);
162 fprintf (stderr
, "%s\n", names
[0]);
168 static destroyed_instance
*all_destroyed_instances
= NULL
;
170 static destroyed_instance
*
171 make_destroyed_instance (name
, type
, widget
, parent
, pop_up_p
)
178 destroyed_instance
* instance
=
179 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
180 instance
->name
= safe_strdup (name
);
181 instance
->type
= safe_strdup (type
);
182 instance
->widget
= widget
;
183 instance
->parent
= parent
;
184 instance
->pop_up_p
= pop_up_p
;
185 instance
->next
= NULL
;
190 free_destroyed_instance (instance
)
191 destroyed_instance
* instance
;
193 free (instance
->name
);
194 free (instance
->type
);
198 \f/* motif utility functions */
203 return ((CompositeWidget
)widget
)->composite
.children
[0];
207 lw_motif_widget_p (widget
)
211 XtClass (widget
) == xmDialogShellWidgetClass
212 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
216 resource_motif_string (widget
, name
)
223 resource
.resource_name
= name
;
224 resource
.resource_class
= XmCXmString
;
225 resource
.resource_type
= XmRXmString
;
226 resource
.resource_size
= sizeof (XmString
);
227 resource
.resource_offset
= 0;
228 resource
.default_type
= XtRImmediate
;
229 resource
.default_addr
= 0;
231 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
232 "DialogString", &resource
, 1, NULL
, 0);
236 /* Destroy all of the children of WIDGET
237 starting with number FIRST_CHILD_TO_DESTROY. */
240 destroy_all_children (widget
, first_child_to_destroy
)
242 int first_child_to_destroy
;
248 children
= XtCompositeChildren (widget
, &number
);
251 XtUnmanageChildren (children
+ first_child_to_destroy
,
252 number
- first_child_to_destroy
);
254 /* Unmanage all children and destroy them. They will only be
255 really destroyed when we get out of DispatchEvent. */
256 for (i
= first_child_to_destroy
; i
< number
; i
++)
260 /* Cascade buttons have submenus,and these submenus
261 need to be freed. But they are not included in
262 XtCompositeChildren. So get it out of the cascade button
263 and free it. If this child is not a cascade button,
264 then submenu should remain unchanged. */
265 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
266 XtGetValues (children
[i
], al
, 1);
268 XtDestroyWidget (submenu
);
269 XtDestroyWidget (children
[i
]);
272 XtFree ((char *) children
);
278 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
279 menu. CLIENT_DATA contains a pointer to the widget_value
280 corresponding to widget W. CALL_DATA contains a
281 XmPushButtonCallbackStruct containing the reason why the callback
285 xm_arm_callback (w
, client_data
, call_data
)
287 XtPointer client_data
, call_data
;
289 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
290 widget_value
*wv
= (widget_value
*) client_data
;
291 widget_instance
*instance
;
293 /* Get the id of the menu bar or popup menu this widget is in. */
296 if (XmIsRowColumn (w
))
298 unsigned char type
= 0xff;
300 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
301 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
310 instance
= lw_get_widget_instance (w
);
311 if (instance
&& instance
->info
->highlight_cb
)
313 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
314 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
321 /* Update the label of widget WIDGET. WIDGET must be a Label widget
322 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
327 Emacs fills VAL->name with the text to display in the menu, and
328 sets VAL->value to null. Function make_menu_in_widget creates
329 widgets with VAL->name as resource name. This works because the
330 Label widget uses its resource name for display if no
331 XmNlabelString is set.
335 VAL->name is again set to the resource name, but VAL->value is
336 not null, and contains the label string to display. */
339 xm_update_label (instance
, widget
, val
)
340 widget_instance
* instance
;
344 XmString res_string
= 0;
345 XmString built_string
= 0;
346 XmString key_string
= 0;
354 /* A label string is specified, i.e. we are in a dialog. First
355 see if it is overridden by something from the resource file. */
356 res_string
= resource_motif_string (widget
, val
->value
);
360 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
365 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
366 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
369 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
374 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
375 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
379 XtSetValues (widget
, al
, ac
);
382 XmStringFree (built_string
);
385 XmStringFree (key_string
);
388 \f/* update of list */
390 xm_update_list (instance
, widget
, val
)
391 widget_instance
* instance
;
397 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
398 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
400 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
403 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
405 XmListAddItem (widget
, xmstr
, 0);
407 XmListSelectPos (widget
, i
, False
);
408 XmStringFree (xmstr
);
412 \f/* update of buttons */
414 xm_update_pushbutton (instance
, widget
, val
)
415 widget_instance
* instance
;
419 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
420 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
421 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
425 xm_update_cascadebutton (instance
, widget
, val
)
426 widget_instance
* instance
;
430 /* Should also rebuild the menu by calling ...update_menu... */
431 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
432 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
436 \f/* update toggle and radiobox */
438 xm_update_toggle (instance
, widget
, val
)
439 widget_instance
* instance
;
443 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
444 XtAddCallback (widget
, XmNvalueChangedCallback
,
445 xm_generic_callback
, instance
);
446 XtVaSetValues (widget
, XmNset
, val
->selected
,
447 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
451 xm_update_radiobox (instance
, widget
, val
)
452 widget_instance
* instance
;
460 /* update the callback */
461 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
462 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
464 /* first update all the toggles */
465 /* Energize kernel interface is currently bad. It sets the selected widget
466 with the selected flag but returns it by its name. So we currently
467 have to support both setting the selection with the selected slot
468 of val contents and setting it with the "value" slot of val. The latter
469 has a higher priority. This to be removed when the kernel is fixed. */
470 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
472 toggle
= XtNameToWidget (widget
, cur
->value
);
475 XtSetSensitive (toggle
, cur
->enabled
);
476 if (!val
->value
&& cur
->selected
)
477 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
478 if (val
->value
&& strcmp (val
->value
, cur
->value
))
479 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
483 /* The selected was specified by the value slot */
486 toggle
= XtNameToWidget (widget
, val
->value
);
488 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
493 /* update a popup menu, pulldown menu or a menubar */
495 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
498 make_menu_in_widget (instance
, widget
, val
, keep_first_children
)
499 widget_instance
* instance
;
502 int keep_first_children
;
504 Widget
* children
= 0;
516 Widget
* old_children
;
517 unsigned int old_num_children
;
519 old_children
= XtCompositeChildren (widget
, &old_num_children
);
521 /* Allocate the children array */
522 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
524 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
526 /* WIDGET should be a RowColumn. */
527 if (!XmIsRowColumn (widget
))
530 /* Determine whether WIDGET is a menu bar. */
532 XtSetArg (al
[0], XmNrowColumnType
, &type
);
533 XtGetValues (widget
, al
, 1);
534 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
536 menubar_p
= type
== XmMENU_BAR
;
538 /* Add a callback to popups and pulldowns that is called when
539 it is made invisible again. */
541 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
542 xm_pop_down_callback
, (XtPointer
)instance
);
544 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
545 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
546 child_index
++, cur
= cur
->next
)
547 children
[child_index
] = old_children
[child_index
];
549 /* Check that those are all we have
550 (the caller should have deleted the rest). */
551 if (old_num_children
!= keep_first_children
)
554 /* Create the rest. */
555 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
557 enum menu_separator separator
;
560 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
561 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
562 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
564 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
565 && !lw_separator_p (cur
->name
, &separator
, 1))
568 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
569 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
571 else if (lw_separator_p (cur
->name
, &separator
, 1))
574 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
575 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
577 else if (!cur
->contents
)
580 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
581 else if (!cur
->call_data
)
582 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
583 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
584 || cur
->button_type
== BUTTON_TYPE_RADIO
)
586 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
587 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
588 XtSetArg (al
[ac
], XmNindicatorType
,
589 (cur
->button_type
== BUTTON_TYPE_TOGGLE
590 ? XmN_OF_MANY
: XmONE_OF_MANY
));
592 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
593 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
594 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
598 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
599 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
600 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
603 xm_update_label (instance
, button
, cur
);
605 /* Add a callback that is called when the button is
606 selected. Toggle buttons don't support
607 XmNactivateCallback, we use XmNvalueChangedCallback in
608 that case. Don't add a callback to a simple label. */
609 if (cur
->button_type
)
610 xm_update_toggle (instance
, button
, cur
);
611 else if (cur
->call_data
)
612 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
613 (XtPointer
)instance
);
617 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
619 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
620 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
621 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
623 xm_update_label (instance
, button
, cur
);
625 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
626 (XtPointer
)instance
);
629 children
[child_index
] = button
;
632 /* Last entry is the help button. The original comment read "Has to
633 be done after managing the buttons otherwise the menubar is only
634 4 pixels high." This is no longer true, and to make
635 XmNmenuHelpWidget work, we need to set it before managing the
636 children.. --gerd. */
638 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
641 XtManageChildren (children
, num_children
);
643 XtFree ((char *) children
);
645 XtFree ((char *) old_children
);
649 update_one_menu_entry (instance
, widget
, val
, deep_p
)
650 widget_instance
* instance
;
658 widget_value
* contents
;
660 if (val
->this_one_change
== NO_CHANGE
)
663 /* update the sensitivity and userdata */
664 /* Common to all widget types */
665 XtSetSensitive (widget
, val
->enabled
);
666 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
668 /* update the menu button as a label. */
669 if (val
->this_one_change
>= VISIBLE_CHANGE
)
671 xm_update_label (instance
, widget
, val
);
672 if (val
->button_type
)
673 xm_update_toggle (instance
, widget
, val
);
676 /* update the pulldown/pullaside as needed */
679 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
680 XtGetValues (widget
, al
, ac
);
682 contents
= val
->contents
;
688 unsigned int old_num_children
, i
;
692 parent
= XtParent (widget
);
693 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
695 /* Find the widget position within the parent's widget list. */
696 for (i
= 0; i
< old_num_children
; i
++)
697 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
699 if (i
== old_num_children
)
701 if (XmIsCascadeButton (widget_list
[i
]))
703 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
704 make_menu_in_widget (instance
, menu
, contents
, 0);
706 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
707 XtSetValues (widget
, al
, ac
);
713 /* The current menuitem is a XmPushButtonGadget, it
714 needs to be replaced by a CascadeButtonGadget */
715 XtDestroyWidget (widget_list
[i
]);
716 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
717 make_menu_in_widget (instance
, menu
, contents
, 0);
719 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
720 /* Non-zero values don't work reliably in
721 conjunction with Emacs' event loop */
722 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
723 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
724 /* Tell Motif to put it in the right place */
725 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
727 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
728 xm_update_label (instance
, button
, val
);
730 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
731 (XtPointer
)instance
);
732 XtManageChild (button
);
739 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
740 XtSetValues (widget
, al
, ac
);
741 XtDestroyWidget (menu
);
743 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
744 xm_update_menu (instance
, menu
, val
, 1);
748 xm_update_menu (instance
, widget
, val
, deep_p
)
749 widget_instance
* instance
;
755 unsigned int num_children
;
756 int num_children_to_keep
= 0;
760 children
= XtCompositeChildren (widget
, &num_children
);
762 /* Widget is a RowColumn widget whose contents have to be updated
763 * to reflect the list of items in val->contents */
765 /* See how many buttons we can keep, and how many we
766 must completely replace. */
767 if (val
->contents
== 0)
768 num_children_to_keep
= 0;
769 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
773 for (i
= 0, cur
= val
->contents
;
775 && cur
); /* how else to ditch unwanted children ?? - mgd */
776 i
++, cur
= cur
->next
)
778 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
782 num_children_to_keep
= i
;
786 num_children_to_keep
= num_children
;
788 /* Update all the buttons of the RowColumn, in order,
789 except for those we are going to replace entirely. */
792 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
796 num_children_to_keep
= i
;
799 if (children
[i
]->core
.being_destroyed
800 || strcmp (XtName (children
[i
]), cur
->name
))
802 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
807 /* Now replace from scratch all the buttons after the last
808 place that the top-level structure changed. */
809 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
811 destroy_all_children (widget
, num_children_to_keep
);
812 make_menu_in_widget (instance
, widget
, val
->contents
,
813 num_children_to_keep
);
816 XtFree ((char *) children
);
820 /* update text widgets */
823 xm_update_text (instance
, widget
, val
)
824 widget_instance
* instance
;
828 XmTextSetString (widget
, val
->value
? val
->value
: "");
829 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
830 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
831 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
832 XtAddCallback (widget
, XmNvalueChangedCallback
,
833 xm_internal_update_other_instances
, instance
);
837 xm_update_text_field (instance
, widget
, val
)
838 widget_instance
* instance
;
842 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
843 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
844 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
845 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
846 XtAddCallback (widget
, XmNvalueChangedCallback
,
847 xm_internal_update_other_instances
, instance
);
851 /* update a motif widget */
854 xm_update_one_widget (instance
, widget
, val
, deep_p
)
855 widget_instance
* instance
;
862 /* Mark as not edited */
865 /* Common to all widget types */
866 XtSetSensitive (widget
, val
->enabled
);
867 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
869 /* Common to all label like widgets */
870 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
871 xm_update_label (instance
, widget
, val
);
873 class = XtClass (widget
);
874 /* Class specific things */
875 if (class == xmPushButtonWidgetClass
||
876 class == xmArrowButtonWidgetClass
)
878 xm_update_pushbutton (instance
, widget
, val
);
880 else if (class == xmCascadeButtonWidgetClass
)
882 xm_update_cascadebutton (instance
, widget
, val
);
884 else if (class == xmToggleButtonWidgetClass
885 || class == xmToggleButtonGadgetClass
)
887 xm_update_toggle (instance
, widget
, val
);
889 else if (class == xmRowColumnWidgetClass
)
891 Boolean radiobox
= 0;
895 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
896 XtGetValues (widget
, al
, ac
);
899 xm_update_radiobox (instance
, widget
, val
);
901 xm_update_menu (instance
, widget
, val
, deep_p
);
903 else if (class == xmTextWidgetClass
)
905 xm_update_text (instance
, widget
, val
);
907 else if (class == xmTextFieldWidgetClass
)
909 xm_update_text_field (instance
, widget
, val
);
911 else if (class == xmListWidgetClass
)
913 xm_update_list (instance
, widget
, val
);
917 \f/* getting the value back */
919 xm_update_one_value (instance
, widget
, val
)
920 widget_instance
* instance
;
924 WidgetClass
class = XtClass (widget
);
925 widget_value
*old_wv
;
927 /* copy the call_data slot into the "return" widget_value */
928 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
929 if (!strcmp (val
->name
, old_wv
->name
))
931 val
->call_data
= old_wv
->call_data
;
935 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
937 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
940 else if (class == xmTextWidgetClass
)
944 val
->value
= XmTextGetString (widget
);
947 else if (class == xmTextFieldWidgetClass
)
951 val
->value
= XmTextFieldGetString (widget
);
954 else if (class == xmRowColumnWidgetClass
)
956 Boolean radiobox
= 0;
960 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
961 XtGetValues (widget
, al
, ac
);
965 CompositeWidget radio
= (CompositeWidget
)widget
;
967 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
970 Widget toggle
= radio
->composite
.children
[i
];
972 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
977 val
->value
= safe_strdup (XtName (toggle
));
983 else if (class == xmListWidgetClass
)
987 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
991 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
995 cur
->selected
= False
;
997 for (j
= 0; j
< pos_cnt
; j
++)
998 if (pos_list
[j
] == i
)
1000 cur
->selected
= True
;
1001 val
->value
= safe_strdup (cur
->name
);
1005 XtFree ((char *) pos_list
);
1011 /* This function is for activating a button from a program. It's wrong because
1012 we pass a NULL argument in the call_data which is not Motif compatible.
1013 This is used from the XmNdefaultAction callback of the List widgets to
1014 have a double-click put down a dialog box like the button would do.
1015 I could not find a way to do that with accelerators.
1018 activate_button (widget
, closure
, call_data
)
1021 XtPointer call_data
;
1023 Widget button
= (Widget
)closure
;
1024 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1027 /* creation functions */
1031 make_dialog (name
, parent
, pop_up_p
, shell_title
, icon_name
, text_input_slot
,
1032 radio_box
, list
, left_buttons
, right_buttons
)
1038 Boolean text_input_slot
;
1048 Widget icon_separator
;
1053 Widget children
[16]; /* for the final XtManageChildren */
1055 Arg al
[64]; /* Arg List */
1056 int ac
; /* Arg Count */
1062 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1063 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1064 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1065 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1067 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1068 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1069 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1070 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1075 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1076 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1077 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1081 n_children
= left_buttons
+ right_buttons
+ 1;
1083 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1084 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1085 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1086 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1087 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1088 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1089 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1090 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1091 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1092 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1093 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1094 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1095 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1096 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1097 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1098 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1099 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1100 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1101 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1104 for (i
= 0; i
< left_buttons
; i
++)
1106 char button_name
[16];
1107 sprintf (button_name
, "button%d", i
+ 1);
1111 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1112 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1114 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1115 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1116 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1120 button
= children
[n_children
];
1122 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1123 XtSetValues (row
, al
, ac
);
1129 /* invisible separator button */
1131 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1132 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1135 for (i
= 0; i
< right_buttons
; i
++)
1137 char button_name
[16];
1138 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1140 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1141 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1142 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1143 if (! button
) button
= children
[n_children
];
1147 XtManageChildren (children
, n_children
);
1150 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1151 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1152 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1153 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1154 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1155 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1156 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1157 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1158 separator
= XmCreateSeparator (form
, "", al
, ac
);
1161 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1162 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1163 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1164 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1165 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1167 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1168 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1171 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1172 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1173 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1174 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1175 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1176 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1177 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1178 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1179 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1180 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1182 if (text_input_slot
)
1185 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1186 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1187 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1188 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1189 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1190 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1191 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1192 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1193 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1194 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1195 value
= XmCreateTextField (form
, "value", al
, ac
);
1201 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1202 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1203 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1204 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1205 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1206 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1207 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1208 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1209 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1210 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1211 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1212 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1213 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1214 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1217 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1218 children
[i
++] = radio_butt
;
1219 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1220 children
[i
++] = radio_butt
;
1221 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1222 children
[i
++] = radio_butt
;
1223 XtManageChildren (children
, i
);
1228 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1229 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1230 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1231 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1232 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1233 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1234 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1235 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1236 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1237 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1238 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1240 /* this is the easiest way I found to have the dble click in the
1241 list activate the default button */
1242 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1246 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1247 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1248 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1249 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1250 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1251 XtSetArg(al
[ac
], XmNbottomWidget
,
1252 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1253 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1254 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1255 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1256 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1257 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1258 message
= XmCreateLabel (form
, "message", al
, ac
);
1261 XtManageChild (value
);
1264 children
[i
] = row
; i
++;
1265 children
[i
] = separator
; i
++;
1266 if (text_input_slot
|| radio_box
)
1268 children
[i
] = value
; i
++;
1270 children
[i
] = message
; i
++;
1271 children
[i
] = icon
; i
++;
1272 children
[i
] = icon_separator
; i
++;
1273 XtManageChildren (children
, i
);
1275 if (text_input_slot
|| list
)
1277 XtInstallAccelerators (value
, button
);
1278 XtSetKeyboardFocus (result
, value
);
1282 XtInstallAccelerators (form
, button
);
1283 XtSetKeyboardFocus (result
, button
);
1289 static destroyed_instance
*
1290 find_matching_instance (instance
)
1291 widget_instance
* instance
;
1293 destroyed_instance
* cur
;
1294 destroyed_instance
* prev
;
1295 char* type
= instance
->info
->type
;
1296 char* name
= instance
->info
->name
;
1298 for (prev
= NULL
, cur
= all_destroyed_instances
;
1300 prev
= cur
, cur
= cur
->next
)
1302 if (!strcmp (cur
->name
, name
)
1303 && !strcmp (cur
->type
, type
)
1304 && cur
->parent
== instance
->parent
1305 && cur
->pop_up_p
== instance
->pop_up_p
)
1308 prev
->next
= cur
->next
;
1310 all_destroyed_instances
= cur
->next
;
1313 /* do some cleanup */
1314 else if (!cur
->widget
)
1317 prev
->next
= cur
->next
;
1319 all_destroyed_instances
= cur
->next
;
1320 free_destroyed_instance (cur
);
1321 cur
= prev
? prev
: all_destroyed_instances
;
1328 mark_dead_instance_destroyed (widget
, closure
, call_data
)
1331 XtPointer call_data
;
1333 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1334 instance
->widget
= NULL
;
1338 recenter_widget (widget
)
1341 Widget parent
= XtParent (widget
);
1342 Screen
* screen
= XtScreen (widget
);
1343 Dimension screen_width
= WidthOfScreen (screen
);
1344 Dimension screen_height
= HeightOfScreen (screen
);
1345 Dimension parent_width
= 0;
1346 Dimension parent_height
= 0;
1347 Dimension child_width
= 0;
1348 Dimension child_height
= 0;
1352 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1353 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1356 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1357 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1359 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1361 if (x
+ child_width
> screen_width
)
1362 x
= screen_width
- child_width
;
1366 if (y
+ child_height
> screen_height
)
1367 y
= screen_height
- child_height
;
1371 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1375 recycle_instance (instance
)
1376 destroyed_instance
* instance
;
1378 Widget widget
= instance
->widget
;
1380 /* widget is NULL if the parent was destroyed. */
1386 /* Remove the destroy callback as the instance is not in the list
1388 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1389 mark_dead_instance_destroyed
,
1390 (XtPointer
)instance
);
1392 /* Give the focus to the initial item */
1393 focus
= XtNameToWidget (widget
, "*value");
1395 focus
= XtNameToWidget (widget
, "*button1");
1397 XtSetKeyboardFocus (widget
, focus
);
1399 /* shrink the separator label back to their original size */
1400 separator
= XtNameToWidget (widget
, "*separator_button");
1402 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1404 /* Center the dialog in its parent */
1405 recenter_widget (widget
);
1407 free_destroyed_instance (instance
);
1412 xm_create_dialog (instance
)
1413 widget_instance
* instance
;
1415 char* name
= instance
->info
->type
;
1416 Widget parent
= instance
->parent
;
1418 Boolean pop_up_p
= instance
->pop_up_p
;
1419 char* shell_name
= 0;
1420 char* icon_name
= 0;
1421 Boolean text_input_slot
= False
;
1422 Boolean radio_box
= False
;
1423 Boolean list
= False
;
1425 int left_buttons
= 0;
1426 int right_buttons
= 1;
1427 destroyed_instance
* dead_one
;
1429 /* try to find a widget to recycle */
1430 dead_one
= find_matching_instance (instance
);
1433 Widget recycled_widget
= recycle_instance (dead_one
);
1434 if (recycled_widget
)
1435 return recycled_widget
;
1440 icon_name
= "dbox-error";
1441 shell_name
= "Error";
1445 icon_name
= "dbox-info";
1446 shell_name
= "Information";
1451 icon_name
= "dbox-question";
1452 shell_name
= "Prompt";
1456 text_input_slot
= True
;
1457 icon_name
= "dbox-question";
1458 shell_name
= "Prompt";
1462 icon_name
= "dbox-question";
1463 shell_name
= "Question";
1467 total_buttons
= name
[1] - '0';
1469 if (name
[3] == 'T' || name
[3] == 't')
1471 text_input_slot
= False
;
1475 right_buttons
= name
[4] - '0';
1477 left_buttons
= total_buttons
- right_buttons
;
1479 widget
= make_dialog (name
, parent
, pop_up_p
,
1480 shell_name
, icon_name
, text_input_slot
, radio_box
,
1481 list
, left_buttons
, right_buttons
);
1483 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1484 (XtPointer
) instance
);
1488 /* Create a menu bar. We turn off the f10 key
1489 because we have not yet managed to make it work right in Motif. */
1492 make_menubar (instance
)
1493 widget_instance
* instance
;
1499 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1500 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1504 remove_grabs (shell
, closure
, call_data
)
1507 XtPointer call_data
;
1509 Widget menu
= (Widget
) closure
;
1510 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1514 make_popup_menu (instance
)
1515 widget_instance
* instance
;
1517 Widget parent
= instance
->parent
;
1518 Window parent_window
= parent
->core
.window
;
1521 /* sets the parent window to 0 to fool Motif into not generating a grab */
1522 parent
->core
.window
= 0;
1523 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1524 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1526 parent
->core
.window
= parent_window
;
1531 make_main (instance
)
1532 widget_instance
* instance
;
1534 Widget parent
= instance
->parent
;
1540 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1541 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1542 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1546 \f/* Table of functions to create widgets */
1550 /* interface with the XDesigner generated functions */
1551 typedef Widget (*widget_maker
) (Widget
);
1552 extern Widget
create_project_p_sheet (Widget parent
);
1553 extern Widget
create_debugger_p_sheet (Widget parent
);
1554 extern Widget
create_breaklist_p_sheet (Widget parent
);
1555 extern Widget
create_le_browser_p_sheet (Widget parent
);
1556 extern Widget
create_class_browser_p_sheet (Widget parent
);
1557 extern Widget
create_call_browser_p_sheet (Widget parent
);
1558 extern Widget
create_build_dialog (Widget parent
);
1559 extern Widget
create_editmode_dialog (Widget parent
);
1560 extern Widget
create_search_dialog (Widget parent
);
1561 extern Widget
create_project_display_dialog (Widget parent
);
1564 make_one (widget_instance
* instance
, widget_maker fn
)
1570 if (instance
->pop_up_p
)
1572 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1573 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1574 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1575 (XtPointer
) instance
);
1580 result
= (*fn
) (instance
->parent
);
1581 XtRealizeWidget (result
);
1587 make_project_p_sheet (widget_instance
* instance
)
1589 return make_one (instance
, create_project_p_sheet
);
1593 make_debugger_p_sheet (widget_instance
* instance
)
1595 return make_one (instance
, create_debugger_p_sheet
);
1599 make_breaklist_p_sheet (widget_instance
* instance
)
1601 return make_one (instance
, create_breaklist_p_sheet
);
1605 make_le_browser_p_sheet (widget_instance
* instance
)
1607 return make_one (instance
, create_le_browser_p_sheet
);
1611 make_class_browser_p_sheet (widget_instance
* instance
)
1613 return make_one (instance
, create_class_browser_p_sheet
);
1617 make_call_browser_p_sheet (widget_instance
* instance
)
1619 return make_one (instance
, create_call_browser_p_sheet
);
1623 make_build_dialog (widget_instance
* instance
)
1625 return make_one (instance
, create_build_dialog
);
1629 make_editmode_dialog (widget_instance
* instance
)
1631 return make_one (instance
, create_editmode_dialog
);
1635 make_search_dialog (widget_instance
* instance
)
1637 return make_one (instance
, create_search_dialog
);
1641 make_project_display_dialog (widget_instance
* instance
)
1643 return make_one (instance
, create_project_display_dialog
);
1646 #endif /* ENERGIZE */
1648 widget_creation_entry
1649 xm_creation_table
[] =
1651 {"menubar", make_menubar
},
1652 {"popup", make_popup_menu
},
1653 {"main", make_main
},
1655 {"project_p_sheet", make_project_p_sheet
},
1656 {"debugger_p_sheet", make_debugger_p_sheet
},
1657 {"breaklist_psheet", make_breaklist_p_sheet
},
1658 {"leb_psheet", make_le_browser_p_sheet
},
1659 {"class_browser_psheet", make_class_browser_p_sheet
},
1660 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1661 {"build", make_build_dialog
},
1662 {"editmode", make_editmode_dialog
},
1663 {"search", make_search_dialog
},
1664 {"project_display", make_project_display_dialog
},
1665 #endif /* ENERGIZE */
1669 \f/* Destruction of instances */
1671 xm_destroy_instance (instance
)
1672 widget_instance
* instance
;
1674 Widget widget
= instance
->widget
;
1675 /* recycle the dialog boxes */
1676 /* Disable the recycling until we can find a way to have the dialog box
1677 get reasonable layout after we modify its contents. */
1679 && XtClass (widget
) == xmDialogShellWidgetClass
)
1681 destroyed_instance
* dead_instance
=
1682 make_destroyed_instance (instance
->info
->name
,
1683 instance
->info
->type
,
1686 instance
->pop_up_p
);
1687 dead_instance
->next
= all_destroyed_instances
;
1688 all_destroyed_instances
= dead_instance
;
1689 XtUnmanageChild (first_child (instance
->widget
));
1690 XFlush (XtDisplay (instance
->widget
));
1691 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1692 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1696 /* This might not be necessary now that the nosel is attached to
1697 popdown instead of destroy, but it can't hurt. */
1698 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1699 xm_nosel_callback
, (XtPointer
)instance
);
1700 XtDestroyWidget (instance
->widget
);
1704 \f/* popup utility */
1706 xm_popup_menu (widget
, event
)
1710 XButtonPressedEvent dummy
;
1714 dummy
.type
= ButtonPress
;
1716 dummy
.send_event
= 0;
1717 dummy
.display
= XtDisplay (widget
);
1718 dummy
.window
= XtWindow (XtParent (widget
));
1721 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1722 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1723 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1724 event
= (XEvent
*) &dummy
;
1727 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1729 /* Setting the menuPost resource only required by Motif 1.1 and
1730 LessTif 0.84 and earlier. With later versions of LessTif,
1731 setting menuPost is unnecessary and may cause problems, so
1733 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
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
);
1749 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1752 XtManageChild (widget
);
1756 set_min_dialog_size (w
)
1761 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1762 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1766 xm_pop_instance (instance
, up
)
1767 widget_instance
* instance
;
1770 Widget widget
= instance
->widget
;
1772 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1774 Widget widget_to_manage
= first_child (widget
);
1777 XtManageChild (widget_to_manage
);
1778 set_min_dialog_size (widget
);
1779 XtSetKeyboardFocus (instance
->parent
, widget
);
1782 XtUnmanageChild (widget_to_manage
);
1787 XtManageChild (widget
);
1789 XtUnmanageChild (widget
);
1794 /* motif callback */
1797 do_call (widget
, closure
, type
)
1800 enum do_call_type type
;
1804 XtPointer user_data
;
1805 widget_instance
* instance
= (widget_instance
*)closure
;
1806 Widget instance_widget
;
1811 if (widget
->core
.being_destroyed
)
1814 instance_widget
= instance
->widget
;
1815 if (!instance_widget
)
1818 id
= instance
->info
->id
;
1821 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1822 XtGetValues (widget
, al
, ac
);
1827 if (instance
->info
->pre_activate_cb
)
1828 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1832 if (instance
->info
->selection_cb
)
1833 instance
->info
->selection_cb (widget
, id
, user_data
);
1837 if (instance
->info
->selection_cb
)
1838 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1842 if (instance
->info
->post_activate_cb
)
1843 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1851 /* Like lw_internal_update_other_instances except that it does not do
1852 anything if its shell parent is not managed. This is to protect
1853 lw_internal_update_other_instances to dereference freed memory
1854 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1857 xm_internal_update_other_instances (widget
, closure
, call_data
)
1860 XtPointer call_data
;
1863 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1864 if (XtIsShell (parent
))
1866 else if (!XtIsManaged (parent
))
1868 lw_internal_update_other_instances (widget
, closure
, call_data
);
1872 xm_generic_callback (widget
, closure
, call_data
)
1875 XtPointer call_data
;
1877 lw_internal_update_other_instances (widget
, closure
, call_data
);
1878 do_call (widget
, closure
, selection
);
1882 xm_nosel_callback (widget
, closure
, call_data
)
1885 XtPointer call_data
;
1887 /* This callback is only called when a dialog box is dismissed with
1888 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1889 box to be destroyed in that case, not just unmapped, so that it
1890 releases its keyboard grabs. But there are problems with running
1891 our callbacks while the widget is in the process of being
1892 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1893 XmDESTROY and then destroy it ourself after having run the
1895 do_call (widget
, closure
, no_selection
);
1896 XtDestroyWidget (widget
);
1900 xm_pull_down_callback (widget
, closure
, call_data
)
1903 XtPointer call_data
;
1905 Widget parent
= XtParent (widget
);
1907 if (XmIsRowColumn (parent
))
1909 unsigned char type
= 0xff;
1910 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1911 if (type
== XmMENU_BAR
)
1912 do_call (widget
, closure
, pre_activate
);
1917 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1918 CLOSURE is a pointer to the widget_instance of the shell,
1920 Note that this callback is called for each cascade button in a
1921 menu, whether or not its submenu is visible. */
1924 xm_pop_down_callback (widget
, closure
, call_data
)
1927 XtPointer call_data
;
1929 widget_instance
*instance
= (widget_instance
*) closure
;
1931 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1932 || XtParent (widget
) == instance
->parent
)
1933 do_call (widget
, closure
, post_activate
);
1937 /* set the keyboard focus */
1939 xm_set_keyboard_focus (parent
, w
)
1943 XmProcessTraversal (w
, 0);
1944 XtSetKeyboardFocus (parent
, w
);
1947 /* Motif hack to set the main window areas. */
1949 xm_set_main_areas (parent
, menubar
, work_area
)
1954 XmMainWindowSetAreas (parent
,
1955 menubar
, /* menubar (maybe 0) */
1956 0, /* command area (psheets) */
1957 0, /* horizontal scroll */
1958 0, /* vertical scroll */
1959 work_area
); /* work area */
1962 /* Motif hack to control resizing on the menubar. */
1964 xm_manage_resizing (w
, flag
)
1968 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);