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;
500 Widget
* old_children
;
501 unsigned int old_num_children
;
503 /* Disable drag and drop for labels in menu bar. */
504 static char overrideTrans
[] = "<Btn2Down>: Noop()";
505 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
507 old_children
= XtCompositeChildren (widget
, &old_num_children
);
509 /* Allocate the children array */
510 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
512 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
514 /* WIDGET should be a RowColumn. */
515 if (!XmIsRowColumn (widget
))
518 /* Determine whether WIDGET is a menu bar. */
520 XtSetArg (al
[0], XmNrowColumnType
, &type
);
521 XtGetValues (widget
, al
, 1);
522 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
524 menubar_p
= type
== XmMENU_BAR
;
526 /* Add a callback to popups and pulldowns that is called when
527 it is made invisible again. */
529 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
530 xm_pop_down_callback
, (XtPointer
)instance
);
532 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
533 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
534 child_index
++, cur
= cur
->next
)
535 children
[child_index
] = old_children
[child_index
];
537 /* Check that those are all we have
538 (the caller should have deleted the rest). */
539 if (old_num_children
!= keep_first_children
)
542 /* Create the rest. */
543 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
545 enum menu_separator separator
;
548 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
549 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
550 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
552 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
553 && !lw_separator_p (cur
->name
, &separator
, 1))
556 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
557 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
559 else if (lw_separator_p (cur
->name
, &separator
, 1))
562 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
563 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
565 else if (!cur
->contents
)
568 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
569 else if (!cur
->call_data
)
570 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
571 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
572 || cur
->button_type
== BUTTON_TYPE_RADIO
)
574 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
575 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
576 XtSetArg (al
[ac
], XmNindicatorType
,
577 (cur
->button_type
== BUTTON_TYPE_TOGGLE
578 ? XmN_OF_MANY
: XmONE_OF_MANY
));
580 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
581 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
582 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
586 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
587 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
588 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
591 xm_update_label (instance
, button
, cur
);
593 /* Add a callback that is called when the button is
594 selected. Toggle buttons don't support
595 XmNactivateCallback, we use XmNvalueChangedCallback in
596 that case. Don't add a callback to a simple label. */
597 if (cur
->button_type
)
598 xm_update_toggle (instance
, button
, cur
);
599 else if (cur
->call_data
)
600 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
601 (XtPointer
)instance
);
605 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
607 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
608 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
609 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
611 xm_update_label (instance
, button
, cur
);
613 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
614 (XtPointer
)instance
);
615 XtOverrideTranslations (button
, override
);
619 children
[child_index
] = button
;
622 /* Last entry is the help button. The original comment read "Has to
623 be done after managing the buttons otherwise the menubar is only
624 4 pixels high." This is no longer true, and to make
625 XmNmenuHelpWidget work, we need to set it before managing the
626 children.. --gerd. */
628 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
631 XtManageChildren (children
, num_children
);
633 XtFree ((char *) children
);
635 XtFree ((char *) old_children
);
639 update_one_menu_entry (widget_instance
* instance
,
647 widget_value
* contents
;
649 if (val
->this_one_change
== NO_CHANGE
)
652 /* update the sensitivity and userdata */
653 /* Common to all widget types */
654 XtSetSensitive (widget
, val
->enabled
);
655 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
657 /* update the menu button as a label. */
658 if (val
->this_one_change
>= VISIBLE_CHANGE
)
660 xm_update_label (instance
, widget
, val
);
661 if (val
->button_type
)
662 xm_update_toggle (instance
, widget
, val
);
665 /* update the pulldown/pullaside as needed */
668 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
669 XtGetValues (widget
, al
, ac
);
671 contents
= val
->contents
;
677 unsigned int old_num_children
, i
;
681 parent
= XtParent (widget
);
682 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
684 /* Find the widget position within the parent's widget list. */
685 for (i
= 0; i
< old_num_children
; i
++)
686 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
688 if (i
== old_num_children
)
690 if (XmIsCascadeButton (widget_list
[i
]))
692 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
693 make_menu_in_widget (instance
, menu
, contents
, 0);
695 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
696 XtSetValues (widget
, al
, ac
);
702 /* The current menuitem is a XmPushButtonGadget, it
703 needs to be replaced by a CascadeButtonGadget */
704 XtDestroyWidget (widget_list
[i
]);
705 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
706 make_menu_in_widget (instance
, menu
, contents
, 0);
708 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
709 /* Non-zero values don't work reliably in
710 conjunction with Emacs' event loop */
711 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
712 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
713 /* Tell Motif to put it in the right place */
714 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
716 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
717 xm_update_label (instance
, button
, val
);
719 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
720 (XtPointer
)instance
);
721 XtManageChild (button
);
725 XtFree ((char*) widget_list
);
731 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
732 XtSetValues (widget
, al
, ac
);
733 XtDestroyWidget (menu
);
735 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
736 xm_update_menu (instance
, menu
, val
, 1);
740 xm_update_menu (widget_instance
* instance
,
746 unsigned int num_children
;
747 int num_children_to_keep
= 0;
751 children
= XtCompositeChildren (widget
, &num_children
);
753 /* Widget is a RowColumn widget whose contents have to be updated
754 * to reflect the list of items in val->contents */
756 /* See how many buttons we can keep, and how many we
757 must completely replace. */
758 if (val
->contents
== 0)
759 num_children_to_keep
= 0;
760 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
764 for (i
= 0, cur
= val
->contents
;
766 && cur
); /* how else to ditch unwanted children ?? - mgd */
767 i
++, cur
= cur
->next
)
769 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
773 num_children_to_keep
= i
;
777 num_children_to_keep
= num_children
;
779 /* Update all the buttons of the RowColumn, in order,
780 except for those we are going to replace entirely. */
783 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
787 num_children_to_keep
= i
;
790 if (children
[i
]->core
.being_destroyed
791 || strcmp (XtName (children
[i
]), cur
->name
))
793 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
798 /* Now replace from scratch all the buttons after the last
799 place that the top-level structure changed. */
800 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
802 destroy_all_children (widget
, num_children_to_keep
);
803 make_menu_in_widget (instance
, widget
, val
->contents
,
804 num_children_to_keep
);
807 XtFree ((char *) children
);
811 /* update text widgets */
814 xm_update_text (widget_instance
* instance
,
818 XmTextSetString (widget
, val
->value
? val
->value
: "");
819 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
820 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
821 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
822 XtAddCallback (widget
, XmNvalueChangedCallback
,
823 xm_internal_update_other_instances
, instance
);
827 xm_update_text_field (widget_instance
* instance
,
831 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
832 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
833 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
834 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
835 XtAddCallback (widget
, XmNvalueChangedCallback
,
836 xm_internal_update_other_instances
, instance
);
840 /* update a motif widget */
843 xm_update_one_widget (widget_instance
* instance
,
850 /* Mark as not edited */
853 /* Common to all widget types */
854 XtSetSensitive (widget
, val
->enabled
);
855 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
857 /* Common to all label like widgets */
858 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
859 xm_update_label (instance
, widget
, val
);
861 class = XtClass (widget
);
862 /* Class specific things */
863 if (class == xmPushButtonWidgetClass
||
864 class == xmArrowButtonWidgetClass
)
866 xm_update_pushbutton (instance
, widget
, val
);
868 else if (class == xmCascadeButtonWidgetClass
)
870 xm_update_cascadebutton (instance
, widget
, val
);
872 else if (class == xmToggleButtonWidgetClass
873 || class == xmToggleButtonGadgetClass
)
875 xm_update_toggle (instance
, widget
, val
);
877 else if (class == xmRowColumnWidgetClass
)
879 Boolean radiobox
= 0;
883 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
884 XtGetValues (widget
, al
, ac
);
887 xm_update_radiobox (instance
, widget
, val
);
889 xm_update_menu (instance
, widget
, val
, deep_p
);
891 else if (class == xmTextWidgetClass
)
893 xm_update_text (instance
, widget
, val
);
895 else if (class == xmTextFieldWidgetClass
)
897 xm_update_text_field (instance
, widget
, val
);
899 else if (class == xmListWidgetClass
)
901 xm_update_list (instance
, widget
, val
);
905 \f/* getting the value back */
907 xm_update_one_value (widget_instance
* instance
,
911 WidgetClass
class = XtClass (widget
);
912 widget_value
*old_wv
;
914 /* copy the call_data slot into the "return" widget_value */
915 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
916 if (!strcmp (val
->name
, old_wv
->name
))
918 val
->call_data
= old_wv
->call_data
;
922 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
924 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
927 else if (class == xmTextWidgetClass
)
930 val
->value
= XmTextGetString (widget
);
933 else if (class == xmTextFieldWidgetClass
)
936 val
->value
= XmTextFieldGetString (widget
);
939 else if (class == xmRowColumnWidgetClass
)
941 Boolean radiobox
= 0;
945 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
946 XtGetValues (widget
, al
, ac
);
950 CompositeWidget radio
= (CompositeWidget
)widget
;
952 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
955 Widget toggle
= radio
->composite
.children
[i
];
957 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
961 val
->value
= safe_strdup (XtName (toggle
));
967 else if (class == xmListWidgetClass
)
971 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
975 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
979 cur
->selected
= False
;
981 for (j
= 0; j
< pos_cnt
; j
++)
982 if (pos_list
[j
] == i
)
984 cur
->selected
= True
;
985 val
->value
= safe_strdup (cur
->name
);
989 XtFree ((char *) pos_list
);
995 /* This function is for activating a button from a program. It's wrong because
996 we pass a NULL argument in the call_data which is not Motif compatible.
997 This is used from the XmNdefaultAction callback of the List widgets to
998 have a double-click put down a dialog box like the button would do.
999 I could not find a way to do that with accelerators.
1002 activate_button (Widget widget
,
1004 XtPointer call_data
)
1006 Widget button
= (Widget
)closure
;
1007 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1010 /* creation functions */
1012 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1014 dialog_key_cb (Widget widget
,
1017 Boolean
*continue_to_dispatch
)
1020 Modifiers modif_ret
;
1022 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1025 if (sym
== osfXK_Cancel
)
1027 Widget w
= *((Widget
*) closure
);
1029 while (w
&& ! XtIsShell (w
))
1032 if (XtIsShell (w
)) XtPopdown (w
);
1035 *continue_to_dispatch
= TRUE
;
1040 make_dialog (char* name
,
1045 Boolean text_input_slot
,
1055 Widget icon_separator
;
1056 Widget message_label
;
1060 Widget children
[16]; /* for the final XtManageChildren */
1062 Arg al
[64]; /* Arg List */
1063 int ac
; /* Arg Count */
1069 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1070 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1071 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1072 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1074 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1075 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1076 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1077 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1082 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1083 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1084 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1088 n_children
= left_buttons
+ right_buttons
+ 1;
1090 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1091 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1092 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1093 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1094 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1095 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1096 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1097 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1098 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1099 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1100 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1101 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1102 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1103 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1104 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1105 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1106 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1107 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1108 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1111 for (i
= 0; i
< left_buttons
; i
++)
1113 char button_name
[16];
1114 sprintf (button_name
, "button%d", i
+ 1);
1118 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1119 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1121 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1122 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1123 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1124 XtAddEventHandler (children
[n_children
],
1125 KeyPressMask
, False
, dialog_key_cb
, result
);
1129 button
= children
[n_children
];
1131 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1132 XtSetValues (row
, al
, ac
);
1138 /* invisible separator button */
1140 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1141 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1144 for (i
= 0; i
< right_buttons
; i
++)
1146 char button_name
[16];
1147 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1149 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1150 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1151 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1152 XtAddEventHandler (children
[n_children
],
1153 KeyPressMask
, False
, dialog_key_cb
, result
);
1155 if (! button
) button
= children
[n_children
];
1159 XtManageChildren (children
, n_children
);
1162 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1163 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1164 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1165 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1166 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1167 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1168 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1169 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1170 separator
= XmCreateSeparator (form
, "", al
, ac
);
1173 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1174 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1175 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1176 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1177 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1178 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1179 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1180 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1183 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1184 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1185 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1186 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1187 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1188 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1189 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1190 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1191 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1192 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1194 if (text_input_slot
)
1197 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1198 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1199 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1200 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1201 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1202 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1203 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1204 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1205 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1206 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1207 value
= XmCreateTextField (form
, "value", al
, ac
);
1213 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1214 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1215 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1216 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1217 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1218 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1219 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1220 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1221 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1222 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1223 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1224 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1225 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1226 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1229 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1230 children
[i
++] = radio_butt
;
1231 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1232 children
[i
++] = radio_butt
;
1233 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1234 children
[i
++] = radio_butt
;
1235 XtManageChildren (children
, i
);
1240 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1241 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1242 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1243 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1244 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1245 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1246 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1247 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1248 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1249 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1250 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1252 /* this is the easiest way I found to have the dble click in the
1253 list activate the default button */
1254 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1258 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1259 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1260 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1261 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1262 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1263 XtSetArg(al
[ac
], XmNbottomWidget
,
1264 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1265 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1266 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1267 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1268 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1269 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1270 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1273 XtManageChild (value
);
1276 children
[i
] = row
; i
++;
1277 children
[i
] = separator
; i
++;
1278 if (text_input_slot
|| radio_box
)
1280 children
[i
] = value
; i
++;
1282 children
[i
] = message_label
; i
++;
1283 children
[i
] = icon
; i
++;
1284 children
[i
] = icon_separator
; i
++;
1285 XtManageChildren (children
, i
);
1287 if (text_input_slot
|| list
)
1289 XtInstallAccelerators (value
, button
);
1290 XtSetKeyboardFocus (result
, value
);
1294 XtInstallAccelerators (form
, button
);
1295 XtSetKeyboardFocus (result
, button
);
1301 static destroyed_instance
*
1302 find_matching_instance (widget_instance
* instance
)
1304 destroyed_instance
* cur
;
1305 destroyed_instance
* prev
;
1306 char* type
= instance
->info
->type
;
1307 char* name
= instance
->info
->name
;
1309 for (prev
= NULL
, cur
= all_destroyed_instances
;
1311 prev
= cur
, cur
= cur
->next
)
1313 if (!strcmp (cur
->name
, name
)
1314 && !strcmp (cur
->type
, type
)
1315 && cur
->parent
== instance
->parent
1316 && cur
->pop_up_p
== instance
->pop_up_p
)
1319 prev
->next
= cur
->next
;
1321 all_destroyed_instances
= cur
->next
;
1324 /* do some cleanup */
1325 else if (!cur
->widget
)
1328 prev
->next
= cur
->next
;
1330 all_destroyed_instances
= cur
->next
;
1331 free_destroyed_instance (cur
);
1332 cur
= prev
? prev
: all_destroyed_instances
;
1339 mark_dead_instance_destroyed (Widget widget
,
1341 XtPointer call_data
)
1343 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1344 instance
->widget
= NULL
;
1348 recenter_widget (Widget widget
)
1350 Widget parent
= XtParent (widget
);
1351 Screen
* screen
= XtScreen (widget
);
1352 Dimension screen_width
= WidthOfScreen (screen
);
1353 Dimension screen_height
= HeightOfScreen (screen
);
1354 Dimension parent_width
= 0;
1355 Dimension parent_height
= 0;
1356 Dimension child_width
= 0;
1357 Dimension child_height
= 0;
1361 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1362 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1365 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1366 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1368 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1370 if (x
+ child_width
> screen_width
)
1371 x
= screen_width
- child_width
;
1375 if (y
+ child_height
> screen_height
)
1376 y
= screen_height
- child_height
;
1380 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1384 recycle_instance (destroyed_instance
* instance
)
1386 Widget widget
= instance
->widget
;
1388 /* widget is NULL if the parent was destroyed. */
1394 /* Remove the destroy callback as the instance is not in the list
1396 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1397 mark_dead_instance_destroyed
,
1398 (XtPointer
)instance
);
1400 /* Give the focus to the initial item */
1401 focus
= XtNameToWidget (widget
, "*value");
1403 focus
= XtNameToWidget (widget
, "*button1");
1405 XtSetKeyboardFocus (widget
, focus
);
1407 /* shrink the separator label back to their original size */
1408 separator
= XtNameToWidget (widget
, "*separator_button");
1410 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1412 /* Center the dialog in its parent */
1413 recenter_widget (widget
);
1415 free_destroyed_instance (instance
);
1420 xm_create_dialog (widget_instance
* instance
)
1422 char* name
= instance
->info
->type
;
1423 Widget parent
= instance
->parent
;
1425 Boolean pop_up_p
= instance
->pop_up_p
;
1426 char* shell_name
= 0;
1427 char* icon_name
= 0;
1428 Boolean text_input_slot
= False
;
1429 Boolean radio_box
= False
;
1430 Boolean list
= False
;
1432 int left_buttons
= 0;
1433 int right_buttons
= 1;
1434 destroyed_instance
* dead_one
;
1436 /* try to find a widget to recycle */
1437 dead_one
= find_matching_instance (instance
);
1440 Widget recycled_widget
= recycle_instance (dead_one
);
1441 if (recycled_widget
)
1442 return recycled_widget
;
1447 icon_name
= "dbox-error";
1448 shell_name
= "Error";
1452 icon_name
= "dbox-info";
1453 shell_name
= "Information";
1458 icon_name
= "dbox-question";
1459 shell_name
= "Prompt";
1463 text_input_slot
= True
;
1464 icon_name
= "dbox-question";
1465 shell_name
= "Prompt";
1469 icon_name
= "dbox-question";
1470 shell_name
= "Question";
1474 total_buttons
= name
[1] - '0';
1476 if (name
[3] == 'T' || name
[3] == 't')
1478 text_input_slot
= False
;
1482 right_buttons
= name
[4] - '0';
1484 left_buttons
= total_buttons
- right_buttons
;
1486 widget
= make_dialog (name
, parent
, pop_up_p
,
1487 shell_name
, icon_name
, text_input_slot
, radio_box
,
1488 list
, left_buttons
, right_buttons
);
1490 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1491 (XtPointer
) instance
);
1496 /* Create a menu bar. We turn off the f10 key
1497 because we have not yet managed to make it work right in Motif. */
1500 make_menubar (widget_instance
* instance
)
1506 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1507 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1511 remove_grabs (Widget shell
,
1513 XtPointer call_data
)
1515 Widget menu
= (Widget
) closure
;
1516 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1520 make_popup_menu (widget_instance
* instance
)
1522 Widget parent
= instance
->parent
;
1523 Window parent_window
= parent
->core
.window
;
1526 /* sets the parent window to 0 to fool Motif into not generating a grab */
1527 parent
->core
.window
= 0;
1528 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1529 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1531 parent
->core
.window
= parent_window
;
1536 make_main (widget_instance
* instance
)
1538 Widget parent
= instance
->parent
;
1544 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1545 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1546 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1550 \f/* Table of functions to create widgets */
1554 /* interface with the XDesigner generated functions */
1555 typedef Widget (*widget_maker
) (Widget
);
1556 extern Widget
create_project_p_sheet (Widget parent
);
1557 extern Widget
create_debugger_p_sheet (Widget parent
);
1558 extern Widget
create_breaklist_p_sheet (Widget parent
);
1559 extern Widget
create_le_browser_p_sheet (Widget parent
);
1560 extern Widget
create_class_browser_p_sheet (Widget parent
);
1561 extern Widget
create_call_browser_p_sheet (Widget parent
);
1562 extern Widget
create_build_dialog (Widget parent
);
1563 extern Widget
create_editmode_dialog (Widget parent
);
1564 extern Widget
create_search_dialog (Widget parent
);
1565 extern Widget
create_project_display_dialog (Widget parent
);
1568 make_one (widget_instance
* instance
, widget_maker fn
)
1574 if (instance
->pop_up_p
)
1576 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1577 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1578 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1579 (XtPointer
) instance
);
1584 result
= (*fn
) (instance
->parent
);
1585 XtRealizeWidget (result
);
1591 make_project_p_sheet (widget_instance
* instance
)
1593 return make_one (instance
, create_project_p_sheet
);
1597 make_debugger_p_sheet (widget_instance
* instance
)
1599 return make_one (instance
, create_debugger_p_sheet
);
1603 make_breaklist_p_sheet (widget_instance
* instance
)
1605 return make_one (instance
, create_breaklist_p_sheet
);
1609 make_le_browser_p_sheet (widget_instance
* instance
)
1611 return make_one (instance
, create_le_browser_p_sheet
);
1615 make_class_browser_p_sheet (widget_instance
* instance
)
1617 return make_one (instance
, create_class_browser_p_sheet
);
1621 make_call_browser_p_sheet (widget_instance
* instance
)
1623 return make_one (instance
, create_call_browser_p_sheet
);
1627 make_build_dialog (widget_instance
* instance
)
1629 return make_one (instance
, create_build_dialog
);
1633 make_editmode_dialog (widget_instance
* instance
)
1635 return make_one (instance
, create_editmode_dialog
);
1639 make_search_dialog (widget_instance
* instance
)
1641 return make_one (instance
, create_search_dialog
);
1645 make_project_display_dialog (widget_instance
* instance
)
1647 return make_one (instance
, create_project_display_dialog
);
1650 #endif /* ENERGIZE */
1652 widget_creation_entry
1653 xm_creation_table
[] =
1655 {"menubar", make_menubar
},
1656 {"popup", make_popup_menu
},
1657 {"main", make_main
},
1659 {"project_p_sheet", make_project_p_sheet
},
1660 {"debugger_p_sheet", make_debugger_p_sheet
},
1661 {"breaklist_psheet", make_breaklist_p_sheet
},
1662 {"leb_psheet", make_le_browser_p_sheet
},
1663 {"class_browser_psheet", make_class_browser_p_sheet
},
1664 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1665 {"build", make_build_dialog
},
1666 {"editmode", make_editmode_dialog
},
1667 {"search", make_search_dialog
},
1668 {"project_display", make_project_display_dialog
},
1669 #endif /* ENERGIZE */
1673 \f/* Destruction of instances */
1675 xm_destroy_instance ( widget_instance
* instance
)
1677 Widget widget
= instance
->widget
;
1678 /* recycle the dialog boxes */
1679 /* Disable the recycling until we can find a way to have the dialog box
1680 get reasonable layout after we modify its contents. */
1682 && XtClass (widget
) == xmDialogShellWidgetClass
)
1684 destroyed_instance
* dead_instance
=
1685 make_destroyed_instance (instance
->info
->name
,
1686 instance
->info
->type
,
1689 instance
->pop_up_p
);
1690 dead_instance
->next
= all_destroyed_instances
;
1691 all_destroyed_instances
= dead_instance
;
1692 XtUnmanageChild (first_child (instance
->widget
));
1693 XFlush (XtDisplay (instance
->widget
));
1694 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1695 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1699 /* This might not be necessary now that the nosel is attached to
1700 popdown instead of destroy, but it can't hurt. */
1701 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1702 xm_nosel_callback
, (XtPointer
)instance
);
1703 XtDestroyWidget (instance
->widget
);
1707 \f/* popup utility */
1709 xm_popup_menu (Widget widget
, XEvent
*event
)
1711 XButtonPressedEvent dummy
;
1715 dummy
.type
= ButtonPress
;
1717 dummy
.send_event
= 0;
1718 dummy
.display
= XtDisplay (widget
);
1719 dummy
.window
= XtWindow (XtParent (widget
));
1722 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1723 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1724 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1725 event
= (XEvent
*) &dummy
;
1728 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1730 /* Setting the menuPost resource only required by Motif 1.1 and
1731 LessTif 0.84 and earlier. With later versions of LessTif,
1732 setting menuPost is unnecessary and may cause problems, so
1734 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1736 /* This is so totally ridiculous: there's NO WAY to tell Motif
1737 that *any* button can select a menu item. Only one button
1738 can have that honor. */
1741 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1742 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1743 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1744 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1745 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1746 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1750 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1753 XtManageChild (widget
);
1757 set_min_dialog_size (Widget w
)
1761 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1762 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1766 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1768 Widget widget
= instance
->widget
;
1770 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1772 Widget widget_to_manage
= first_child (widget
);
1775 XtManageChild (widget_to_manage
);
1776 set_min_dialog_size (widget
);
1777 XtSetKeyboardFocus (instance
->parent
, widget
);
1780 XtUnmanageChild (widget_to_manage
);
1785 XtManageChild (widget
);
1787 XtUnmanageChild (widget
);
1792 /* motif callback */
1795 do_call (Widget widget
,
1797 enum do_call_type type
)
1801 XtPointer user_data
;
1802 widget_instance
* instance
= (widget_instance
*)closure
;
1803 Widget instance_widget
;
1808 if (widget
->core
.being_destroyed
)
1811 instance_widget
= instance
->widget
;
1812 if (!instance_widget
)
1815 id
= instance
->info
->id
;
1818 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1819 XtGetValues (widget
, al
, ac
);
1824 if (instance
->info
->pre_activate_cb
)
1825 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1829 if (instance
->info
->selection_cb
)
1830 instance
->info
->selection_cb (widget
, id
, user_data
);
1834 if (instance
->info
->selection_cb
)
1835 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1839 if (instance
->info
->post_activate_cb
)
1840 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1848 /* Like lw_internal_update_other_instances except that it does not do
1849 anything if its shell parent is not managed. This is to protect
1850 lw_internal_update_other_instances to dereference freed memory
1851 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1854 xm_internal_update_other_instances (Widget widget
,
1856 XtPointer call_data
)
1859 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1860 if (XtIsShell (parent
))
1862 else if (!XtIsManaged (parent
))
1864 lw_internal_update_other_instances (widget
, closure
, call_data
);
1868 xm_generic_callback (Widget widget
,
1870 XtPointer call_data
)
1872 lw_internal_update_other_instances (widget
, closure
, call_data
);
1873 do_call (widget
, closure
, selection
);
1877 xm_nosel_callback (Widget widget
,
1879 XtPointer call_data
)
1881 /* This callback is only called when a dialog box is dismissed with
1882 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1883 box to be destroyed in that case, not just unmapped, so that it
1884 releases its keyboard grabs. But there are problems with running
1885 our callbacks while the widget is in the process of being
1886 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1887 XmDESTROY and then destroy it ourself after having run the
1889 do_call (widget
, closure
, no_selection
);
1890 XtDestroyWidget (widget
);
1894 xm_pull_down_callback (Widget widget
,
1896 XtPointer call_data
)
1898 Widget parent
= XtParent (widget
);
1900 if (XmIsRowColumn (parent
))
1902 unsigned char type
= 0xff;
1903 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1904 if (type
== XmMENU_BAR
)
1905 do_call (widget
, closure
, pre_activate
);
1910 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1911 CLOSURE is a pointer to the widget_instance of the shell,
1913 Note that this callback is called for each cascade button in a
1914 menu, whether or not its submenu is visible. */
1917 xm_pop_down_callback (Widget widget
,
1919 XtPointer call_data
)
1921 widget_instance
*instance
= (widget_instance
*) closure
;
1923 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1924 || XtParent (widget
) == instance
->parent
)
1925 do_call (widget
, closure
, post_activate
);
1929 /* set the keyboard focus */
1931 xm_set_keyboard_focus (Widget parent
, Widget w
)
1933 XmProcessTraversal (w
, 0);
1934 XtSetKeyboardFocus (parent
, w
);
1937 /* Motif hack to set the main window areas. */
1939 xm_set_main_areas (Widget parent
,
1943 XmMainWindowSetAreas (parent
,
1944 menubar
, /* menubar (maybe 0) */
1945 0, /* command area (psheets) */
1946 0, /* horizontal scroll */
1947 0, /* vertical scroll */
1948 work_area
); /* work area */
1951 /* Motif hack to control resizing on the menubar. */
1953 xm_manage_resizing (Widget w
, Boolean flag
)
1955 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);