1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2011 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
31 #include <X11/StringDefs.h>
32 #include <X11/IntrinsicP.h>
33 #include <X11/ObjectP.h>
34 #include <X11/CoreP.h>
35 #include <X11/CompositeP.h>
40 #include "lwlib-utils.h"
42 #include <Xm/BulletinB.h>
43 #include <Xm/CascadeB.h>
44 #include <Xm/CascadeBG.h>
45 #include <Xm/DrawingA.h>
46 #include <Xm/FileSB.h>
50 #include <Xm/MenuShell.h>
51 #include <Xm/MessageB.h>
52 #include <Xm/PanedW.h>
54 #include <Xm/PushBG.h>
55 #include <Xm/ArrowB.h>
56 #include <Xm/SelectioB.h>
59 #include <Xm/ToggleB.h>
60 #include <Xm/ToggleBG.h>
61 #include <Xm/RowColumn.h>
62 #include <Xm/ScrolledW.h>
63 #include <Xm/Separator.h>
64 #include <Xm/DialogS.h>
67 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
70 \f/* Structures to keep destroyed instances */
71 typedef struct _destroyed_instance
78 struct _destroyed_instance
* next
;
81 static destroyed_instance
*make_destroyed_instance (char *, char *,
84 static void free_destroyed_instance (destroyed_instance
*);
85 Widget
first_child (Widget
);
86 Boolean
lw_motif_widget_p (Widget
);
87 static XmString
resource_motif_string (Widget
, char *);
88 static void destroy_all_children (Widget
, int);
89 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
90 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
91 static void xm_update_pushbutton (widget_instance
*, Widget
,
93 static void xm_update_cascadebutton (widget_instance
*, Widget
,
95 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
96 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
97 static void make_menu_in_widget (widget_instance
*, Widget
,
99 static void update_one_menu_entry (widget_instance
*, Widget
,
100 widget_value
*, Boolean
);
101 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
103 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
104 static void xm_update_text_field (widget_instance
*, Widget
,
106 void xm_update_one_value (widget_instance
*, Widget
, widget_value
*);
107 static void activate_button (Widget
, XtPointer
, XtPointer
);
108 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
109 Boolean
, Boolean
, Boolean
, int, int);
110 static destroyed_instance
* find_matching_instance (widget_instance
*);
111 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
112 static void recenter_widget (Widget
);
113 static Widget
recycle_instance (destroyed_instance
*);
114 Widget
xm_create_dialog (widget_instance
*);
115 static Widget
make_menubar (widget_instance
*);
116 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
117 static Widget
make_popup_menu (widget_instance
*);
118 static Widget
make_main (widget_instance
*);
119 void xm_destroy_instance (widget_instance
*);
120 void xm_popup_menu (Widget
, XEvent
*);
121 static void set_min_dialog_size (Widget
);
122 static void do_call (Widget
, XtPointer
, enum do_call_type
);
123 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
124 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
125 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
126 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
127 void xm_set_keyboard_focus (Widget
, Widget
);
128 void xm_set_main_areas (Widget
, Widget
, Widget
);
129 static void xm_internal_update_other_instances (Widget
, XtPointer
,
131 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
134 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
136 void xm_pop_instance (widget_instance
*, Boolean
);
137 void xm_manage_resizing (Widget
, Boolean
);
143 /* Print the complete X resource name of widget WIDGET to stderr.
144 This is sometimes handy to have available. */
147 x_print_complete_resource_name (Widget widget
)
152 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
154 names
[i
] = XtName (widget
);
155 widget
= XtParent (widget
);
158 for (--i
; i
>= 1; --i
)
159 fprintf (stderr
, "%s.", names
[i
]);
160 fprintf (stderr
, "%s\n", names
[0]);
166 static destroyed_instance
*all_destroyed_instances
= NULL
;
168 static destroyed_instance
*
169 make_destroyed_instance (char* name
,
175 destroyed_instance
* instance
=
176 (destroyed_instance
*) xmalloc (sizeof (destroyed_instance
));
177 instance
->name
= safe_strdup (name
);
178 instance
->type
= safe_strdup (type
);
179 instance
->widget
= widget
;
180 instance
->parent
= parent
;
181 instance
->pop_up_p
= pop_up_p
;
182 instance
->next
= NULL
;
187 free_destroyed_instance (destroyed_instance
* instance
)
189 free (instance
->name
);
190 free (instance
->type
);
194 \f/* motif utility functions */
196 first_child (Widget widget
)
198 return ((CompositeWidget
)widget
)->composite
.children
[0];
202 lw_motif_widget_p (Widget widget
)
205 XtClass (widget
) == xmDialogShellWidgetClass
206 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
210 resource_motif_string (Widget widget
,
216 resource
.resource_name
= name
;
217 resource
.resource_class
= XmCXmString
;
218 resource
.resource_type
= XmRXmString
;
219 resource
.resource_size
= sizeof (XmString
);
220 resource
.resource_offset
= 0;
221 resource
.default_type
= XtRImmediate
;
222 resource
.default_addr
= 0;
224 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
225 "DialogString", &resource
, 1, NULL
, 0);
229 /* Destroy all of the children of WIDGET
230 starting with number FIRST_CHILD_TO_DESTROY. */
233 destroy_all_children (Widget widget
,
234 int first_child_to_destroy
)
240 children
= XtCompositeChildren (widget
, &number
);
243 XtUnmanageChildren (children
+ first_child_to_destroy
,
244 number
- first_child_to_destroy
);
246 /* Unmanage all children and destroy them. They will only be
247 really destroyed when we get out of DispatchEvent. */
248 for (i
= first_child_to_destroy
; i
< number
; i
++)
252 /* Cascade buttons have submenus,and these submenus
253 need to be freed. But they are not included in
254 XtCompositeChildren. So get it out of the cascade button
255 and free it. If this child is not a cascade button,
256 then submenu should remain unchanged. */
257 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
258 XtGetValues (children
[i
], al
, 1);
261 destroy_all_children (submenu
, 0);
262 XtDestroyWidget (submenu
);
264 XtDestroyWidget (children
[i
]);
267 XtFree ((char *) children
);
273 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
274 menu. CLIENT_DATA contains a pointer to the widget_value
275 corresponding to widget W. CALL_DATA contains a
276 XmPushButtonCallbackStruct containing the reason why the callback
280 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
282 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
283 widget_value
*wv
= (widget_value
*) client_data
;
284 widget_instance
*instance
;
286 /* Get the id of the menu bar or popup menu this widget is in. */
289 if (XmIsRowColumn (w
))
291 unsigned char type
= 0xff;
293 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
294 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
303 instance
= lw_get_widget_instance (w
);
304 if (instance
&& instance
->info
->highlight_cb
)
306 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
307 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
314 /* Update the label of widget WIDGET. WIDGET must be a Label widget
315 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
320 Emacs fills VAL->name with the text to display in the menu, and
321 sets VAL->value to null. Function make_menu_in_widget creates
322 widgets with VAL->name as resource name. This works because the
323 Label widget uses its resource name for display if no
324 XmNlabelString is set.
328 VAL->name is again set to the resource name, but VAL->value is
329 not null, and contains the label string to display. */
332 xm_update_label (widget_instance
* instance
,
336 XmString res_string
= 0;
337 XmString built_string
= 0;
338 XmString key_string
= 0;
346 /* A label string is specified, i.e. we are in a dialog. First
347 see if it is overridden by something from the resource file. */
348 res_string
= resource_motif_string (widget
, val
->value
);
352 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
357 XmStringCreateLocalized (val
->value
);
358 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
361 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
366 key_string
= XmStringCreateLocalized (val
->key
);
367 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
371 XtSetValues (widget
, al
, ac
);
374 XmStringFree (built_string
);
377 XmStringFree (key_string
);
380 \f/* update of list */
382 xm_update_list (widget_instance
* instance
,
388 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
389 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
391 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
394 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
396 XmListAddItem (widget
, xmstr
, 0);
398 XmListSelectPos (widget
, i
, False
);
399 XmStringFree (xmstr
);
403 \f/* update of buttons */
405 xm_update_pushbutton (widget_instance
* instance
,
409 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
410 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
411 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
415 xm_update_cascadebutton (widget_instance
* instance
,
419 /* Should also rebuild the menu by calling ...update_menu... */
420 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
421 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
425 \f/* update toggle and radiobox */
427 xm_update_toggle (widget_instance
* instance
,
431 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
432 XtAddCallback (widget
, XmNvalueChangedCallback
,
433 xm_generic_callback
, instance
);
434 XtVaSetValues (widget
, XmNset
, val
->selected
,
435 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
439 xm_update_radiobox (widget_instance
* instance
,
447 /* update the callback */
448 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
449 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
451 /* first update all the toggles */
452 /* Energize kernel interface is currently bad. It sets the selected widget
453 with the selected flag but returns it by its name. So we currently
454 have to support both setting the selection with the selected slot
455 of val contents and setting it with the "value" slot of val. The latter
456 has a higher priority. This to be removed when the kernel is fixed. */
457 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
459 toggle
= XtNameToWidget (widget
, cur
->value
);
462 XtSetSensitive (toggle
, cur
->enabled
);
463 if (!val
->value
&& cur
->selected
)
464 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
465 if (val
->value
&& strcmp (val
->value
, cur
->value
))
466 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
470 /* The selected was specified by the value slot */
473 toggle
= XtNameToWidget (widget
, val
->value
);
475 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
480 /* update a popup menu, pulldown menu or a menubar */
482 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
485 make_menu_in_widget (widget_instance
* instance
,
488 int keep_first_children
)
490 Widget
* children
= 0;
502 Widget
* old_children
;
503 unsigned int old_num_children
;
505 /* Disable drag and drop for labels in menu bar. */
506 static char overrideTrans
[] = "<Btn2Down>: Noop()";
507 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
509 old_children
= XtCompositeChildren (widget
, &old_num_children
);
511 /* Allocate the children array */
512 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
514 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
516 /* WIDGET should be a RowColumn. */
517 if (!XmIsRowColumn (widget
))
520 /* Determine whether WIDGET is a menu bar. */
522 XtSetArg (al
[0], XmNrowColumnType
, &type
);
523 XtGetValues (widget
, al
, 1);
524 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
526 menubar_p
= type
== XmMENU_BAR
;
528 /* Add a callback to popups and pulldowns that is called when
529 it is made invisible again. */
531 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
532 xm_pop_down_callback
, (XtPointer
)instance
);
534 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
535 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
536 child_index
++, cur
= cur
->next
)
537 children
[child_index
] = old_children
[child_index
];
539 /* Check that those are all we have
540 (the caller should have deleted the rest). */
541 if (old_num_children
!= keep_first_children
)
544 /* Create the rest. */
545 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
547 enum menu_separator separator
;
550 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
551 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
552 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
554 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
555 && !lw_separator_p (cur
->name
, &separator
, 1))
558 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
559 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
561 else if (lw_separator_p (cur
->name
, &separator
, 1))
564 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
565 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
567 else if (!cur
->contents
)
570 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
571 else if (!cur
->call_data
)
572 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
573 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
574 || cur
->button_type
== BUTTON_TYPE_RADIO
)
576 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
577 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
578 XtSetArg (al
[ac
], XmNindicatorType
,
579 (cur
->button_type
== BUTTON_TYPE_TOGGLE
580 ? XmN_OF_MANY
: XmONE_OF_MANY
));
582 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
583 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
584 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
588 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
589 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
590 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
593 xm_update_label (instance
, button
, cur
);
595 /* Add a callback that is called when the button is
596 selected. Toggle buttons don't support
597 XmNactivateCallback, we use XmNvalueChangedCallback in
598 that case. Don't add a callback to a simple label. */
599 if (cur
->button_type
)
600 xm_update_toggle (instance
, button
, cur
);
601 else if (cur
->call_data
)
602 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
603 (XtPointer
)instance
);
607 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
609 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
610 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
611 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
613 xm_update_label (instance
, button
, cur
);
615 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
616 (XtPointer
)instance
);
617 XtOverrideTranslations (button
, override
);
621 children
[child_index
] = button
;
624 /* Last entry is the help button. The original comment read "Has to
625 be done after managing the buttons otherwise the menubar is only
626 4 pixels high." This is no longer true, and to make
627 XmNmenuHelpWidget work, we need to set it before managing the
628 children.. --gerd. */
630 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
633 XtManageChildren (children
, num_children
);
635 XtFree ((char *) children
);
637 XtFree ((char *) old_children
);
641 update_one_menu_entry (widget_instance
* instance
,
649 widget_value
* contents
;
651 if (val
->this_one_change
== NO_CHANGE
)
654 /* update the sensitivity and userdata */
655 /* Common to all widget types */
656 XtSetSensitive (widget
, val
->enabled
);
657 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
659 /* update the menu button as a label. */
660 if (val
->this_one_change
>= VISIBLE_CHANGE
)
662 xm_update_label (instance
, widget
, val
);
663 if (val
->button_type
)
664 xm_update_toggle (instance
, widget
, val
);
667 /* update the pulldown/pullaside as needed */
670 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
671 XtGetValues (widget
, al
, ac
);
673 contents
= val
->contents
;
679 unsigned int old_num_children
, i
;
683 parent
= XtParent (widget
);
684 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
686 /* Find the widget position within the parent's widget list. */
687 for (i
= 0; i
< old_num_children
; i
++)
688 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
690 if (i
== old_num_children
)
692 if (XmIsCascadeButton (widget_list
[i
]))
694 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
695 make_menu_in_widget (instance
, menu
, contents
, 0);
697 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
698 XtSetValues (widget
, al
, ac
);
704 /* The current menuitem is a XmPushButtonGadget, it
705 needs to be replaced by a CascadeButtonGadget */
706 XtDestroyWidget (widget_list
[i
]);
707 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
708 make_menu_in_widget (instance
, menu
, contents
, 0);
710 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
711 /* Non-zero values don't work reliably in
712 conjunction with Emacs' event loop */
713 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
714 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
715 /* Tell Motif to put it in the right place */
716 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
718 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
719 xm_update_label (instance
, button
, val
);
721 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
722 (XtPointer
)instance
);
723 XtManageChild (button
);
727 XtFree ((char*) widget_list
);
733 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
734 XtSetValues (widget
, al
, ac
);
735 XtDestroyWidget (menu
);
737 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
738 xm_update_menu (instance
, menu
, val
, 1);
742 xm_update_menu (widget_instance
* instance
,
748 unsigned int num_children
;
749 int num_children_to_keep
= 0;
753 children
= XtCompositeChildren (widget
, &num_children
);
755 /* Widget is a RowColumn widget whose contents have to be updated
756 * to reflect the list of items in val->contents */
758 /* See how many buttons we can keep, and how many we
759 must completely replace. */
760 if (val
->contents
== 0)
761 num_children_to_keep
= 0;
762 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
766 for (i
= 0, cur
= val
->contents
;
768 && cur
); /* how else to ditch unwanted children ?? - mgd */
769 i
++, cur
= cur
->next
)
771 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
775 num_children_to_keep
= i
;
779 num_children_to_keep
= num_children
;
781 /* Update all the buttons of the RowColumn, in order,
782 except for those we are going to replace entirely. */
785 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
789 num_children_to_keep
= i
;
792 if (children
[i
]->core
.being_destroyed
793 || strcmp (XtName (children
[i
]), cur
->name
))
795 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
800 /* Now replace from scratch all the buttons after the last
801 place that the top-level structure changed. */
802 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
804 destroy_all_children (widget
, num_children_to_keep
);
805 make_menu_in_widget (instance
, widget
, val
->contents
,
806 num_children_to_keep
);
809 XtFree ((char *) children
);
813 /* update text widgets */
816 xm_update_text (widget_instance
* instance
,
820 XmTextSetString (widget
, val
->value
? val
->value
: "");
821 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
822 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
823 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
824 XtAddCallback (widget
, XmNvalueChangedCallback
,
825 xm_internal_update_other_instances
, instance
);
829 xm_update_text_field (widget_instance
* instance
,
833 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
834 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
835 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
836 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
837 XtAddCallback (widget
, XmNvalueChangedCallback
,
838 xm_internal_update_other_instances
, instance
);
842 /* update a motif widget */
845 xm_update_one_widget (widget_instance
* instance
,
852 /* Mark as not edited */
855 /* Common to all widget types */
856 XtSetSensitive (widget
, val
->enabled
);
857 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
859 /* Common to all label like widgets */
860 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
861 xm_update_label (instance
, widget
, val
);
863 class = XtClass (widget
);
864 /* Class specific things */
865 if (class == xmPushButtonWidgetClass
||
866 class == xmArrowButtonWidgetClass
)
868 xm_update_pushbutton (instance
, widget
, val
);
870 else if (class == xmCascadeButtonWidgetClass
)
872 xm_update_cascadebutton (instance
, widget
, val
);
874 else if (class == xmToggleButtonWidgetClass
875 || class == xmToggleButtonGadgetClass
)
877 xm_update_toggle (instance
, widget
, val
);
879 else if (class == xmRowColumnWidgetClass
)
881 Boolean radiobox
= 0;
885 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
886 XtGetValues (widget
, al
, ac
);
889 xm_update_radiobox (instance
, widget
, val
);
891 xm_update_menu (instance
, widget
, val
, deep_p
);
893 else if (class == xmTextWidgetClass
)
895 xm_update_text (instance
, widget
, val
);
897 else if (class == xmTextFieldWidgetClass
)
899 xm_update_text_field (instance
, widget
, val
);
901 else if (class == xmListWidgetClass
)
903 xm_update_list (instance
, widget
, val
);
907 \f/* getting the value back */
909 xm_update_one_value (widget_instance
* instance
,
913 WidgetClass
class = XtClass (widget
);
914 widget_value
*old_wv
;
916 /* copy the call_data slot into the "return" widget_value */
917 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
918 if (!strcmp (val
->name
, old_wv
->name
))
920 val
->call_data
= old_wv
->call_data
;
924 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
926 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
929 else if (class == xmTextWidgetClass
)
932 val
->value
= XmTextGetString (widget
);
935 else if (class == xmTextFieldWidgetClass
)
938 val
->value
= XmTextFieldGetString (widget
);
941 else if (class == xmRowColumnWidgetClass
)
943 Boolean radiobox
= 0;
947 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
948 XtGetValues (widget
, al
, ac
);
952 CompositeWidget radio
= (CompositeWidget
)widget
;
954 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
957 Widget toggle
= radio
->composite
.children
[i
];
959 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
963 val
->value
= safe_strdup (XtName (toggle
));
969 else if (class == xmListWidgetClass
)
973 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
977 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
981 cur
->selected
= False
;
983 for (j
= 0; j
< pos_cnt
; j
++)
984 if (pos_list
[j
] == i
)
986 cur
->selected
= True
;
987 val
->value
= safe_strdup (cur
->name
);
991 XtFree ((char *) pos_list
);
997 /* This function is for activating a button from a program. It's wrong because
998 we pass a NULL argument in the call_data which is not Motif compatible.
999 This is used from the XmNdefaultAction callback of the List widgets to
1000 have a double-click put down a dialog box like the button would do.
1001 I could not find a way to do that with accelerators.
1004 activate_button (Widget widget
,
1006 XtPointer call_data
)
1008 Widget button
= (Widget
)closure
;
1009 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1012 /* creation functions */
1014 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1016 dialog_key_cb (Widget widget
,
1019 Boolean
*continue_to_dispatch
)
1022 Modifiers modif_ret
;
1024 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1027 if (sym
== osfXK_Cancel
)
1029 Widget w
= *((Widget
*) closure
);
1031 while (w
&& ! XtIsShell (w
))
1034 if (XtIsShell (w
)) XtPopdown (w
);
1037 *continue_to_dispatch
= TRUE
;
1042 make_dialog (char* name
,
1047 Boolean text_input_slot
,
1057 Widget icon_separator
;
1058 Widget message_label
;
1062 Widget children
[16]; /* for the final XtManageChildren */
1064 Arg al
[64]; /* Arg List */
1065 int ac
; /* Arg Count */
1071 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1072 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1073 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1074 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1076 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1077 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1078 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1079 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1084 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1085 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1086 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1090 n_children
= left_buttons
+ right_buttons
+ 1;
1092 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1093 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1094 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1095 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1096 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1097 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1098 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1099 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1100 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1101 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1102 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1103 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1104 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1105 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1106 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1107 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1108 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1109 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1110 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1113 for (i
= 0; i
< left_buttons
; i
++)
1115 char button_name
[16];
1116 sprintf (button_name
, "button%d", i
+ 1);
1120 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1121 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1123 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1124 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1125 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1126 XtAddEventHandler (children
[n_children
],
1127 KeyPressMask
, False
, dialog_key_cb
, result
);
1131 button
= children
[n_children
];
1133 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1134 XtSetValues (row
, al
, ac
);
1140 /* invisible separator button */
1142 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1143 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1146 for (i
= 0; i
< right_buttons
; i
++)
1148 char button_name
[16];
1149 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1151 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1152 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1153 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1154 XtAddEventHandler (children
[n_children
],
1155 KeyPressMask
, False
, dialog_key_cb
, result
);
1157 if (! button
) button
= children
[n_children
];
1161 XtManageChildren (children
, n_children
);
1164 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1165 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1166 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1167 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1168 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1169 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1170 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1171 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1172 separator
= XmCreateSeparator (form
, "", al
, ac
);
1175 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1176 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1177 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1178 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1179 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1180 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1181 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1182 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1185 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1186 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1187 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1188 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1189 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1190 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1191 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1192 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1193 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1194 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1196 if (text_input_slot
)
1199 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1200 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1201 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1202 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1203 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1204 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1205 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1206 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1207 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1208 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1209 value
= XmCreateTextField (form
, "value", al
, ac
);
1215 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1216 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1217 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1218 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1219 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1220 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1221 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1222 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1223 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1224 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1225 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1226 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1227 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1228 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1231 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1232 children
[i
++] = radio_butt
;
1233 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1234 children
[i
++] = radio_butt
;
1235 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1236 children
[i
++] = radio_butt
;
1237 XtManageChildren (children
, i
);
1242 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1243 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1244 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1245 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1246 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1247 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1248 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1249 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1250 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1251 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1252 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1254 /* this is the easiest way I found to have the dble click in the
1255 list activate the default button */
1256 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1260 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1261 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1262 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1263 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1264 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1265 XtSetArg(al
[ac
], XmNbottomWidget
,
1266 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1267 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1268 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1269 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1270 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1271 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1272 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1275 XtManageChild (value
);
1278 children
[i
] = row
; i
++;
1279 children
[i
] = separator
; i
++;
1280 if (text_input_slot
|| radio_box
)
1282 children
[i
] = value
; i
++;
1284 children
[i
] = message_label
; i
++;
1285 children
[i
] = icon
; i
++;
1286 children
[i
] = icon_separator
; i
++;
1287 XtManageChildren (children
, i
);
1289 if (text_input_slot
|| list
)
1291 XtInstallAccelerators (value
, button
);
1292 XtSetKeyboardFocus (result
, value
);
1296 XtInstallAccelerators (form
, button
);
1297 XtSetKeyboardFocus (result
, button
);
1303 static destroyed_instance
*
1304 find_matching_instance (widget_instance
* instance
)
1306 destroyed_instance
* cur
;
1307 destroyed_instance
* prev
;
1308 char* type
= instance
->info
->type
;
1309 char* name
= instance
->info
->name
;
1311 for (prev
= NULL
, cur
= all_destroyed_instances
;
1313 prev
= cur
, cur
= cur
->next
)
1315 if (!strcmp (cur
->name
, name
)
1316 && !strcmp (cur
->type
, type
)
1317 && cur
->parent
== instance
->parent
1318 && cur
->pop_up_p
== instance
->pop_up_p
)
1321 prev
->next
= cur
->next
;
1323 all_destroyed_instances
= cur
->next
;
1326 /* do some cleanup */
1327 else if (!cur
->widget
)
1330 prev
->next
= cur
->next
;
1332 all_destroyed_instances
= cur
->next
;
1333 free_destroyed_instance (cur
);
1334 cur
= prev
? prev
: all_destroyed_instances
;
1341 mark_dead_instance_destroyed (Widget widget
,
1343 XtPointer call_data
)
1345 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1346 instance
->widget
= NULL
;
1350 recenter_widget (Widget widget
)
1352 Widget parent
= XtParent (widget
);
1353 Screen
* screen
= XtScreen (widget
);
1354 Dimension screen_width
= WidthOfScreen (screen
);
1355 Dimension screen_height
= HeightOfScreen (screen
);
1356 Dimension parent_width
= 0;
1357 Dimension parent_height
= 0;
1358 Dimension child_width
= 0;
1359 Dimension child_height
= 0;
1363 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1364 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1367 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1368 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1370 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1372 if (x
+ child_width
> screen_width
)
1373 x
= screen_width
- child_width
;
1377 if (y
+ child_height
> screen_height
)
1378 y
= screen_height
- child_height
;
1382 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1386 recycle_instance (destroyed_instance
* instance
)
1388 Widget widget
= instance
->widget
;
1390 /* widget is NULL if the parent was destroyed. */
1396 /* Remove the destroy callback as the instance is not in the list
1398 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1399 mark_dead_instance_destroyed
,
1400 (XtPointer
)instance
);
1402 /* Give the focus to the initial item */
1403 focus
= XtNameToWidget (widget
, "*value");
1405 focus
= XtNameToWidget (widget
, "*button1");
1407 XtSetKeyboardFocus (widget
, focus
);
1409 /* shrink the separator label back to their original size */
1410 separator
= XtNameToWidget (widget
, "*separator_button");
1412 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1414 /* Center the dialog in its parent */
1415 recenter_widget (widget
);
1417 free_destroyed_instance (instance
);
1422 xm_create_dialog (widget_instance
* instance
)
1424 char* name
= instance
->info
->type
;
1425 Widget parent
= instance
->parent
;
1427 Boolean pop_up_p
= instance
->pop_up_p
;
1428 char* shell_name
= 0;
1429 char* icon_name
= 0;
1430 Boolean text_input_slot
= False
;
1431 Boolean radio_box
= False
;
1432 Boolean list
= False
;
1434 int left_buttons
= 0;
1435 int right_buttons
= 1;
1436 destroyed_instance
* dead_one
;
1438 /* try to find a widget to recycle */
1439 dead_one
= find_matching_instance (instance
);
1442 Widget recycled_widget
= recycle_instance (dead_one
);
1443 if (recycled_widget
)
1444 return recycled_widget
;
1449 icon_name
= "dbox-error";
1450 shell_name
= "Error";
1454 icon_name
= "dbox-info";
1455 shell_name
= "Information";
1460 icon_name
= "dbox-question";
1461 shell_name
= "Prompt";
1465 text_input_slot
= True
;
1466 icon_name
= "dbox-question";
1467 shell_name
= "Prompt";
1471 icon_name
= "dbox-question";
1472 shell_name
= "Question";
1476 total_buttons
= name
[1] - '0';
1478 if (name
[3] == 'T' || name
[3] == 't')
1480 text_input_slot
= False
;
1484 right_buttons
= name
[4] - '0';
1486 left_buttons
= total_buttons
- right_buttons
;
1488 widget
= make_dialog (name
, parent
, pop_up_p
,
1489 shell_name
, icon_name
, text_input_slot
, radio_box
,
1490 list
, left_buttons
, right_buttons
);
1492 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1493 (XtPointer
) instance
);
1498 /* Create a menu bar. We turn off the f10 key
1499 because we have not yet managed to make it work right in Motif. */
1502 make_menubar (widget_instance
* instance
)
1508 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1509 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1513 remove_grabs (Widget shell
,
1515 XtPointer call_data
)
1517 Widget menu
= (Widget
) closure
;
1518 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1522 make_popup_menu (widget_instance
* instance
)
1524 Widget parent
= instance
->parent
;
1525 Window parent_window
= parent
->core
.window
;
1528 /* sets the parent window to 0 to fool Motif into not generating a grab */
1529 parent
->core
.window
= 0;
1530 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1531 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1533 parent
->core
.window
= parent_window
;
1538 make_main (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 ( widget_instance
* instance
)
1679 Widget widget
= instance
->widget
;
1680 /* recycle the dialog boxes */
1681 /* Disable the recycling until we can find a way to have the dialog box
1682 get reasonable layout after we modify its contents. */
1684 && XtClass (widget
) == xmDialogShellWidgetClass
)
1686 destroyed_instance
* dead_instance
=
1687 make_destroyed_instance (instance
->info
->name
,
1688 instance
->info
->type
,
1691 instance
->pop_up_p
);
1692 dead_instance
->next
= all_destroyed_instances
;
1693 all_destroyed_instances
= dead_instance
;
1694 XtUnmanageChild (first_child (instance
->widget
));
1695 XFlush (XtDisplay (instance
->widget
));
1696 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1697 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1701 /* This might not be necessary now that the nosel is attached to
1702 popdown instead of destroy, but it can't hurt. */
1703 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1704 xm_nosel_callback
, (XtPointer
)instance
);
1705 XtDestroyWidget (instance
->widget
);
1709 \f/* popup utility */
1711 xm_popup_menu (Widget widget
, XEvent
*event
)
1713 XButtonPressedEvent dummy
;
1717 dummy
.type
= ButtonPress
;
1719 dummy
.send_event
= 0;
1720 dummy
.display
= XtDisplay (widget
);
1721 dummy
.window
= XtWindow (XtParent (widget
));
1724 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1725 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1726 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1727 event
= (XEvent
*) &dummy
;
1730 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1732 /* Setting the menuPost resource only required by Motif 1.1 and
1733 LessTif 0.84 and earlier. With later versions of LessTif,
1734 setting menuPost is unnecessary and may cause problems, so
1736 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1738 /* This is so totally ridiculous: there's NO WAY to tell Motif
1739 that *any* button can select a menu item. Only one button
1740 can have that honor. */
1743 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1744 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1745 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1746 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1747 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1748 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1752 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1755 XtManageChild (widget
);
1759 set_min_dialog_size (Widget w
)
1763 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1764 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1768 xm_pop_instance (widget_instance
* instance
, Boolean up
)
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 widget
,
1799 enum do_call_type type
)
1803 XtPointer user_data
;
1804 widget_instance
* instance
= (widget_instance
*)closure
;
1805 Widget instance_widget
;
1810 if (widget
->core
.being_destroyed
)
1813 instance_widget
= instance
->widget
;
1814 if (!instance_widget
)
1817 id
= instance
->info
->id
;
1820 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1821 XtGetValues (widget
, al
, ac
);
1826 if (instance
->info
->pre_activate_cb
)
1827 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1831 if (instance
->info
->selection_cb
)
1832 instance
->info
->selection_cb (widget
, id
, user_data
);
1836 if (instance
->info
->selection_cb
)
1837 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1841 if (instance
->info
->post_activate_cb
)
1842 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1850 /* Like lw_internal_update_other_instances except that it does not do
1851 anything if its shell parent is not managed. This is to protect
1852 lw_internal_update_other_instances to dereference freed memory
1853 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1856 xm_internal_update_other_instances (Widget widget
,
1858 XtPointer call_data
)
1861 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1862 if (XtIsShell (parent
))
1864 else if (!XtIsManaged (parent
))
1866 lw_internal_update_other_instances (widget
, closure
, call_data
);
1870 xm_generic_callback (Widget widget
,
1872 XtPointer call_data
)
1874 lw_internal_update_other_instances (widget
, closure
, call_data
);
1875 do_call (widget
, closure
, selection
);
1879 xm_nosel_callback (Widget widget
,
1881 XtPointer call_data
)
1883 /* This callback is only called when a dialog box is dismissed with
1884 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1885 box to be destroyed in that case, not just unmapped, so that it
1886 releases its keyboard grabs. But there are problems with running
1887 our callbacks while the widget is in the process of being
1888 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1889 XmDESTROY and then destroy it ourself after having run the
1891 do_call (widget
, closure
, no_selection
);
1892 XtDestroyWidget (widget
);
1896 xm_pull_down_callback (Widget widget
,
1898 XtPointer call_data
)
1900 Widget parent
= XtParent (widget
);
1902 if (XmIsRowColumn (parent
))
1904 unsigned char type
= 0xff;
1905 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1906 if (type
== XmMENU_BAR
)
1907 do_call (widget
, closure
, pre_activate
);
1912 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1913 CLOSURE is a pointer to the widget_instance of the shell,
1915 Note that this callback is called for each cascade button in a
1916 menu, whether or not its submenu is visible. */
1919 xm_pop_down_callback (Widget widget
,
1921 XtPointer call_data
)
1923 widget_instance
*instance
= (widget_instance
*) closure
;
1925 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1926 || XtParent (widget
) == instance
->parent
)
1927 do_call (widget
, closure
, post_activate
);
1931 /* set the keyboard focus */
1933 xm_set_keyboard_focus (Widget parent
, Widget w
)
1935 XmProcessTraversal (w
, 0);
1936 XtSetKeyboardFocus (parent
, w
);
1939 /* Motif hack to set the main window areas. */
1941 xm_set_main_areas (Widget parent
,
1945 XmMainWindowSetAreas (parent
,
1946 menubar
, /* menubar (maybe 0) */
1947 0, /* command area (psheets) */
1948 0, /* horizontal scroll */
1949 0, /* vertical scroll */
1950 work_area
); /* work area */
1953 /* Motif hack to control resizing on the menubar. */
1955 xm_manage_resizing (Widget w
, Boolean flag
)
1957 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);