1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2012 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. */
29 #include <X11/StringDefs.h>
30 #include <X11/IntrinsicP.h>
31 #include <X11/ObjectP.h>
32 #include <X11/CoreP.h>
33 #include <X11/CompositeP.h>
38 #include "lwlib-utils.h"
40 #include <Xm/BulletinB.h>
41 #include <Xm/CascadeB.h>
42 #include <Xm/CascadeBG.h>
43 #include <Xm/DrawingA.h>
44 #include <Xm/FileSB.h>
48 #include <Xm/MenuShell.h>
49 #include <Xm/MessageB.h>
50 #include <Xm/PanedW.h>
52 #include <Xm/PushBG.h>
53 #include <Xm/ArrowB.h>
54 #include <Xm/SelectioB.h>
57 #include <Xm/ToggleB.h>
58 #include <Xm/ToggleBG.h>
59 #include <Xm/RowColumn.h>
60 #include <Xm/ScrolledW.h>
61 #include <Xm/Separator.h>
62 #include <Xm/DialogS.h>
65 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
68 \f/* Structures to keep destroyed instances */
69 typedef struct _destroyed_instance
76 struct _destroyed_instance
* next
;
79 static destroyed_instance
*make_destroyed_instance (char *, char *,
82 static void free_destroyed_instance (destroyed_instance
*);
83 Widget
first_child (Widget
);
84 Boolean
lw_motif_widget_p (Widget
);
85 static XmString
resource_motif_string (Widget
, char *);
86 static void destroy_all_children (Widget
, int);
87 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
88 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
89 static void xm_update_pushbutton (widget_instance
*, Widget
,
91 static void xm_update_cascadebutton (widget_instance
*, Widget
,
93 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
94 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
95 static void make_menu_in_widget (widget_instance
*, Widget
,
97 static void update_one_menu_entry (widget_instance
*, Widget
,
98 widget_value
*, Boolean
);
99 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
101 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
102 static void xm_update_text_field (widget_instance
*, Widget
,
104 void xm_update_one_value (widget_instance
*, Widget
, widget_value
*);
105 static void activate_button (Widget
, XtPointer
, XtPointer
);
106 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
107 Boolean
, Boolean
, Boolean
, int, int);
108 static destroyed_instance
* find_matching_instance (widget_instance
*);
109 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
110 static void recenter_widget (Widget
);
111 static Widget
recycle_instance (destroyed_instance
*);
112 Widget
xm_create_dialog (widget_instance
*);
113 static Widget
make_menubar (widget_instance
*);
114 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
115 static Widget
make_popup_menu (widget_instance
*);
116 static Widget
make_main (widget_instance
*);
117 void xm_destroy_instance (widget_instance
*);
118 void xm_popup_menu (Widget
, XEvent
*);
119 static void set_min_dialog_size (Widget
);
120 static void do_call (Widget
, XtPointer
, enum do_call_type
);
121 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
122 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
123 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
124 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
125 void xm_set_keyboard_focus (Widget
, Widget
);
126 void xm_set_main_areas (Widget
, Widget
, Widget
);
127 static void xm_internal_update_other_instances (Widget
, XtPointer
,
129 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
132 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
134 void xm_pop_instance (widget_instance
*, Boolean
);
135 void xm_manage_resizing (Widget
, Boolean
);
141 /* Print the complete X resource name of widget WIDGET to stderr.
142 This is sometimes handy to have available. */
145 x_print_complete_resource_name (Widget widget
)
150 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
152 names
[i
] = XtName (widget
);
153 widget
= XtParent (widget
);
156 for (--i
; i
>= 1; --i
)
157 fprintf (stderr
, "%s.", names
[i
]);
158 fprintf (stderr
, "%s\n", names
[0]);
164 static destroyed_instance
*all_destroyed_instances
= NULL
;
166 static destroyed_instance
*
167 make_destroyed_instance (char* name
,
173 destroyed_instance
* instance
=
174 (destroyed_instance
*) xmalloc (sizeof (destroyed_instance
));
175 instance
->name
= safe_strdup (name
);
176 instance
->type
= safe_strdup (type
);
177 instance
->widget
= widget
;
178 instance
->parent
= parent
;
179 instance
->pop_up_p
= pop_up_p
;
180 instance
->next
= NULL
;
185 free_destroyed_instance (destroyed_instance
* instance
)
187 xfree (instance
->name
);
188 xfree (instance
->type
);
192 \f/* motif utility functions */
194 first_child (Widget widget
)
196 return ((CompositeWidget
)widget
)->composite
.children
[0];
200 lw_motif_widget_p (Widget widget
)
203 XtClass (widget
) == xmDialogShellWidgetClass
204 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
208 resource_motif_string (Widget widget
,
214 resource
.resource_name
= name
;
215 resource
.resource_class
= XmCXmString
;
216 resource
.resource_type
= XmRXmString
;
217 resource
.resource_size
= sizeof (XmString
);
218 resource
.resource_offset
= 0;
219 resource
.default_type
= XtRImmediate
;
220 resource
.default_addr
= 0;
222 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
223 "DialogString", &resource
, 1, NULL
, 0);
227 /* Destroy all of the children of WIDGET
228 starting with number FIRST_CHILD_TO_DESTROY. */
231 destroy_all_children (Widget widget
,
232 int first_child_to_destroy
)
238 children
= XtCompositeChildren (widget
, &number
);
241 XtUnmanageChildren (children
+ first_child_to_destroy
,
242 number
- first_child_to_destroy
);
244 /* Unmanage all children and destroy them. They will only be
245 really destroyed when we get out of DispatchEvent. */
246 for (i
= first_child_to_destroy
; i
< number
; i
++)
250 /* Cascade buttons have submenus,and these submenus
251 need to be freed. But they are not included in
252 XtCompositeChildren. So get it out of the cascade button
253 and free it. If this child is not a cascade button,
254 then submenu should remain unchanged. */
255 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
256 XtGetValues (children
[i
], al
, 1);
259 destroy_all_children (submenu
, 0);
260 XtDestroyWidget (submenu
);
262 XtDestroyWidget (children
[i
]);
265 XtFree ((char *) children
);
271 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
272 menu. CLIENT_DATA contains a pointer to the widget_value
273 corresponding to widget W. CALL_DATA contains a
274 XmPushButtonCallbackStruct containing the reason why the callback
278 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
280 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
281 widget_value
*wv
= (widget_value
*) client_data
;
282 widget_instance
*instance
;
284 /* Get the id of the menu bar or popup menu this widget is in. */
287 if (XmIsRowColumn (w
))
289 unsigned char type
= 0xff;
291 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
292 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
301 instance
= lw_get_widget_instance (w
);
302 if (instance
&& instance
->info
->highlight_cb
)
304 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
305 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
312 /* Update the label of widget WIDGET. WIDGET must be a Label widget
313 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
318 Emacs fills VAL->name with the text to display in the menu, and
319 sets VAL->value to null. Function make_menu_in_widget creates
320 widgets with VAL->name as resource name. This works because the
321 Label widget uses its resource name for display if no
322 XmNlabelString is set.
326 VAL->name is again set to the resource name, but VAL->value is
327 not null, and contains the label string to display. */
330 xm_update_label (widget_instance
* instance
,
334 XmString res_string
= 0;
335 XmString built_string
= 0;
336 XmString key_string
= 0;
344 /* A label string is specified, i.e. we are in a dialog. First
345 see if it is overridden by something from the resource file. */
346 res_string
= resource_motif_string (widget
, val
->value
);
350 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
355 XmStringCreateLocalized (val
->value
);
356 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
359 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
364 key_string
= XmStringCreateLocalized (val
->key
);
365 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
369 XtSetValues (widget
, al
, ac
);
372 XmStringFree (built_string
);
375 XmStringFree (key_string
);
378 \f/* update of list */
380 xm_update_list (widget_instance
* instance
,
386 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
387 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
389 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
392 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
394 XmListAddItem (widget
, xmstr
, 0);
396 XmListSelectPos (widget
, i
, False
);
397 XmStringFree (xmstr
);
401 \f/* update of buttons */
403 xm_update_pushbutton (widget_instance
* instance
,
407 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
408 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
409 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
413 xm_update_cascadebutton (widget_instance
* instance
,
417 /* Should also rebuild the menu by calling ...update_menu... */
418 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
419 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
423 \f/* update toggle and radiobox */
425 xm_update_toggle (widget_instance
* instance
,
429 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
430 XtAddCallback (widget
, XmNvalueChangedCallback
,
431 xm_generic_callback
, instance
);
432 XtVaSetValues (widget
, XmNset
, val
->selected
,
433 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
437 xm_update_radiobox (widget_instance
* instance
,
445 /* update the callback */
446 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
447 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
449 /* first update all the toggles */
450 /* Energize kernel interface is currently bad. It sets the selected widget
451 with the selected flag but returns it by its name. So we currently
452 have to support both setting the selection with the selected slot
453 of val contents and setting it with the "value" slot of val. The latter
454 has a higher priority. This to be removed when the kernel is fixed. */
455 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
457 toggle
= XtNameToWidget (widget
, cur
->value
);
460 XtSetSensitive (toggle
, cur
->enabled
);
461 if (!val
->value
&& cur
->selected
)
462 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
463 if (val
->value
&& strcmp (val
->value
, cur
->value
))
464 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
468 /* The selected was specified by the value slot */
471 toggle
= XtNameToWidget (widget
, val
->value
);
473 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
478 /* update a popup menu, pulldown menu or a menubar */
480 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
483 make_menu_in_widget (widget_instance
* instance
,
486 int keep_first_children
)
488 Widget
* children
= 0;
499 Widget
* old_children
;
500 unsigned int old_num_children
;
502 /* Disable drag and drop for labels in menu bar. */
503 static char overrideTrans
[] = "<Btn2Down>: Noop()";
504 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
506 old_children
= XtCompositeChildren (widget
, &old_num_children
);
508 /* Allocate the children array */
509 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
511 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
513 /* WIDGET should be a RowColumn. */
514 if (!XmIsRowColumn (widget
))
517 /* Determine whether WIDGET is a menu bar. */
519 XtSetArg (al
[0], XmNrowColumnType
, &type
);
520 XtGetValues (widget
, al
, 1);
521 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
523 menubar_p
= type
== XmMENU_BAR
;
525 /* Add a callback to popups and pulldowns that is called when
526 it is made invisible again. */
528 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
529 xm_pop_down_callback
, (XtPointer
)instance
);
531 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
532 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
533 child_index
++, cur
= cur
->next
)
534 children
[child_index
] = old_children
[child_index
];
536 /* Check that those are all we have
537 (the caller should have deleted the rest). */
538 if (old_num_children
!= keep_first_children
)
541 /* Create the rest. */
542 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
544 enum menu_separator separator
;
547 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
548 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
549 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
551 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
552 && !lw_separator_p (cur
->name
, &separator
, 1))
555 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
556 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
558 else if (lw_separator_p (cur
->name
, &separator
, 1))
561 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
562 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
564 else if (!cur
->contents
)
567 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
568 else if (!cur
->call_data
)
569 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
570 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
571 || cur
->button_type
== BUTTON_TYPE_RADIO
)
573 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
574 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
575 XtSetArg (al
[ac
], XmNindicatorType
,
576 (cur
->button_type
== BUTTON_TYPE_TOGGLE
577 ? XmN_OF_MANY
: XmONE_OF_MANY
));
579 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
580 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
581 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
585 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
586 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
587 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
590 xm_update_label (instance
, button
, cur
);
592 /* Add a callback that is called when the button is
593 selected. Toggle buttons don't support
594 XmNactivateCallback, we use XmNvalueChangedCallback in
595 that case. Don't add a callback to a simple label. */
596 if (cur
->button_type
)
597 xm_update_toggle (instance
, button
, cur
);
598 else if (cur
->call_data
)
599 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
600 (XtPointer
)instance
);
604 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
606 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
607 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
608 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
610 xm_update_label (instance
, button
, cur
);
612 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
613 (XtPointer
)instance
);
614 XtOverrideTranslations (button
, override
);
618 children
[child_index
] = button
;
621 /* Last entry is the help button. The original comment read "Has to
622 be done after managing the buttons otherwise the menubar is only
623 4 pixels high." This is no longer true, and to make
624 XmNmenuHelpWidget work, we need to set it before managing the
625 children.. --gerd. */
627 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
630 XtManageChildren (children
, num_children
);
632 XtFree ((char *) children
);
634 XtFree ((char *) old_children
);
638 update_one_menu_entry (widget_instance
* instance
,
646 widget_value
* contents
;
648 if (val
->this_one_change
== NO_CHANGE
)
651 /* update the sensitivity and userdata */
652 /* Common to all widget types */
653 XtSetSensitive (widget
, val
->enabled
);
654 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
656 /* update the menu button as a label. */
657 if (val
->this_one_change
>= VISIBLE_CHANGE
)
659 xm_update_label (instance
, widget
, val
);
660 if (val
->button_type
)
661 xm_update_toggle (instance
, widget
, val
);
664 /* update the pulldown/pullaside as needed */
667 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
668 XtGetValues (widget
, al
, ac
);
670 contents
= val
->contents
;
676 unsigned int old_num_children
, i
;
680 parent
= XtParent (widget
);
681 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
683 /* Find the widget position within the parent's widget list. */
684 for (i
= 0; i
< old_num_children
; i
++)
685 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
687 if (i
== old_num_children
)
689 if (XmIsCascadeButton (widget_list
[i
]))
691 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
692 make_menu_in_widget (instance
, menu
, contents
, 0);
694 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
695 XtSetValues (widget
, al
, ac
);
701 /* The current menuitem is a XmPushButtonGadget, it
702 needs to be replaced by a CascadeButtonGadget */
703 XtDestroyWidget (widget_list
[i
]);
704 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
705 make_menu_in_widget (instance
, menu
, contents
, 0);
707 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
708 /* Non-zero values don't work reliably in
709 conjunction with Emacs' event loop */
710 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
711 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
712 /* Tell Motif to put it in the right place */
713 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
715 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
716 xm_update_label (instance
, button
, val
);
718 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
719 (XtPointer
)instance
);
720 XtManageChild (button
);
724 XtFree ((char*) widget_list
);
730 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
731 XtSetValues (widget
, al
, ac
);
732 XtDestroyWidget (menu
);
734 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
735 xm_update_menu (instance
, menu
, val
, 1);
739 xm_update_menu (widget_instance
* instance
,
745 unsigned int num_children
;
746 int num_children_to_keep
= 0;
750 children
= XtCompositeChildren (widget
, &num_children
);
752 /* Widget is a RowColumn widget whose contents have to be updated
753 * to reflect the list of items in val->contents */
755 /* See how many buttons we can keep, and how many we
756 must completely replace. */
757 if (val
->contents
== 0)
758 num_children_to_keep
= 0;
759 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
763 for (i
= 0, cur
= val
->contents
;
765 && cur
); /* how else to ditch unwanted children ?? - mgd */
766 i
++, cur
= cur
->next
)
768 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
772 num_children_to_keep
= i
;
776 num_children_to_keep
= num_children
;
778 /* Update all the buttons of the RowColumn, in order,
779 except for those we are going to replace entirely. */
782 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
786 num_children_to_keep
= i
;
789 if (children
[i
]->core
.being_destroyed
790 || strcmp (XtName (children
[i
]), cur
->name
))
792 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
797 /* Now replace from scratch all the buttons after the last
798 place that the top-level structure changed. */
799 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
801 destroy_all_children (widget
, num_children_to_keep
);
802 make_menu_in_widget (instance
, widget
, val
->contents
,
803 num_children_to_keep
);
806 XtFree ((char *) children
);
810 /* update text widgets */
813 xm_update_text (widget_instance
* instance
,
817 XmTextSetString (widget
, val
->value
? val
->value
: "");
818 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
819 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
820 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
821 XtAddCallback (widget
, XmNvalueChangedCallback
,
822 xm_internal_update_other_instances
, instance
);
826 xm_update_text_field (widget_instance
* instance
,
830 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
831 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
832 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
833 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
834 XtAddCallback (widget
, XmNvalueChangedCallback
,
835 xm_internal_update_other_instances
, instance
);
839 /* update a motif widget */
842 xm_update_one_widget (widget_instance
* instance
,
849 /* Mark as not edited */
852 /* Common to all widget types */
853 XtSetSensitive (widget
, val
->enabled
);
854 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
856 /* Common to all label like widgets */
857 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
858 xm_update_label (instance
, widget
, val
);
860 class = XtClass (widget
);
861 /* Class specific things */
862 if (class == xmPushButtonWidgetClass
||
863 class == xmArrowButtonWidgetClass
)
865 xm_update_pushbutton (instance
, widget
, val
);
867 else if (class == xmCascadeButtonWidgetClass
)
869 xm_update_cascadebutton (instance
, widget
, val
);
871 else if (class == xmToggleButtonWidgetClass
872 || class == xmToggleButtonGadgetClass
)
874 xm_update_toggle (instance
, widget
, val
);
876 else if (class == xmRowColumnWidgetClass
)
878 Boolean radiobox
= 0;
882 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
883 XtGetValues (widget
, al
, ac
);
886 xm_update_radiobox (instance
, widget
, val
);
888 xm_update_menu (instance
, widget
, val
, deep_p
);
890 else if (class == xmTextWidgetClass
)
892 xm_update_text (instance
, widget
, val
);
894 else if (class == xmTextFieldWidgetClass
)
896 xm_update_text_field (instance
, widget
, val
);
898 else if (class == xmListWidgetClass
)
900 xm_update_list (instance
, widget
, val
);
904 \f/* getting the value back */
906 xm_update_one_value (widget_instance
* instance
,
910 WidgetClass
class = XtClass (widget
);
911 widget_value
*old_wv
;
913 /* copy the call_data slot into the "return" widget_value */
914 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
915 if (!strcmp (val
->name
, old_wv
->name
))
917 val
->call_data
= old_wv
->call_data
;
921 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
923 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
926 else if (class == xmTextWidgetClass
)
929 val
->value
= XmTextGetString (widget
);
932 else if (class == xmTextFieldWidgetClass
)
935 val
->value
= XmTextFieldGetString (widget
);
938 else if (class == xmRowColumnWidgetClass
)
940 Boolean radiobox
= 0;
944 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
945 XtGetValues (widget
, al
, ac
);
949 CompositeWidget radio
= (CompositeWidget
)widget
;
951 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
954 Widget toggle
= radio
->composite
.children
[i
];
956 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
960 val
->value
= safe_strdup (XtName (toggle
));
966 else if (class == xmListWidgetClass
)
970 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
974 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
978 cur
->selected
= False
;
980 for (j
= 0; j
< pos_cnt
; j
++)
981 if (pos_list
[j
] == i
)
983 cur
->selected
= True
;
984 val
->value
= safe_strdup (cur
->name
);
988 XtFree ((char *) pos_list
);
994 /* This function is for activating a button from a program. It's wrong because
995 we pass a NULL argument in the call_data which is not Motif compatible.
996 This is used from the XmNdefaultAction callback of the List widgets to
997 have a double-click put down a dialog box like the button would do.
998 I could not find a way to do that with accelerators.
1001 activate_button (Widget widget
,
1003 XtPointer call_data
)
1005 Widget button
= (Widget
)closure
;
1006 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1009 /* creation functions */
1011 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1013 dialog_key_cb (Widget widget
,
1016 Boolean
*continue_to_dispatch
)
1019 Modifiers modif_ret
;
1021 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1024 if (sym
== osfXK_Cancel
)
1026 Widget w
= *((Widget
*) closure
);
1028 while (w
&& ! XtIsShell (w
))
1031 if (XtIsShell (w
)) XtPopdown (w
);
1034 *continue_to_dispatch
= TRUE
;
1039 make_dialog (char* name
,
1044 Boolean text_input_slot
,
1054 Widget icon_separator
;
1055 Widget message_label
;
1059 Widget children
[16]; /* for the final XtManageChildren */
1061 Arg al
[64]; /* Arg List */
1062 int ac
; /* Arg Count */
1068 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1069 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1070 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1071 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1073 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1074 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1075 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1076 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1081 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1082 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1083 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1087 n_children
= left_buttons
+ right_buttons
+ 1;
1089 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1090 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1091 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1092 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1093 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1094 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1095 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1096 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1097 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1098 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1099 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1100 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1101 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1102 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1103 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1104 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1105 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1106 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1107 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1110 for (i
= 0; i
< left_buttons
; i
++)
1112 char button_name
[16];
1113 sprintf (button_name
, "button%d", i
+ 1);
1117 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1118 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1120 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1121 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1122 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1123 XtAddEventHandler (children
[n_children
],
1124 KeyPressMask
, False
, dialog_key_cb
, result
);
1128 button
= children
[n_children
];
1130 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1131 XtSetValues (row
, al
, ac
);
1137 /* invisible separator button */
1139 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1140 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1143 for (i
= 0; i
< right_buttons
; i
++)
1145 char button_name
[16];
1146 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1148 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1149 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1150 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1151 XtAddEventHandler (children
[n_children
],
1152 KeyPressMask
, False
, dialog_key_cb
, result
);
1154 if (! button
) button
= children
[n_children
];
1158 XtManageChildren (children
, n_children
);
1161 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1162 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1163 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1164 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1165 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1167 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1168 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1169 separator
= XmCreateSeparator (form
, "", al
, ac
);
1172 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1173 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1174 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1175 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1176 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1177 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1178 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1179 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1182 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1183 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1184 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1185 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1186 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1187 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1188 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1189 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1190 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1191 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1193 if (text_input_slot
)
1196 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1197 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1198 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1199 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1200 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1201 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1202 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1203 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1204 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1205 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1206 value
= XmCreateTextField (form
, "value", al
, ac
);
1212 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1213 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1214 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1215 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1216 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1217 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1218 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1219 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1220 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1221 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1222 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1223 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1224 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1225 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1228 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1229 children
[i
++] = radio_butt
;
1230 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1231 children
[i
++] = radio_butt
;
1232 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1233 children
[i
++] = radio_butt
;
1234 XtManageChildren (children
, i
);
1239 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1240 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1241 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1242 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1243 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1244 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1245 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1246 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1247 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1248 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1249 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1251 /* this is the easiest way I found to have the dble click in the
1252 list activate the default button */
1253 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1257 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1258 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1259 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1260 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1261 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1262 XtSetArg(al
[ac
], XmNbottomWidget
,
1263 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1264 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1265 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1266 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1267 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1268 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1269 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1272 XtManageChild (value
);
1275 children
[i
] = row
; i
++;
1276 children
[i
] = separator
; i
++;
1277 if (text_input_slot
|| radio_box
)
1279 children
[i
] = value
; i
++;
1281 children
[i
] = message_label
; i
++;
1282 children
[i
] = icon
; i
++;
1283 children
[i
] = icon_separator
; i
++;
1284 XtManageChildren (children
, i
);
1286 if (text_input_slot
|| list
)
1288 XtInstallAccelerators (value
, button
);
1289 XtSetKeyboardFocus (result
, value
);
1293 XtInstallAccelerators (form
, button
);
1294 XtSetKeyboardFocus (result
, button
);
1300 static destroyed_instance
*
1301 find_matching_instance (widget_instance
* instance
)
1303 destroyed_instance
* cur
;
1304 destroyed_instance
* prev
;
1305 char* type
= instance
->info
->type
;
1306 char* name
= instance
->info
->name
;
1308 for (prev
= NULL
, cur
= all_destroyed_instances
;
1310 prev
= cur
, cur
= cur
->next
)
1312 if (!strcmp (cur
->name
, name
)
1313 && !strcmp (cur
->type
, type
)
1314 && cur
->parent
== instance
->parent
1315 && cur
->pop_up_p
== instance
->pop_up_p
)
1318 prev
->next
= cur
->next
;
1320 all_destroyed_instances
= cur
->next
;
1323 /* do some cleanup */
1324 else if (!cur
->widget
)
1327 prev
->next
= cur
->next
;
1329 all_destroyed_instances
= cur
->next
;
1330 free_destroyed_instance (cur
);
1331 cur
= prev
? prev
: all_destroyed_instances
;
1338 mark_dead_instance_destroyed (Widget widget
,
1340 XtPointer call_data
)
1342 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1343 instance
->widget
= NULL
;
1347 recenter_widget (Widget widget
)
1349 Widget parent
= XtParent (widget
);
1350 Screen
* screen
= XtScreen (widget
);
1351 Dimension screen_width
= WidthOfScreen (screen
);
1352 Dimension screen_height
= HeightOfScreen (screen
);
1353 Dimension parent_width
= 0;
1354 Dimension parent_height
= 0;
1355 Dimension child_width
= 0;
1356 Dimension child_height
= 0;
1360 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1361 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1364 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1365 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1367 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1369 if (x
+ child_width
> screen_width
)
1370 x
= screen_width
- child_width
;
1374 if (y
+ child_height
> screen_height
)
1375 y
= screen_height
- child_height
;
1379 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1383 recycle_instance (destroyed_instance
* instance
)
1385 Widget widget
= instance
->widget
;
1387 /* widget is NULL if the parent was destroyed. */
1393 /* Remove the destroy callback as the instance is not in the list
1395 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1396 mark_dead_instance_destroyed
,
1397 (XtPointer
)instance
);
1399 /* Give the focus to the initial item */
1400 focus
= XtNameToWidget (widget
, "*value");
1402 focus
= XtNameToWidget (widget
, "*button1");
1404 XtSetKeyboardFocus (widget
, focus
);
1406 /* shrink the separator label back to their original size */
1407 separator
= XtNameToWidget (widget
, "*separator_button");
1409 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1411 /* Center the dialog in its parent */
1412 recenter_widget (widget
);
1414 free_destroyed_instance (instance
);
1419 xm_create_dialog (widget_instance
* instance
)
1421 char* name
= instance
->info
->type
;
1422 Widget parent
= instance
->parent
;
1424 Boolean pop_up_p
= instance
->pop_up_p
;
1425 char* shell_name
= 0;
1426 char* icon_name
= 0;
1427 Boolean text_input_slot
= False
;
1428 Boolean radio_box
= False
;
1429 Boolean list
= False
;
1431 int left_buttons
= 0;
1432 int right_buttons
= 1;
1433 destroyed_instance
* dead_one
;
1435 /* try to find a widget to recycle */
1436 dead_one
= find_matching_instance (instance
);
1439 Widget recycled_widget
= recycle_instance (dead_one
);
1440 if (recycled_widget
)
1441 return recycled_widget
;
1446 icon_name
= "dbox-error";
1447 shell_name
= "Error";
1451 icon_name
= "dbox-info";
1452 shell_name
= "Information";
1457 icon_name
= "dbox-question";
1458 shell_name
= "Prompt";
1462 text_input_slot
= True
;
1463 icon_name
= "dbox-question";
1464 shell_name
= "Prompt";
1468 icon_name
= "dbox-question";
1469 shell_name
= "Question";
1473 total_buttons
= name
[1] - '0';
1475 if (name
[3] == 'T' || name
[3] == 't')
1477 text_input_slot
= False
;
1481 right_buttons
= name
[4] - '0';
1483 left_buttons
= total_buttons
- right_buttons
;
1485 widget
= make_dialog (name
, parent
, pop_up_p
,
1486 shell_name
, icon_name
, text_input_slot
, radio_box
,
1487 list
, left_buttons
, right_buttons
);
1489 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1490 (XtPointer
) instance
);
1495 /* Create a menu bar. We turn off the f10 key
1496 because we have not yet managed to make it work right in Motif. */
1499 make_menubar (widget_instance
* instance
)
1505 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1506 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1510 remove_grabs (Widget shell
,
1512 XtPointer call_data
)
1514 Widget menu
= (Widget
) closure
;
1515 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1519 make_popup_menu (widget_instance
* instance
)
1521 Widget parent
= instance
->parent
;
1522 Window parent_window
= parent
->core
.window
;
1525 /* sets the parent window to 0 to fool Motif into not generating a grab */
1526 parent
->core
.window
= 0;
1527 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1528 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1530 parent
->core
.window
= parent_window
;
1535 make_main (widget_instance
* instance
)
1537 Widget parent
= instance
->parent
;
1543 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1544 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1545 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1549 \f/* Table of functions to create widgets */
1553 /* interface with the XDesigner generated functions */
1554 typedef Widget (*widget_maker
) (Widget
);
1555 extern Widget
create_project_p_sheet (Widget parent
);
1556 extern Widget
create_debugger_p_sheet (Widget parent
);
1557 extern Widget
create_breaklist_p_sheet (Widget parent
);
1558 extern Widget
create_le_browser_p_sheet (Widget parent
);
1559 extern Widget
create_class_browser_p_sheet (Widget parent
);
1560 extern Widget
create_call_browser_p_sheet (Widget parent
);
1561 extern Widget
create_build_dialog (Widget parent
);
1562 extern Widget
create_editmode_dialog (Widget parent
);
1563 extern Widget
create_search_dialog (Widget parent
);
1564 extern Widget
create_project_display_dialog (Widget parent
);
1567 make_one (widget_instance
* instance
, widget_maker fn
)
1573 if (instance
->pop_up_p
)
1575 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1576 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1577 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1578 (XtPointer
) instance
);
1583 result
= (*fn
) (instance
->parent
);
1584 XtRealizeWidget (result
);
1590 make_project_p_sheet (widget_instance
* instance
)
1592 return make_one (instance
, create_project_p_sheet
);
1596 make_debugger_p_sheet (widget_instance
* instance
)
1598 return make_one (instance
, create_debugger_p_sheet
);
1602 make_breaklist_p_sheet (widget_instance
* instance
)
1604 return make_one (instance
, create_breaklist_p_sheet
);
1608 make_le_browser_p_sheet (widget_instance
* instance
)
1610 return make_one (instance
, create_le_browser_p_sheet
);
1614 make_class_browser_p_sheet (widget_instance
* instance
)
1616 return make_one (instance
, create_class_browser_p_sheet
);
1620 make_call_browser_p_sheet (widget_instance
* instance
)
1622 return make_one (instance
, create_call_browser_p_sheet
);
1626 make_build_dialog (widget_instance
* instance
)
1628 return make_one (instance
, create_build_dialog
);
1632 make_editmode_dialog (widget_instance
* instance
)
1634 return make_one (instance
, create_editmode_dialog
);
1638 make_search_dialog (widget_instance
* instance
)
1640 return make_one (instance
, create_search_dialog
);
1644 make_project_display_dialog (widget_instance
* instance
)
1646 return make_one (instance
, create_project_display_dialog
);
1649 #endif /* ENERGIZE */
1651 widget_creation_entry
1652 xm_creation_table
[] =
1654 {"menubar", make_menubar
},
1655 {"popup", make_popup_menu
},
1656 {"main", make_main
},
1658 {"project_p_sheet", make_project_p_sheet
},
1659 {"debugger_p_sheet", make_debugger_p_sheet
},
1660 {"breaklist_psheet", make_breaklist_p_sheet
},
1661 {"leb_psheet", make_le_browser_p_sheet
},
1662 {"class_browser_psheet", make_class_browser_p_sheet
},
1663 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1664 {"build", make_build_dialog
},
1665 {"editmode", make_editmode_dialog
},
1666 {"search", make_search_dialog
},
1667 {"project_display", make_project_display_dialog
},
1668 #endif /* ENERGIZE */
1672 \f/* Destruction of instances */
1674 xm_destroy_instance ( widget_instance
* instance
)
1676 Widget widget
= instance
->widget
;
1677 /* recycle the dialog boxes */
1678 /* Disable the recycling until we can find a way to have the dialog box
1679 get reasonable layout after we modify its contents. */
1681 && XtClass (widget
) == xmDialogShellWidgetClass
)
1683 destroyed_instance
* dead_instance
=
1684 make_destroyed_instance (instance
->info
->name
,
1685 instance
->info
->type
,
1688 instance
->pop_up_p
);
1689 dead_instance
->next
= all_destroyed_instances
;
1690 all_destroyed_instances
= dead_instance
;
1691 XtUnmanageChild (first_child (instance
->widget
));
1692 XFlush (XtDisplay (instance
->widget
));
1693 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1694 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1698 /* This might not be necessary now that the nosel is attached to
1699 popdown instead of destroy, but it can't hurt. */
1700 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1701 xm_nosel_callback
, (XtPointer
)instance
);
1702 XtDestroyWidget (instance
->widget
);
1706 \f/* popup utility */
1708 xm_popup_menu (Widget widget
, XEvent
*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 (Widget w
)
1760 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1761 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1765 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1767 Widget widget
= instance
->widget
;
1769 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1771 Widget widget_to_manage
= first_child (widget
);
1774 XtManageChild (widget_to_manage
);
1775 set_min_dialog_size (widget
);
1776 XtSetKeyboardFocus (instance
->parent
, widget
);
1779 XtUnmanageChild (widget_to_manage
);
1784 XtManageChild (widget
);
1786 XtUnmanageChild (widget
);
1791 /* motif callback */
1794 do_call (Widget widget
,
1796 enum do_call_type type
)
1800 XtPointer user_data
;
1801 widget_instance
* instance
= (widget_instance
*)closure
;
1802 Widget instance_widget
;
1807 if (widget
->core
.being_destroyed
)
1810 instance_widget
= instance
->widget
;
1811 if (!instance_widget
)
1814 id
= instance
->info
->id
;
1817 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1818 XtGetValues (widget
, al
, ac
);
1823 if (instance
->info
->pre_activate_cb
)
1824 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1828 if (instance
->info
->selection_cb
)
1829 instance
->info
->selection_cb (widget
, id
, user_data
);
1833 if (instance
->info
->selection_cb
)
1834 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1838 if (instance
->info
->post_activate_cb
)
1839 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1847 /* Like lw_internal_update_other_instances except that it does not do
1848 anything if its shell parent is not managed. This is to protect
1849 lw_internal_update_other_instances to dereference freed memory
1850 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1853 xm_internal_update_other_instances (Widget widget
,
1855 XtPointer call_data
)
1858 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1859 if (XtIsShell (parent
))
1861 else if (!XtIsManaged (parent
))
1863 lw_internal_update_other_instances (widget
, closure
, call_data
);
1867 xm_generic_callback (Widget widget
,
1869 XtPointer call_data
)
1871 lw_internal_update_other_instances (widget
, closure
, call_data
);
1872 do_call (widget
, closure
, selection
);
1876 xm_nosel_callback (Widget widget
,
1878 XtPointer call_data
)
1880 /* This callback is only called when a dialog box is dismissed with
1881 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1882 box to be destroyed in that case, not just unmapped, so that it
1883 releases its keyboard grabs. But there are problems with running
1884 our callbacks while the widget is in the process of being
1885 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1886 XmDESTROY and then destroy it ourself after having run the
1888 do_call (widget
, closure
, no_selection
);
1889 XtDestroyWidget (widget
);
1893 xm_pull_down_callback (Widget widget
,
1895 XtPointer call_data
)
1897 Widget parent
= XtParent (widget
);
1899 if (XmIsRowColumn (parent
))
1901 unsigned char type
= 0xff;
1902 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1903 if (type
== XmMENU_BAR
)
1904 do_call (widget
, closure
, pre_activate
);
1909 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1910 CLOSURE is a pointer to the widget_instance of the shell,
1912 Note that this callback is called for each cascade button in a
1913 menu, whether or not its submenu is visible. */
1916 xm_pop_down_callback (Widget widget
,
1918 XtPointer call_data
)
1920 widget_instance
*instance
= (widget_instance
*) closure
;
1922 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1923 || XtParent (widget
) == instance
->parent
)
1924 do_call (widget
, closure
, post_activate
);
1928 /* set the keyboard focus */
1930 xm_set_keyboard_focus (Widget parent
, Widget w
)
1932 XmProcessTraversal (w
, 0);
1933 XtSetKeyboardFocus (parent
, w
);
1936 /* Motif hack to set the main window areas. */
1938 xm_set_main_areas (Widget parent
,
1942 XmMainWindowSetAreas (parent
,
1943 menubar
, /* menubar (maybe 0) */
1944 0, /* command area (psheets) */
1945 0, /* horizontal scroll */
1946 0, /* vertical scroll */
1947 work_area
); /* work area */
1950 /* Motif hack to control resizing on the menubar. */
1952 xm_manage_resizing (Widget w
, Boolean flag
)
1954 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);