1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2014 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. If not, see <http://www.gnu.org/licenses/>. */
27 #include <X11/StringDefs.h>
28 #include <X11/IntrinsicP.h>
29 #include <X11/ObjectP.h>
30 #include <X11/CoreP.h>
31 #include <X11/CompositeP.h>
36 #include "lwlib-utils.h"
38 #include <Xm/BulletinB.h>
39 #include <Xm/CascadeB.h>
40 #include <Xm/CascadeBG.h>
41 #include <Xm/DrawingA.h>
42 #include <Xm/FileSB.h>
46 #include <Xm/MenuShell.h>
47 #include <Xm/MessageB.h>
48 #include <Xm/PanedW.h>
50 #include <Xm/PushBG.h>
51 #include <Xm/ArrowB.h>
52 #include <Xm/SelectioB.h>
55 #include <Xm/ToggleB.h>
56 #include <Xm/ToggleBG.h>
57 #include <Xm/RowColumn.h>
58 #include <Xm/ScrolledW.h>
59 #include <Xm/Separator.h>
60 #include <Xm/DialogS.h>
63 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
66 \f/* Structures to keep destroyed instances */
67 typedef struct _destroyed_instance
74 struct _destroyed_instance
* next
;
77 static destroyed_instance
*make_destroyed_instance (char *, char *,
80 static void free_destroyed_instance (destroyed_instance
*);
81 Widget
first_child (Widget
);
82 Boolean
lw_motif_widget_p (Widget
);
83 static XmString
resource_motif_string (Widget
, char *);
84 static void destroy_all_children (Widget
, int);
85 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
86 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
87 static void xm_update_pushbutton (widget_instance
*, Widget
,
89 static void xm_update_cascadebutton (widget_instance
*, Widget
,
91 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
92 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
93 static void make_menu_in_widget (widget_instance
*, Widget
,
95 static void update_one_menu_entry (widget_instance
*, Widget
,
96 widget_value
*, Boolean
);
97 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
99 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
100 static void xm_update_text_field (widget_instance
*, Widget
,
102 void xm_update_one_value (widget_instance
*, Widget
, widget_value
*);
103 static void activate_button (Widget
, XtPointer
, XtPointer
);
104 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
105 Boolean
, Boolean
, Boolean
, int, int);
106 static destroyed_instance
* find_matching_instance (widget_instance
*);
107 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
108 static void recenter_widget (Widget
);
109 static Widget
recycle_instance (destroyed_instance
*);
110 Widget
xm_create_dialog (widget_instance
*);
111 static Widget
make_menubar (widget_instance
*);
112 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
113 static Widget
make_popup_menu (widget_instance
*);
114 static Widget
make_main (widget_instance
*);
115 void xm_destroy_instance (widget_instance
*);
116 void xm_popup_menu (Widget
, XEvent
*);
117 static void set_min_dialog_size (Widget
);
118 static void do_call (Widget
, XtPointer
, enum do_call_type
);
119 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
120 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
121 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
122 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
123 void xm_set_keyboard_focus (Widget
, Widget
);
124 void xm_set_main_areas (Widget
, Widget
, Widget
);
125 static void xm_internal_update_other_instances (Widget
, XtPointer
,
127 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
130 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
132 void xm_pop_instance (widget_instance
*, Boolean
);
133 void xm_manage_resizing (Widget
, Boolean
);
139 /* Print the complete X resource name of widget WIDGET to stderr.
140 This is sometimes handy to have available. */
143 x_print_complete_resource_name (Widget widget
)
148 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
150 names
[i
] = XtName (widget
);
151 widget
= XtParent (widget
);
154 for (--i
; i
>= 1; --i
)
155 fprintf (stderr
, "%s.", names
[i
]);
156 fprintf (stderr
, "%s\n", names
[0]);
162 static destroyed_instance
*all_destroyed_instances
= NULL
;
164 static destroyed_instance
*
165 make_destroyed_instance (char* name
,
171 destroyed_instance
* instance
=
172 (destroyed_instance
*) xmalloc (sizeof (destroyed_instance
));
173 instance
->name
= safe_strdup (name
);
174 instance
->type
= safe_strdup (type
);
175 instance
->widget
= widget
;
176 instance
->parent
= parent
;
177 instance
->pop_up_p
= pop_up_p
;
178 instance
->next
= NULL
;
183 free_destroyed_instance (destroyed_instance
* instance
)
185 xfree (instance
->name
);
186 xfree (instance
->type
);
190 \f/* motif utility functions */
192 first_child (Widget widget
)
194 return ((CompositeWidget
)widget
)->composite
.children
[0];
198 lw_motif_widget_p (Widget widget
)
201 XtClass (widget
) == xmDialogShellWidgetClass
202 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
206 resource_motif_string (Widget widget
,
212 resource
.resource_name
= name
;
213 resource
.resource_class
= XmCXmString
;
214 resource
.resource_type
= XmRXmString
;
215 resource
.resource_size
= sizeof (XmString
);
216 resource
.resource_offset
= 0;
217 resource
.default_type
= XtRImmediate
;
218 resource
.default_addr
= 0;
220 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
221 "DialogString", &resource
, 1, NULL
, 0);
225 /* Destroy all of the children of WIDGET
226 starting with number FIRST_CHILD_TO_DESTROY. */
229 destroy_all_children (Widget widget
,
230 int first_child_to_destroy
)
236 children
= XtCompositeChildren (widget
, &number
);
239 XtUnmanageChildren (children
+ first_child_to_destroy
,
240 number
- first_child_to_destroy
);
242 /* Unmanage all children and destroy them. They will only be
243 really destroyed when we get out of DispatchEvent. */
244 for (i
= first_child_to_destroy
; i
< number
; i
++)
248 /* Cascade buttons have submenus,and these submenus
249 need to be freed. But they are not included in
250 XtCompositeChildren. So get it out of the cascade button
251 and free it. If this child is not a cascade button,
252 then submenu should remain unchanged. */
253 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
254 XtGetValues (children
[i
], al
, 1);
257 destroy_all_children (submenu
, 0);
258 XtDestroyWidget (submenu
);
260 XtDestroyWidget (children
[i
]);
263 XtFree ((char *) children
);
269 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
270 menu. CLIENT_DATA contains a pointer to the widget_value
271 corresponding to widget W. CALL_DATA contains a
272 XmPushButtonCallbackStruct containing the reason why the callback
276 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
278 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
279 widget_value
*wv
= (widget_value
*) client_data
;
280 widget_instance
*instance
;
282 /* Get the id of the menu bar or popup menu this widget is in. */
285 if (XmIsRowColumn (w
))
287 unsigned char type
= 0xff;
289 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
290 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
299 instance
= lw_get_widget_instance (w
);
300 if (instance
&& instance
->info
->highlight_cb
)
302 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
303 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
310 /* Update the label of widget WIDGET. WIDGET must be a Label widget
311 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
316 Emacs fills VAL->name with the text to display in the menu, and
317 sets VAL->value to null. Function make_menu_in_widget creates
318 widgets with VAL->name as resource name. This works because the
319 Label widget uses its resource name for display if no
320 XmNlabelString is set.
324 VAL->name is again set to the resource name, but VAL->value is
325 not null, and contains the label string to display. */
328 xm_update_label (widget_instance
* instance
,
332 XmString res_string
= 0;
333 XmString built_string
= 0;
334 XmString key_string
= 0;
342 /* A label string is specified, i.e. we are in a dialog. First
343 see if it is overridden by something from the resource file. */
344 res_string
= resource_motif_string (widget
, val
->value
);
348 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
353 XmStringCreateLocalized (val
->value
);
354 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
357 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
362 key_string
= XmStringCreateLocalized (val
->key
);
363 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
367 XtSetValues (widget
, al
, ac
);
370 XmStringFree (built_string
);
373 XmStringFree (key_string
);
376 \f/* update of list */
378 xm_update_list (widget_instance
* instance
,
384 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
385 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
387 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
390 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
392 XmListAddItem (widget
, xmstr
, 0);
394 XmListSelectPos (widget
, i
, False
);
395 XmStringFree (xmstr
);
399 \f/* update of buttons */
401 xm_update_pushbutton (widget_instance
* instance
,
405 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
406 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
407 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
411 xm_update_cascadebutton (widget_instance
* instance
,
415 /* Should also rebuild the menu by calling ...update_menu... */
416 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
417 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
421 \f/* update toggle and radiobox */
423 xm_update_toggle (widget_instance
* instance
,
427 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
428 XtAddCallback (widget
, XmNvalueChangedCallback
,
429 xm_generic_callback
, instance
);
430 XtVaSetValues (widget
, XmNset
, val
->selected
,
431 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
435 xm_update_radiobox (widget_instance
* instance
,
443 /* update the callback */
444 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
445 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
447 /* first update all the toggles */
448 /* Energize kernel interface is currently bad. It sets the selected widget
449 with the selected flag but returns it by its name. So we currently
450 have to support both setting the selection with the selected slot
451 of val contents and setting it with the "value" slot of val. The latter
452 has a higher priority. This to be removed when the kernel is fixed. */
453 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
455 toggle
= XtNameToWidget (widget
, cur
->value
);
458 XtSetSensitive (toggle
, cur
->enabled
);
459 if (!val
->value
&& cur
->selected
)
460 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
461 if (val
->value
&& strcmp (val
->value
, cur
->value
))
462 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
466 /* The selected was specified by the value slot */
469 toggle
= XtNameToWidget (widget
, val
->value
);
471 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
476 /* update a popup menu, pulldown menu or a menubar */
478 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
481 make_menu_in_widget (widget_instance
* instance
,
484 int keep_first_children
)
486 Widget
* children
= 0;
497 Widget
* old_children
;
498 unsigned int old_num_children
;
500 /* Disable drag and drop for labels in menu bar. */
501 static char overrideTrans
[] = "<Btn2Down>: Noop()";
502 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
504 old_children
= XtCompositeChildren (widget
, &old_num_children
);
506 /* Allocate the children array */
507 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
509 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
511 /* WIDGET should be a RowColumn. */
512 if (!XmIsRowColumn (widget
))
515 /* Determine whether WIDGET is a menu bar. */
517 XtSetArg (al
[0], XmNrowColumnType
, &type
);
518 XtGetValues (widget
, al
, 1);
519 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
521 menubar_p
= type
== XmMENU_BAR
;
523 /* Add a callback to popups and pulldowns that is called when
524 it is made invisible again. */
526 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
527 xm_pop_down_callback
, (XtPointer
)instance
);
529 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
530 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
531 child_index
++, cur
= cur
->next
)
532 children
[child_index
] = old_children
[child_index
];
534 /* Check that those are all we have
535 (the caller should have deleted the rest). */
536 if (old_num_children
!= keep_first_children
)
539 /* Create the rest. */
540 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
542 enum menu_separator separator
;
545 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
546 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
547 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
549 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
550 && !lw_separator_p (cur
->name
, &separator
, 1))
553 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
554 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
556 else if (lw_separator_p (cur
->name
, &separator
, 1))
559 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
560 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
562 else if (!cur
->contents
)
565 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
566 else if (!cur
->call_data
)
567 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
568 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
569 || cur
->button_type
== BUTTON_TYPE_RADIO
)
571 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
572 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
573 XtSetArg (al
[ac
], XmNindicatorType
,
574 (cur
->button_type
== BUTTON_TYPE_TOGGLE
575 ? XmN_OF_MANY
: XmONE_OF_MANY
));
577 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
578 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
579 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
583 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
584 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
585 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
588 xm_update_label (instance
, button
, cur
);
590 /* Add a callback that is called when the button is
591 selected. Toggle buttons don't support
592 XmNactivateCallback, we use XmNvalueChangedCallback in
593 that case. Don't add a callback to a simple label. */
594 if (cur
->button_type
)
595 xm_update_toggle (instance
, button
, cur
);
596 else if (cur
->call_data
)
597 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
598 (XtPointer
)instance
);
602 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
604 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
605 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
606 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
608 xm_update_label (instance
, button
, cur
);
610 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
611 (XtPointer
)instance
);
612 XtOverrideTranslations (button
, override
);
616 children
[child_index
] = button
;
619 /* Last entry is the help button. The original comment read "Has to
620 be done after managing the buttons otherwise the menubar is only
621 4 pixels high." This is no longer true, and to make
622 XmNmenuHelpWidget work, we need to set it before managing the
623 children.. --gerd. */
625 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
628 XtManageChildren (children
, num_children
);
630 XtFree ((char *) children
);
632 XtFree ((char *) old_children
);
636 update_one_menu_entry (widget_instance
* instance
,
644 widget_value
* contents
;
646 if (val
->this_one_change
== NO_CHANGE
)
649 /* update the sensitivity and userdata */
650 /* Common to all widget types */
651 XtSetSensitive (widget
, val
->enabled
);
652 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
654 /* update the menu button as a label. */
655 if (val
->this_one_change
>= VISIBLE_CHANGE
)
657 xm_update_label (instance
, widget
, val
);
658 if (val
->button_type
)
659 xm_update_toggle (instance
, widget
, val
);
662 /* update the pulldown/pullaside as needed */
665 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
666 XtGetValues (widget
, al
, ac
);
668 contents
= val
->contents
;
674 unsigned int old_num_children
, i
;
678 parent
= XtParent (widget
);
679 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
681 /* Find the widget position within the parent's widget list. */
682 for (i
= 0; i
< old_num_children
; i
++)
683 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
685 if (i
== old_num_children
)
687 if (XmIsCascadeButton (widget_list
[i
]))
689 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
690 make_menu_in_widget (instance
, menu
, contents
, 0);
692 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
693 XtSetValues (widget
, al
, ac
);
699 /* The current menuitem is a XmPushButtonGadget, it
700 needs to be replaced by a CascadeButtonGadget */
701 XtDestroyWidget (widget_list
[i
]);
702 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
703 make_menu_in_widget (instance
, menu
, contents
, 0);
705 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
706 /* Non-zero values don't work reliably in
707 conjunction with Emacs' event loop */
708 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
709 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
710 /* Tell Motif to put it in the right place */
711 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
713 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
714 xm_update_label (instance
, button
, val
);
716 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
717 (XtPointer
)instance
);
718 XtManageChild (button
);
722 XtFree ((char*) widget_list
);
728 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
729 XtSetValues (widget
, al
, ac
);
730 XtDestroyWidget (menu
);
732 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
733 xm_update_menu (instance
, menu
, val
, 1);
737 xm_update_menu (widget_instance
* instance
,
743 unsigned int num_children
;
744 int num_children_to_keep
= 0;
748 children
= XtCompositeChildren (widget
, &num_children
);
750 /* Widget is a RowColumn widget whose contents have to be updated
751 * to reflect the list of items in val->contents */
753 /* See how many buttons we can keep, and how many we
754 must completely replace. */
755 if (val
->contents
== 0)
756 num_children_to_keep
= 0;
757 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
761 for (i
= 0, cur
= val
->contents
;
763 && cur
); /* how else to ditch unwanted children ?? - mgd */
764 i
++, cur
= cur
->next
)
766 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
770 num_children_to_keep
= i
;
774 num_children_to_keep
= num_children
;
776 /* Update all the buttons of the RowColumn, in order,
777 except for those we are going to replace entirely. */
780 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
784 num_children_to_keep
= i
;
787 if (children
[i
]->core
.being_destroyed
788 || strcmp (XtName (children
[i
]), cur
->name
))
790 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
795 /* Now replace from scratch all the buttons after the last
796 place that the top-level structure changed. */
797 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
799 destroy_all_children (widget
, num_children_to_keep
);
800 make_menu_in_widget (instance
, widget
, val
->contents
,
801 num_children_to_keep
);
804 XtFree ((char *) children
);
808 /* update text widgets */
811 xm_update_text (widget_instance
* instance
,
815 XmTextSetString (widget
, val
->value
? val
->value
: "");
816 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
817 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
818 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
819 XtAddCallback (widget
, XmNvalueChangedCallback
,
820 xm_internal_update_other_instances
, instance
);
824 xm_update_text_field (widget_instance
* instance
,
828 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
829 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
830 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
831 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
832 XtAddCallback (widget
, XmNvalueChangedCallback
,
833 xm_internal_update_other_instances
, instance
);
837 /* update a motif widget */
840 xm_update_one_widget (widget_instance
* instance
,
847 /* Mark as not edited */
850 /* Common to all widget types */
851 XtSetSensitive (widget
, val
->enabled
);
852 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
854 /* Common to all label like widgets */
855 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
856 xm_update_label (instance
, widget
, val
);
858 class = XtClass (widget
);
859 /* Class specific things */
860 if (class == xmPushButtonWidgetClass
||
861 class == xmArrowButtonWidgetClass
)
863 xm_update_pushbutton (instance
, widget
, val
);
865 else if (class == xmCascadeButtonWidgetClass
)
867 xm_update_cascadebutton (instance
, widget
, val
);
869 else if (class == xmToggleButtonWidgetClass
870 || class == xmToggleButtonGadgetClass
)
872 xm_update_toggle (instance
, widget
, val
);
874 else if (class == xmRowColumnWidgetClass
)
876 Boolean radiobox
= 0;
880 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
881 XtGetValues (widget
, al
, ac
);
884 xm_update_radiobox (instance
, widget
, val
);
886 xm_update_menu (instance
, widget
, val
, deep_p
);
888 else if (class == xmTextWidgetClass
)
890 xm_update_text (instance
, widget
, val
);
892 else if (class == xmTextFieldWidgetClass
)
894 xm_update_text_field (instance
, widget
, val
);
896 else if (class == xmListWidgetClass
)
898 xm_update_list (instance
, widget
, val
);
902 \f/* getting the value back */
904 xm_update_one_value (widget_instance
* instance
,
908 WidgetClass
class = XtClass (widget
);
909 widget_value
*old_wv
;
911 /* copy the call_data slot into the "return" widget_value */
912 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
913 if (!strcmp (val
->name
, old_wv
->name
))
915 val
->call_data
= old_wv
->call_data
;
919 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
921 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
924 else if (class == xmTextWidgetClass
)
927 val
->value
= XmTextGetString (widget
);
930 else if (class == xmTextFieldWidgetClass
)
933 val
->value
= XmTextFieldGetString (widget
);
936 else if (class == xmRowColumnWidgetClass
)
938 Boolean radiobox
= 0;
942 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
943 XtGetValues (widget
, al
, ac
);
947 CompositeWidget radio
= (CompositeWidget
)widget
;
949 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
952 Widget toggle
= radio
->composite
.children
[i
];
954 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
958 val
->value
= safe_strdup (XtName (toggle
));
964 else if (class == xmListWidgetClass
)
968 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
972 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
976 cur
->selected
= False
;
978 for (j
= 0; j
< pos_cnt
; j
++)
979 if (pos_list
[j
] == i
)
981 cur
->selected
= True
;
982 val
->value
= safe_strdup (cur
->name
);
986 XtFree ((char *) pos_list
);
992 /* This function is for activating a button from a program. It's wrong because
993 we pass a NULL argument in the call_data which is not Motif compatible.
994 This is used from the XmNdefaultAction callback of the List widgets to
995 have a double-click put down a dialog box like the button would do.
996 I could not find a way to do that with accelerators.
999 activate_button (Widget widget
,
1001 XtPointer call_data
)
1003 Widget button
= (Widget
)closure
;
1004 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1007 /* creation functions */
1009 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1011 dialog_key_cb (Widget widget
,
1014 Boolean
*continue_to_dispatch
)
1017 Modifiers modif_ret
;
1019 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1022 if (sym
== osfXK_Cancel
)
1024 Widget w
= *((Widget
*) closure
);
1026 while (w
&& ! XtIsShell (w
))
1029 if (XtIsShell (w
)) XtPopdown (w
);
1032 *continue_to_dispatch
= TRUE
;
1037 make_dialog (char* name
,
1042 Boolean text_input_slot
,
1052 Widget icon_separator
;
1053 Widget message_label
;
1057 Widget children
[16]; /* for the final XtManageChildren */
1059 Arg al
[64]; /* Arg List */
1060 int ac
; /* Arg Count */
1066 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1067 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1068 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1069 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1071 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1072 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1073 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1074 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1079 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1080 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1081 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1085 n_children
= left_buttons
+ right_buttons
+ 1;
1087 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1088 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1089 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1090 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1091 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1092 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1093 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1094 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1095 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1096 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1097 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1098 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1099 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1100 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1101 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1102 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1103 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1104 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1105 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1108 for (i
= 0; i
< left_buttons
; i
++)
1110 char button_name
[16];
1111 sprintf (button_name
, "button%d", i
+ 1);
1115 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1116 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1118 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1119 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1120 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1121 XtAddEventHandler (children
[n_children
],
1122 KeyPressMask
, False
, dialog_key_cb
, result
);
1126 button
= children
[n_children
];
1128 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1129 XtSetValues (row
, al
, ac
);
1135 /* invisible separator button */
1137 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1138 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1141 for (i
= 0; i
< right_buttons
; i
++)
1143 char button_name
[16];
1144 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1146 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1147 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1148 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1149 XtAddEventHandler (children
[n_children
],
1150 KeyPressMask
, False
, dialog_key_cb
, result
);
1152 if (! button
) button
= children
[n_children
];
1156 XtManageChildren (children
, n_children
);
1159 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1160 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1161 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1162 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1163 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1164 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1165 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1166 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1167 separator
= XmCreateSeparator (form
, "", al
, ac
);
1170 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1171 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1172 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1173 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1174 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1175 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1176 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1177 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1180 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1181 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1182 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1183 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1184 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1185 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1186 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1187 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1188 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1189 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1191 if (text_input_slot
)
1194 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1195 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1196 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1197 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1198 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1199 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1200 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1201 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1202 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1203 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1204 value
= XmCreateTextField (form
, "value", al
, ac
);
1210 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1211 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1212 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1213 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1214 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1215 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1216 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1217 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1218 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1219 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1220 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1221 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1222 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1223 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1226 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1227 children
[i
++] = radio_butt
;
1228 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1229 children
[i
++] = radio_butt
;
1230 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1231 children
[i
++] = radio_butt
;
1232 XtManageChildren (children
, i
);
1237 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1238 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1239 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1240 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1241 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1242 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1243 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1244 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1245 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1246 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1247 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1249 /* this is the easiest way I found to have the dble click in the
1250 list activate the default button */
1251 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1255 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1256 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1257 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1258 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1259 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1260 XtSetArg(al
[ac
], XmNbottomWidget
,
1261 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1262 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1263 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1264 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1265 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1266 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1267 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1270 XtManageChild (value
);
1273 children
[i
] = row
; i
++;
1274 children
[i
] = separator
; i
++;
1275 if (text_input_slot
|| radio_box
)
1277 children
[i
] = value
; i
++;
1279 children
[i
] = message_label
; i
++;
1280 children
[i
] = icon
; i
++;
1281 children
[i
] = icon_separator
; i
++;
1282 XtManageChildren (children
, i
);
1284 if (text_input_slot
|| list
)
1286 XtInstallAccelerators (value
, button
);
1287 XtSetKeyboardFocus (result
, value
);
1291 XtInstallAccelerators (form
, button
);
1292 XtSetKeyboardFocus (result
, button
);
1298 static destroyed_instance
*
1299 find_matching_instance (widget_instance
* instance
)
1301 destroyed_instance
* cur
;
1302 destroyed_instance
* prev
;
1303 char* type
= instance
->info
->type
;
1304 char* name
= instance
->info
->name
;
1306 for (prev
= NULL
, cur
= all_destroyed_instances
;
1308 prev
= cur
, cur
= cur
->next
)
1310 if (!strcmp (cur
->name
, name
)
1311 && !strcmp (cur
->type
, type
)
1312 && cur
->parent
== instance
->parent
1313 && cur
->pop_up_p
== instance
->pop_up_p
)
1316 prev
->next
= cur
->next
;
1318 all_destroyed_instances
= cur
->next
;
1321 /* do some cleanup */
1322 else if (!cur
->widget
)
1325 prev
->next
= cur
->next
;
1327 all_destroyed_instances
= cur
->next
;
1328 free_destroyed_instance (cur
);
1329 cur
= prev
? prev
: all_destroyed_instances
;
1336 mark_dead_instance_destroyed (Widget widget
,
1338 XtPointer call_data
)
1340 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1341 instance
->widget
= NULL
;
1345 recenter_widget (Widget widget
)
1347 Widget parent
= XtParent (widget
);
1348 Screen
* screen
= XtScreen (widget
);
1349 Dimension screen_width
= WidthOfScreen (screen
);
1350 Dimension screen_height
= HeightOfScreen (screen
);
1351 Dimension parent_width
= 0;
1352 Dimension parent_height
= 0;
1353 Dimension child_width
= 0;
1354 Dimension child_height
= 0;
1358 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1359 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1362 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1363 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1365 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1367 if (x
+ child_width
> screen_width
)
1368 x
= screen_width
- child_width
;
1372 if (y
+ child_height
> screen_height
)
1373 y
= screen_height
- child_height
;
1377 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1381 recycle_instance (destroyed_instance
* instance
)
1383 Widget widget
= instance
->widget
;
1385 /* widget is NULL if the parent was destroyed. */
1391 /* Remove the destroy callback as the instance is not in the list
1393 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1394 mark_dead_instance_destroyed
,
1395 (XtPointer
)instance
);
1397 /* Give the focus to the initial item */
1398 focus
= XtNameToWidget (widget
, "*value");
1400 focus
= XtNameToWidget (widget
, "*button1");
1402 XtSetKeyboardFocus (widget
, focus
);
1404 /* shrink the separator label back to their original size */
1405 separator
= XtNameToWidget (widget
, "*separator_button");
1407 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1409 /* Center the dialog in its parent */
1410 recenter_widget (widget
);
1412 free_destroyed_instance (instance
);
1417 xm_create_dialog (widget_instance
* instance
)
1419 char* name
= instance
->info
->type
;
1420 Widget parent
= instance
->parent
;
1422 Boolean pop_up_p
= instance
->pop_up_p
;
1423 char* shell_name
= 0;
1424 char* icon_name
= 0;
1425 Boolean text_input_slot
= False
;
1426 Boolean radio_box
= False
;
1427 Boolean list
= False
;
1429 int left_buttons
= 0;
1430 int right_buttons
= 1;
1431 destroyed_instance
* dead_one
;
1433 /* try to find a widget to recycle */
1434 dead_one
= find_matching_instance (instance
);
1437 Widget recycled_widget
= recycle_instance (dead_one
);
1438 if (recycled_widget
)
1439 return recycled_widget
;
1444 icon_name
= "dbox-error";
1445 shell_name
= "Error";
1449 icon_name
= "dbox-info";
1450 shell_name
= "Information";
1455 icon_name
= "dbox-question";
1456 shell_name
= "Prompt";
1460 text_input_slot
= True
;
1461 icon_name
= "dbox-question";
1462 shell_name
= "Prompt";
1466 icon_name
= "dbox-question";
1467 shell_name
= "Question";
1471 total_buttons
= name
[1] - '0';
1473 if (name
[3] == 'T' || name
[3] == 't')
1475 text_input_slot
= False
;
1479 right_buttons
= name
[4] - '0';
1481 left_buttons
= total_buttons
- right_buttons
;
1483 widget
= make_dialog (name
, parent
, pop_up_p
,
1484 shell_name
, icon_name
, text_input_slot
, radio_box
,
1485 list
, left_buttons
, right_buttons
);
1487 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1488 (XtPointer
) instance
);
1493 /* Create a menu bar. We turn off the f10 key
1494 because we have not yet managed to make it work right in Motif. */
1497 make_menubar (widget_instance
* instance
)
1503 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1504 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1508 remove_grabs (Widget shell
,
1510 XtPointer call_data
)
1512 Widget menu
= (Widget
) closure
;
1513 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1517 make_popup_menu (widget_instance
* instance
)
1519 Widget parent
= instance
->parent
;
1520 Window parent_window
= parent
->core
.window
;
1523 /* sets the parent window to 0 to fool Motif into not generating a grab */
1524 parent
->core
.window
= 0;
1525 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1526 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1528 parent
->core
.window
= parent_window
;
1533 make_main (widget_instance
* instance
)
1535 Widget parent
= instance
->parent
;
1541 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1542 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1543 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1547 \f/* Table of functions to create widgets */
1551 /* interface with the XDesigner generated functions */
1552 typedef Widget (*widget_maker
) (Widget
);
1553 extern Widget
create_project_p_sheet (Widget parent
);
1554 extern Widget
create_debugger_p_sheet (Widget parent
);
1555 extern Widget
create_breaklist_p_sheet (Widget parent
);
1556 extern Widget
create_le_browser_p_sheet (Widget parent
);
1557 extern Widget
create_class_browser_p_sheet (Widget parent
);
1558 extern Widget
create_call_browser_p_sheet (Widget parent
);
1559 extern Widget
create_build_dialog (Widget parent
);
1560 extern Widget
create_editmode_dialog (Widget parent
);
1561 extern Widget
create_search_dialog (Widget parent
);
1562 extern Widget
create_project_display_dialog (Widget parent
);
1565 make_one (widget_instance
* instance
, widget_maker fn
)
1571 if (instance
->pop_up_p
)
1573 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1574 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1575 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1576 (XtPointer
) instance
);
1581 result
= (*fn
) (instance
->parent
);
1582 XtRealizeWidget (result
);
1588 make_project_p_sheet (widget_instance
* instance
)
1590 return make_one (instance
, create_project_p_sheet
);
1594 make_debugger_p_sheet (widget_instance
* instance
)
1596 return make_one (instance
, create_debugger_p_sheet
);
1600 make_breaklist_p_sheet (widget_instance
* instance
)
1602 return make_one (instance
, create_breaklist_p_sheet
);
1606 make_le_browser_p_sheet (widget_instance
* instance
)
1608 return make_one (instance
, create_le_browser_p_sheet
);
1612 make_class_browser_p_sheet (widget_instance
* instance
)
1614 return make_one (instance
, create_class_browser_p_sheet
);
1618 make_call_browser_p_sheet (widget_instance
* instance
)
1620 return make_one (instance
, create_call_browser_p_sheet
);
1624 make_build_dialog (widget_instance
* instance
)
1626 return make_one (instance
, create_build_dialog
);
1630 make_editmode_dialog (widget_instance
* instance
)
1632 return make_one (instance
, create_editmode_dialog
);
1636 make_search_dialog (widget_instance
* instance
)
1638 return make_one (instance
, create_search_dialog
);
1642 make_project_display_dialog (widget_instance
* instance
)
1644 return make_one (instance
, create_project_display_dialog
);
1647 #endif /* ENERGIZE */
1649 widget_creation_entry
1650 xm_creation_table
[] =
1652 {"menubar", make_menubar
},
1653 {"popup", make_popup_menu
},
1654 {"main", make_main
},
1656 {"project_p_sheet", make_project_p_sheet
},
1657 {"debugger_p_sheet", make_debugger_p_sheet
},
1658 {"breaklist_psheet", make_breaklist_p_sheet
},
1659 {"leb_psheet", make_le_browser_p_sheet
},
1660 {"class_browser_psheet", make_class_browser_p_sheet
},
1661 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1662 {"build", make_build_dialog
},
1663 {"editmode", make_editmode_dialog
},
1664 {"search", make_search_dialog
},
1665 {"project_display", make_project_display_dialog
},
1666 #endif /* ENERGIZE */
1670 \f/* Destruction of instances */
1672 xm_destroy_instance ( widget_instance
* instance
)
1674 Widget widget
= instance
->widget
;
1675 /* recycle the dialog boxes */
1676 /* Disable the recycling until we can find a way to have the dialog box
1677 get reasonable layout after we modify its contents. */
1679 && XtClass (widget
) == xmDialogShellWidgetClass
)
1681 destroyed_instance
* dead_instance
=
1682 make_destroyed_instance (instance
->info
->name
,
1683 instance
->info
->type
,
1686 instance
->pop_up_p
);
1687 dead_instance
->next
= all_destroyed_instances
;
1688 all_destroyed_instances
= dead_instance
;
1689 XtUnmanageChild (first_child (instance
->widget
));
1690 XFlush (XtDisplay (instance
->widget
));
1691 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1692 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1696 /* This might not be necessary now that the nosel is attached to
1697 popdown instead of destroy, but it can't hurt. */
1698 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1699 xm_nosel_callback
, (XtPointer
)instance
);
1700 XtDestroyWidget (instance
->widget
);
1704 \f/* popup utility */
1706 xm_popup_menu (Widget widget
, XEvent
*event
)
1708 XButtonPressedEvent dummy
;
1712 dummy
.type
= ButtonPress
;
1714 dummy
.send_event
= 0;
1715 dummy
.display
= XtDisplay (widget
);
1716 dummy
.window
= XtWindow (XtParent (widget
));
1719 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1720 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1721 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1722 event
= (XEvent
*) &dummy
;
1725 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1727 /* Setting the menuPost resource only required by Motif 1.1 and
1728 LessTif 0.84 and earlier. With later versions of LessTif,
1729 setting menuPost is unnecessary and may cause problems, so
1731 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1733 /* This is so totally ridiculous: there's NO WAY to tell Motif
1734 that *any* button can select a menu item. Only one button
1735 can have that honor. */
1738 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1739 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1740 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1741 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1742 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1743 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1747 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1750 XtManageChild (widget
);
1754 set_min_dialog_size (Widget w
)
1758 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1759 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1763 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1765 Widget widget
= instance
->widget
;
1767 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1769 Widget widget_to_manage
= first_child (widget
);
1772 XtManageChild (widget_to_manage
);
1773 set_min_dialog_size (widget
);
1774 XtSetKeyboardFocus (instance
->parent
, widget
);
1777 XtUnmanageChild (widget_to_manage
);
1782 XtManageChild (widget
);
1784 XtUnmanageChild (widget
);
1789 /* motif callback */
1792 do_call (Widget widget
,
1794 enum do_call_type type
)
1798 XtPointer user_data
;
1799 widget_instance
* instance
= (widget_instance
*)closure
;
1800 Widget instance_widget
;
1805 if (widget
->core
.being_destroyed
)
1808 instance_widget
= instance
->widget
;
1809 if (!instance_widget
)
1812 id
= instance
->info
->id
;
1815 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1816 XtGetValues (widget
, al
, ac
);
1821 if (instance
->info
->pre_activate_cb
)
1822 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1826 if (instance
->info
->selection_cb
)
1827 instance
->info
->selection_cb (widget
, id
, user_data
);
1831 if (instance
->info
->selection_cb
)
1832 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1836 if (instance
->info
->post_activate_cb
)
1837 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1845 /* Like lw_internal_update_other_instances except that it does not do
1846 anything if its shell parent is not managed. This is to protect
1847 lw_internal_update_other_instances to dereference freed memory
1848 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1851 xm_internal_update_other_instances (Widget widget
,
1853 XtPointer call_data
)
1856 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1857 if (XtIsShell (parent
))
1859 else if (!XtIsManaged (parent
))
1861 lw_internal_update_other_instances (widget
, closure
, call_data
);
1865 xm_generic_callback (Widget widget
,
1867 XtPointer call_data
)
1869 lw_internal_update_other_instances (widget
, closure
, call_data
);
1870 do_call (widget
, closure
, selection
);
1874 xm_nosel_callback (Widget widget
,
1876 XtPointer call_data
)
1878 /* This callback is only called when a dialog box is dismissed with
1879 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1880 box to be destroyed in that case, not just unmapped, so that it
1881 releases its keyboard grabs. But there are problems with running
1882 our callbacks while the widget is in the process of being
1883 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1884 XmDESTROY and then destroy it ourself after having run the
1886 do_call (widget
, closure
, no_selection
);
1887 XtDestroyWidget (widget
);
1891 xm_pull_down_callback (Widget widget
,
1893 XtPointer call_data
)
1895 Widget parent
= XtParent (widget
);
1897 if (XmIsRowColumn (parent
))
1899 unsigned char type
= 0xff;
1900 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1901 if (type
== XmMENU_BAR
)
1902 do_call (widget
, closure
, pre_activate
);
1907 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1908 CLOSURE is a pointer to the widget_instance of the shell,
1910 Note that this callback is called for each cascade button in a
1911 menu, whether or not its submenu is visible. */
1914 xm_pop_down_callback (Widget widget
,
1916 XtPointer call_data
)
1918 widget_instance
*instance
= (widget_instance
*) closure
;
1920 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1921 || XtParent (widget
) == instance
->parent
)
1922 do_call (widget
, closure
, post_activate
);
1926 /* set the keyboard focus */
1928 xm_set_keyboard_focus (Widget parent
, Widget w
)
1930 XmProcessTraversal (w
, 0);
1931 XtSetKeyboardFocus (parent
, w
);
1934 /* Motif hack to set the main window areas. */
1936 xm_set_main_areas (Widget parent
,
1940 XmMainWindowSetAreas (parent
,
1941 menubar
, /* menubar (maybe 0) */
1942 0, /* command area (psheets) */
1943 0, /* horizontal scroll */
1944 0, /* vertical scroll */
1945 work_area
); /* work area */
1948 /* Motif hack to control resizing on the menubar. */
1950 xm_manage_resizing (Widget w
, Boolean flag
)
1952 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);