1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2017 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 static XmString
resource_motif_string (Widget
, char *);
83 static void destroy_all_children (Widget
, int);
84 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
85 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
86 static void xm_update_pushbutton (widget_instance
*, Widget
,
88 static void xm_update_cascadebutton (widget_instance
*, Widget
,
90 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
91 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
92 static void make_menu_in_widget (widget_instance
*, Widget
,
94 static void update_one_menu_entry (widget_instance
*, Widget
,
95 widget_value
*, Boolean
);
96 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
98 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
99 static void xm_update_text_field (widget_instance
*, Widget
,
101 static void activate_button (Widget
, XtPointer
, XtPointer
);
102 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
103 Boolean
, Boolean
, Boolean
, int, int);
104 static destroyed_instance
* find_matching_instance (widget_instance
*);
105 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
106 static void recenter_widget (Widget
);
107 static Widget
recycle_instance (destroyed_instance
*);
108 static Widget
make_menubar (widget_instance
*);
109 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
110 static Widget
make_popup_menu (widget_instance
*);
111 static Widget
make_main (widget_instance
*);
112 static void set_min_dialog_size (Widget
);
113 static void do_call (Widget
, XtPointer
, enum do_call_type
);
114 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
115 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
116 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
117 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
118 static void xm_internal_update_other_instances (Widget
, XtPointer
,
120 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
123 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
125 void xm_pop_instance (widget_instance
*, Boolean
);
126 void xm_manage_resizing (Widget
, Boolean
);
132 /* Print the complete X resource name of widget WIDGET to stderr.
133 This is sometimes handy to have available. */
136 x_print_complete_resource_name (Widget widget
)
141 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
143 names
[i
] = XtName (widget
);
144 widget
= XtParent (widget
);
147 for (--i
; i
>= 1; --i
)
148 fprintf (stderr
, "%s.", names
[i
]);
149 fprintf (stderr
, "%s\n", names
[0]);
155 static destroyed_instance
*all_destroyed_instances
= NULL
;
157 static destroyed_instance
*
158 make_destroyed_instance (char* name
,
164 destroyed_instance
* instance
=
165 (destroyed_instance
*) xmalloc (sizeof (destroyed_instance
));
166 instance
->name
= xstrdup (name
);
167 instance
->type
= xstrdup (type
);
168 instance
->widget
= widget
;
169 instance
->parent
= parent
;
170 instance
->pop_up_p
= pop_up_p
;
171 instance
->next
= NULL
;
176 free_destroyed_instance (destroyed_instance
* instance
)
178 xfree (instance
->name
);
179 xfree (instance
->type
);
183 \f/* motif utility functions */
185 first_child (Widget widget
)
187 return ((CompositeWidget
)widget
)->composite
.children
[0];
191 lw_motif_widget_p (Widget widget
)
194 XtClass (widget
) == xmDialogShellWidgetClass
195 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
199 resource_motif_string (Widget widget
,
205 resource
.resource_name
= name
;
206 resource
.resource_class
= XmCXmString
;
207 resource
.resource_type
= XmRXmString
;
208 resource
.resource_size
= sizeof (XmString
);
209 resource
.resource_offset
= 0;
210 resource
.default_type
= XtRImmediate
;
211 resource
.default_addr
= 0;
213 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
214 "DialogString", &resource
, 1, NULL
, 0);
218 /* Destroy all of the children of WIDGET
219 starting with number FIRST_CHILD_TO_DESTROY. */
222 destroy_all_children (Widget widget
,
223 int first_child_to_destroy
)
229 children
= XtCompositeChildren (widget
, &number
);
232 XtUnmanageChildren (children
+ first_child_to_destroy
,
233 number
- first_child_to_destroy
);
235 /* Unmanage all children and destroy them. They will only be
236 really destroyed when we get out of DispatchEvent. */
237 for (i
= first_child_to_destroy
; i
< number
; i
++)
241 /* Cascade buttons have submenus,and these submenus
242 need to be freed. But they are not included in
243 XtCompositeChildren. So get it out of the cascade button
244 and free it. If this child is not a cascade button,
245 then submenu should remain unchanged. */
246 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
247 XtGetValues (children
[i
], al
, 1);
250 destroy_all_children (submenu
, 0);
251 XtDestroyWidget (submenu
);
253 XtDestroyWidget (children
[i
]);
256 XtFree ((char *) children
);
262 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
263 menu. CLIENT_DATA contains a pointer to the widget_value
264 corresponding to widget W. CALL_DATA contains a
265 XmPushButtonCallbackStruct containing the reason why the callback
269 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
271 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
272 widget_value
*wv
= (widget_value
*) client_data
;
273 widget_instance
*instance
;
275 /* Get the id of the menu bar or popup menu this widget is in. */
278 if (XmIsRowColumn (w
))
280 unsigned char type
= 0xff;
282 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
283 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
292 instance
= lw_get_widget_instance (w
);
293 if (instance
&& instance
->info
->highlight_cb
)
295 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
296 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
303 /* Update the label of widget WIDGET. WIDGET must be a Label widget
304 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
309 Emacs fills VAL->name with the text to display in the menu, and
310 sets VAL->value to null. Function make_menu_in_widget creates
311 widgets with VAL->name as resource name. This works because the
312 Label widget uses its resource name for display if no
313 XmNlabelString is set.
317 VAL->name is again set to the resource name, but VAL->value is
318 not null, and contains the label string to display. */
321 xm_update_label (widget_instance
* instance
,
325 XmString res_string
= 0;
326 XmString built_string
= 0;
327 XmString key_string
= 0;
335 /* A label string is specified, i.e. we are in a dialog. First
336 see if it is overridden by something from the resource file. */
337 res_string
= resource_motif_string (widget
, val
->value
);
341 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
346 XmStringCreateLocalized (val
->value
);
347 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
350 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
355 key_string
= XmStringCreateLocalized (val
->key
);
356 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
360 XtSetValues (widget
, al
, ac
);
363 XmStringFree (built_string
);
366 XmStringFree (key_string
);
369 \f/* update of list */
371 xm_update_list (widget_instance
* instance
,
377 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
378 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
380 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
383 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
385 XmListAddItem (widget
, xmstr
, 0);
387 XmListSelectPos (widget
, i
, False
);
388 XmStringFree (xmstr
);
392 \f/* update of buttons */
394 xm_update_pushbutton (widget_instance
* instance
,
398 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
399 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
400 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
404 xm_update_cascadebutton (widget_instance
* instance
,
408 /* Should also rebuild the menu by calling ...update_menu... */
409 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
410 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
414 \f/* update toggle and radiobox */
416 xm_update_toggle (widget_instance
* instance
,
420 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
421 XtAddCallback (widget
, XmNvalueChangedCallback
,
422 xm_generic_callback
, instance
);
423 XtVaSetValues (widget
, XmNset
, val
->selected
,
424 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
428 xm_update_radiobox (widget_instance
* instance
,
436 /* update the callback */
437 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
438 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
440 /* first update all the toggles */
441 /* Energize kernel interface is currently bad. It sets the selected widget
442 with the selected flag but returns it by its name. So we currently
443 have to support both setting the selection with the selected slot
444 of val contents and setting it with the "value" slot of val. The latter
445 has a higher priority. This to be removed when the kernel is fixed. */
446 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
448 toggle
= XtNameToWidget (widget
, cur
->value
);
451 XtSetSensitive (toggle
, cur
->enabled
);
452 if (!val
->value
&& cur
->selected
)
453 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
454 if (val
->value
&& strcmp (val
->value
, cur
->value
))
455 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
459 /* The selected was specified by the value slot */
462 toggle
= XtNameToWidget (widget
, val
->value
);
464 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
469 /* update a popup menu, pulldown menu or a menubar */
471 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
474 make_menu_in_widget (widget_instance
* instance
,
477 int keep_first_children
)
479 Widget
* children
= 0;
490 Widget
* old_children
;
491 unsigned int old_num_children
;
493 /* Disable drag and drop for labels in menu bar. */
494 static char overrideTrans
[] = "<Btn2Down>: Noop()";
495 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
497 old_children
= XtCompositeChildren (widget
, &old_num_children
);
499 /* Allocate the children array */
500 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
502 children
= (Widget
*)(void*)XtMalloc (num_children
* sizeof (Widget
));
504 /* WIDGET should be a RowColumn. */
505 if (!XmIsRowColumn (widget
))
508 /* Determine whether WIDGET is a menu bar. */
510 XtSetArg (al
[0], XmNrowColumnType
, &type
);
511 XtGetValues (widget
, al
, 1);
512 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
514 menubar_p
= type
== XmMENU_BAR
;
516 /* Add a callback to popups and pulldowns that is called when
517 it is made invisible again. */
519 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
520 xm_pop_down_callback
, (XtPointer
)instance
);
522 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
523 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
524 child_index
++, cur
= cur
->next
)
525 children
[child_index
] = old_children
[child_index
];
527 /* Check that those are all we have
528 (the caller should have deleted the rest). */
529 if (old_num_children
!= keep_first_children
)
532 /* Create the rest. */
533 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
535 enum menu_separator separator
;
538 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
539 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
540 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
542 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
543 && !lw_separator_p (cur
->name
, &separator
, 1))
546 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
547 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
549 else if (lw_separator_p (cur
->name
, &separator
, 1))
552 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
553 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
555 else if (!cur
->contents
)
558 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
559 else if (!cur
->call_data
)
560 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
561 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
562 || cur
->button_type
== BUTTON_TYPE_RADIO
)
564 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
565 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
566 XtSetArg (al
[ac
], XmNindicatorType
,
567 (cur
->button_type
== BUTTON_TYPE_TOGGLE
568 ? XmN_OF_MANY
: XmONE_OF_MANY
));
570 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
571 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
572 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
576 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
577 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
578 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
581 xm_update_label (instance
, button
, cur
);
583 /* Add a callback that is called when the button is
584 selected. Toggle buttons don't support
585 XmNactivateCallback, we use XmNvalueChangedCallback in
586 that case. Don't add a callback to a simple label. */
587 if (cur
->button_type
)
588 xm_update_toggle (instance
, button
, cur
);
589 else if (cur
->call_data
)
590 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
591 (XtPointer
)instance
);
595 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
597 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
598 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
599 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
601 xm_update_label (instance
, button
, cur
);
603 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
604 (XtPointer
)instance
);
605 XtOverrideTranslations (button
, override
);
609 children
[child_index
] = button
;
612 /* Last entry is the help button. The original comment read "Has to
613 be done after managing the buttons otherwise the menubar is only
614 4 pixels high." This is no longer true, and to make
615 XmNmenuHelpWidget work, we need to set it before managing the
616 children.. --gerd. */
618 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
621 XtManageChildren (children
, num_children
);
623 XtFree ((char *) children
);
625 XtFree ((char *) old_children
);
629 update_one_menu_entry (widget_instance
* instance
,
637 widget_value
* contents
;
639 if (val
->this_one_change
== NO_CHANGE
)
642 /* update the sensitivity and userdata */
643 /* Common to all widget types */
644 XtSetSensitive (widget
, val
->enabled
);
645 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
647 /* update the menu button as a label. */
648 if (val
->this_one_change
>= VISIBLE_CHANGE
)
650 xm_update_label (instance
, widget
, val
);
651 if (val
->button_type
)
652 xm_update_toggle (instance
, widget
, val
);
655 /* update the pulldown/pullaside as needed */
658 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
659 XtGetValues (widget
, al
, ac
);
661 contents
= val
->contents
;
667 unsigned int old_num_children
, i
;
671 parent
= XtParent (widget
);
672 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
674 /* Find the widget position within the parent's widget list. */
675 for (i
= 0; i
< old_num_children
; i
++)
676 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
678 if (i
== old_num_children
)
680 if (XmIsCascadeButton (widget_list
[i
]))
682 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
683 make_menu_in_widget (instance
, menu
, contents
, 0);
685 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
686 XtSetValues (widget
, al
, ac
);
692 /* The current menuitem is a XmPushButtonGadget, it
693 needs to be replaced by a CascadeButtonGadget */
694 XtDestroyWidget (widget_list
[i
]);
695 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
696 make_menu_in_widget (instance
, menu
, contents
, 0);
698 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
699 /* Non-zero values don't work reliably in
700 conjunction with Emacs' event loop */
701 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
702 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
703 /* Tell Motif to put it in the right place */
704 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
706 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
707 xm_update_label (instance
, button
, val
);
709 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
710 (XtPointer
)instance
);
711 XtManageChild (button
);
715 XtFree ((char*) widget_list
);
721 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
722 XtSetValues (widget
, al
, ac
);
723 XtDestroyWidget (menu
);
725 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
726 xm_update_menu (instance
, menu
, val
, 1);
730 xm_update_menu (widget_instance
* instance
,
736 unsigned int num_children
;
737 int num_children_to_keep
= 0;
741 children
= XtCompositeChildren (widget
, &num_children
);
743 /* Widget is a RowColumn widget whose contents have to be updated
744 * to reflect the list of items in val->contents */
746 /* See how many buttons we can keep, and how many we
747 must completely replace. */
748 if (val
->contents
== 0)
749 num_children_to_keep
= 0;
750 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
754 for (i
= 0, cur
= val
->contents
;
756 && cur
); /* how else to ditch unwanted children ?? - mgd */
757 i
++, cur
= cur
->next
)
759 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
763 num_children_to_keep
= i
;
767 num_children_to_keep
= num_children
;
769 /* Update all the buttons of the RowColumn, in order,
770 except for those we are going to replace entirely. */
773 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
777 num_children_to_keep
= i
;
780 if (children
[i
]->core
.being_destroyed
781 || strcmp (XtName (children
[i
]), cur
->name
))
783 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
788 /* Now replace from scratch all the buttons after the last
789 place that the top-level structure changed. */
790 if (val
->contents
&& val
->contents
->change
== STRUCTURAL_CHANGE
)
792 destroy_all_children (widget
, num_children_to_keep
);
793 make_menu_in_widget (instance
, widget
, val
->contents
,
794 num_children_to_keep
);
797 XtFree ((char *) children
);
801 /* update text widgets */
804 xm_update_text (widget_instance
* instance
,
808 XmTextSetString (widget
, val
->value
? val
->value
: "");
809 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
810 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
811 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
812 XtAddCallback (widget
, XmNvalueChangedCallback
,
813 xm_internal_update_other_instances
, instance
);
817 xm_update_text_field (widget_instance
* instance
,
821 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
822 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
823 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
824 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
825 XtAddCallback (widget
, XmNvalueChangedCallback
,
826 xm_internal_update_other_instances
, instance
);
830 /* update a motif widget */
833 xm_update_one_widget (widget_instance
* instance
,
840 /* Mark as not edited */
843 /* Common to all widget types */
844 XtSetSensitive (widget
, val
->enabled
);
845 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
847 /* Common to all label like widgets */
848 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
849 xm_update_label (instance
, widget
, val
);
851 class = XtClass (widget
);
852 /* Class specific things */
853 if (class == xmPushButtonWidgetClass
||
854 class == xmArrowButtonWidgetClass
)
856 xm_update_pushbutton (instance
, widget
, val
);
858 else if (class == xmCascadeButtonWidgetClass
)
860 xm_update_cascadebutton (instance
, widget
, val
);
862 else if (class == xmToggleButtonWidgetClass
863 || class == xmToggleButtonGadgetClass
)
865 xm_update_toggle (instance
, widget
, val
);
867 else if (class == xmRowColumnWidgetClass
)
869 Boolean radiobox
= 0;
873 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
874 XtGetValues (widget
, al
, ac
);
877 xm_update_radiobox (instance
, widget
, val
);
879 xm_update_menu (instance
, widget
, val
, deep_p
);
881 else if (class == xmTextWidgetClass
)
883 xm_update_text (instance
, widget
, val
);
885 else if (class == xmTextFieldWidgetClass
)
887 xm_update_text_field (instance
, widget
, val
);
889 else if (class == xmListWidgetClass
)
891 xm_update_list (instance
, widget
, val
);
895 \f/* getting the value back */
897 xm_update_one_value (widget_instance
* instance
,
901 WidgetClass
class = XtClass (widget
);
902 widget_value
*old_wv
;
904 /* copy the call_data slot into the "return" widget_value */
905 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
906 if (!strcmp (val
->name
, old_wv
->name
))
908 val
->call_data
= old_wv
->call_data
;
912 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
914 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
917 else if (class == xmTextWidgetClass
)
920 val
->value
= XmTextGetString (widget
);
923 else if (class == xmTextFieldWidgetClass
)
926 val
->value
= XmTextFieldGetString (widget
);
929 else if (class == xmRowColumnWidgetClass
)
931 Boolean radiobox
= 0;
935 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
936 XtGetValues (widget
, al
, ac
);
940 CompositeWidget radio
= (CompositeWidget
)widget
;
942 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
945 Widget toggle
= radio
->composite
.children
[i
];
947 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
949 dupstring (&val
->value
, XtName (toggle
));
954 else if (class == xmListWidgetClass
)
958 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
962 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
966 cur
->selected
= False
;
968 for (j
= 0; j
< pos_cnt
; j
++)
969 if (pos_list
[j
] == i
)
971 cur
->selected
= True
;
972 val
->value
= xstrdup (cur
->name
);
976 XtFree ((char *) pos_list
);
982 /* This function is for activating a button from a program. It's wrong because
983 we pass a NULL argument in the call_data which is not Motif compatible.
984 This is used from the XmNdefaultAction callback of the List widgets to
985 have a double-click put down a dialog box like the button would do.
986 I could not find a way to do that with accelerators.
989 activate_button (Widget widget
,
993 Widget button
= (Widget
)closure
;
994 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
997 /* creation functions */
999 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1001 dialog_key_cb (Widget widget
,
1004 Boolean
*continue_to_dispatch
)
1007 Modifiers modif_ret
;
1009 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1012 if (sym
== osfXK_Cancel
)
1014 Widget w
= *((Widget
*) closure
);
1016 while (w
&& ! XtIsShell (w
))
1019 if (XtIsShell (w
)) XtPopdown (w
);
1022 *continue_to_dispatch
= TRUE
;
1027 make_dialog (char* name
,
1032 Boolean text_input_slot
,
1042 Widget icon_separator
;
1043 Widget message_label
;
1047 Widget children
[16]; /* for the final XtManageChildren */
1049 Arg al
[64]; /* Arg List */
1050 int ac
; /* Arg Count */
1056 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1057 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1058 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1059 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1061 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1062 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1063 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1064 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1069 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1070 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1071 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1075 n_children
= left_buttons
+ right_buttons
+ 1;
1077 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1078 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1079 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1080 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1081 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1082 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1083 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1084 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1085 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1086 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1087 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1088 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1089 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1090 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1091 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1092 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1093 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1094 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1095 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1098 for (i
= 0; i
< left_buttons
; i
++)
1100 char button_name
[16];
1101 sprintf (button_name
, "button%d", i
+ 1);
1105 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1106 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1108 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1109 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1110 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1111 XtAddEventHandler (children
[n_children
],
1112 KeyPressMask
, False
, dialog_key_cb
, result
);
1116 button
= children
[n_children
];
1118 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1119 XtSetValues (row
, al
, ac
);
1125 /* invisible separator button */
1127 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1128 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1131 for (i
= 0; i
< right_buttons
; i
++)
1133 char button_name
[16];
1134 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1136 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1137 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1138 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1139 XtAddEventHandler (children
[n_children
],
1140 KeyPressMask
, False
, dialog_key_cb
, result
);
1142 if (! button
) button
= children
[n_children
];
1146 XtManageChildren (children
, n_children
);
1149 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1150 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1151 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1152 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1153 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1154 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1155 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1156 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1157 separator
= XmCreateSeparator (form
, "", al
, ac
);
1160 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1161 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1162 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1163 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1164 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1165 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1166 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1167 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1170 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1171 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1172 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1173 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1174 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1175 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1176 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1177 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1178 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1179 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1181 if (text_input_slot
)
1184 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1185 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1186 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1187 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1188 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1189 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1190 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1191 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1192 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1193 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1194 value
= XmCreateTextField (form
, "value", al
, ac
);
1200 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1201 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1202 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1203 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1204 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1205 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1206 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1207 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1208 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1209 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1210 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1211 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1212 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1213 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1216 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1217 children
[i
++] = radio_butt
;
1218 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1219 children
[i
++] = radio_butt
;
1220 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1221 children
[i
++] = radio_butt
;
1222 XtManageChildren (children
, i
);
1227 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1228 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1229 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1230 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1231 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1232 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1233 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1234 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1235 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1236 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1237 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1239 /* this is the easiest way I found to have the dble click in the
1240 list activate the default button */
1241 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1245 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1246 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1247 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1248 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1249 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1250 XtSetArg(al
[ac
], XmNbottomWidget
,
1251 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1252 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1253 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1254 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1255 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1256 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1257 message_label
= XmCreateLabel (form
, "message", al
, ac
);
1260 XtManageChild (value
);
1263 children
[i
] = row
; i
++;
1264 children
[i
] = separator
; i
++;
1265 if (text_input_slot
|| radio_box
)
1267 children
[i
] = value
; i
++;
1269 children
[i
] = message_label
; i
++;
1270 children
[i
] = icon
; i
++;
1271 children
[i
] = icon_separator
; i
++;
1272 XtManageChildren (children
, i
);
1274 if (text_input_slot
|| list
)
1276 XtInstallAccelerators (value
, button
);
1277 XtSetKeyboardFocus (result
, value
);
1281 XtInstallAccelerators (form
, button
);
1282 XtSetKeyboardFocus (result
, button
);
1288 static destroyed_instance
*
1289 find_matching_instance (widget_instance
* instance
)
1291 destroyed_instance
* cur
;
1292 destroyed_instance
* prev
;
1293 char* type
= instance
->info
->type
;
1294 char* name
= instance
->info
->name
;
1296 for (prev
= NULL
, cur
= all_destroyed_instances
;
1298 prev
= cur
, cur
= cur
->next
)
1300 if (!strcmp (cur
->name
, name
)
1301 && !strcmp (cur
->type
, type
)
1302 && cur
->parent
== instance
->parent
1303 && cur
->pop_up_p
== instance
->pop_up_p
)
1306 prev
->next
= cur
->next
;
1308 all_destroyed_instances
= cur
->next
;
1311 /* do some cleanup */
1312 else if (!cur
->widget
)
1315 prev
->next
= cur
->next
;
1317 all_destroyed_instances
= cur
->next
;
1318 free_destroyed_instance (cur
);
1319 cur
= prev
? prev
: all_destroyed_instances
;
1326 mark_dead_instance_destroyed (Widget widget
,
1328 XtPointer call_data
)
1330 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1331 instance
->widget
= NULL
;
1335 recenter_widget (Widget widget
)
1337 Widget parent
= XtParent (widget
);
1338 Screen
* screen
= XtScreen (widget
);
1339 Dimension screen_width
= WidthOfScreen (screen
);
1340 Dimension screen_height
= HeightOfScreen (screen
);
1341 Dimension parent_width
= 0;
1342 Dimension parent_height
= 0;
1343 Dimension child_width
= 0;
1344 Dimension child_height
= 0;
1348 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1349 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1352 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1353 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1355 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1357 if (x
+ child_width
> screen_width
)
1358 x
= screen_width
- child_width
;
1362 if (y
+ child_height
> screen_height
)
1363 y
= screen_height
- child_height
;
1367 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1371 recycle_instance (destroyed_instance
* instance
)
1373 Widget widget
= instance
->widget
;
1375 /* widget is NULL if the parent was destroyed. */
1381 /* Remove the destroy callback as the instance is not in the list
1383 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1384 mark_dead_instance_destroyed
,
1385 (XtPointer
)instance
);
1387 /* Give the focus to the initial item */
1388 focus
= XtNameToWidget (widget
, "*value");
1390 focus
= XtNameToWidget (widget
, "*button1");
1392 XtSetKeyboardFocus (widget
, focus
);
1394 /* shrink the separator label back to their original size */
1395 separator
= XtNameToWidget (widget
, "*separator_button");
1397 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1399 /* Center the dialog in its parent */
1400 recenter_widget (widget
);
1402 free_destroyed_instance (instance
);
1407 xm_create_dialog (widget_instance
* instance
)
1409 char* name
= instance
->info
->type
;
1410 Widget parent
= instance
->parent
;
1412 Boolean pop_up_p
= instance
->pop_up_p
;
1413 char* shell_name
= 0;
1414 char* icon_name
= 0;
1415 Boolean text_input_slot
= False
;
1416 Boolean radio_box
= False
;
1417 Boolean list
= False
;
1419 int left_buttons
= 0;
1420 int right_buttons
= 1;
1421 destroyed_instance
* dead_one
;
1423 /* try to find a widget to recycle */
1424 dead_one
= find_matching_instance (instance
);
1427 Widget recycled_widget
= recycle_instance (dead_one
);
1428 if (recycled_widget
)
1429 return recycled_widget
;
1434 icon_name
= "dbox-error";
1435 shell_name
= "Error";
1439 icon_name
= "dbox-info";
1440 shell_name
= "Information";
1445 icon_name
= "dbox-question";
1446 shell_name
= "Prompt";
1450 text_input_slot
= True
;
1451 icon_name
= "dbox-question";
1452 shell_name
= "Prompt";
1456 icon_name
= "dbox-question";
1457 shell_name
= "Question";
1461 total_buttons
= name
[1] - '0';
1463 if (name
[3] == 'T' || name
[3] == 't')
1465 text_input_slot
= False
;
1469 right_buttons
= name
[4] - '0';
1471 left_buttons
= total_buttons
- right_buttons
;
1473 widget
= make_dialog (name
, parent
, pop_up_p
,
1474 shell_name
, icon_name
, text_input_slot
, radio_box
,
1475 list
, left_buttons
, right_buttons
);
1477 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1478 (XtPointer
) instance
);
1483 /* Create a menu bar. We turn off the f10 key
1484 because we have not yet managed to make it work right in Motif. */
1487 make_menubar (widget_instance
* instance
)
1493 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1494 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1498 remove_grabs (Widget shell
,
1500 XtPointer call_data
)
1502 Widget menu
= (Widget
) closure
;
1503 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1507 make_popup_menu (widget_instance
* instance
)
1509 Widget parent
= instance
->parent
;
1510 Window parent_window
= parent
->core
.window
;
1513 /* sets the parent window to 0 to fool Motif into not generating a grab */
1514 parent
->core
.window
= 0;
1515 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1516 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1518 parent
->core
.window
= parent_window
;
1523 make_main (widget_instance
* instance
)
1525 Widget parent
= instance
->parent
;
1531 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1532 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1533 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1537 \f/* Table of functions to create widgets */
1541 /* interface with the XDesigner generated functions */
1542 typedef Widget (*widget_maker
) (Widget
);
1543 extern Widget
create_project_p_sheet (Widget parent
);
1544 extern Widget
create_debugger_p_sheet (Widget parent
);
1545 extern Widget
create_breaklist_p_sheet (Widget parent
);
1546 extern Widget
create_le_browser_p_sheet (Widget parent
);
1547 extern Widget
create_class_browser_p_sheet (Widget parent
);
1548 extern Widget
create_call_browser_p_sheet (Widget parent
);
1549 extern Widget
create_build_dialog (Widget parent
);
1550 extern Widget
create_editmode_dialog (Widget parent
);
1551 extern Widget
create_search_dialog (Widget parent
);
1552 extern Widget
create_project_display_dialog (Widget parent
);
1555 make_one (widget_instance
* instance
, widget_maker fn
)
1561 if (instance
->pop_up_p
)
1563 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1564 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1565 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1566 (XtPointer
) instance
);
1571 result
= (*fn
) (instance
->parent
);
1572 XtRealizeWidget (result
);
1578 make_project_p_sheet (widget_instance
* instance
)
1580 return make_one (instance
, create_project_p_sheet
);
1584 make_debugger_p_sheet (widget_instance
* instance
)
1586 return make_one (instance
, create_debugger_p_sheet
);
1590 make_breaklist_p_sheet (widget_instance
* instance
)
1592 return make_one (instance
, create_breaklist_p_sheet
);
1596 make_le_browser_p_sheet (widget_instance
* instance
)
1598 return make_one (instance
, create_le_browser_p_sheet
);
1602 make_class_browser_p_sheet (widget_instance
* instance
)
1604 return make_one (instance
, create_class_browser_p_sheet
);
1608 make_call_browser_p_sheet (widget_instance
* instance
)
1610 return make_one (instance
, create_call_browser_p_sheet
);
1614 make_build_dialog (widget_instance
* instance
)
1616 return make_one (instance
, create_build_dialog
);
1620 make_editmode_dialog (widget_instance
* instance
)
1622 return make_one (instance
, create_editmode_dialog
);
1626 make_search_dialog (widget_instance
* instance
)
1628 return make_one (instance
, create_search_dialog
);
1632 make_project_display_dialog (widget_instance
* instance
)
1634 return make_one (instance
, create_project_display_dialog
);
1637 #endif /* ENERGIZE */
1639 widget_creation_entry
1640 xm_creation_table
[] =
1642 {"menubar", make_menubar
},
1643 {"popup", make_popup_menu
},
1644 {"main", make_main
},
1646 {"project_p_sheet", make_project_p_sheet
},
1647 {"debugger_p_sheet", make_debugger_p_sheet
},
1648 {"breaklist_psheet", make_breaklist_p_sheet
},
1649 {"leb_psheet", make_le_browser_p_sheet
},
1650 {"class_browser_psheet", make_class_browser_p_sheet
},
1651 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1652 {"build", make_build_dialog
},
1653 {"editmode", make_editmode_dialog
},
1654 {"search", make_search_dialog
},
1655 {"project_display", make_project_display_dialog
},
1656 #endif /* ENERGIZE */
1660 \f/* Destruction of instances */
1662 xm_destroy_instance ( widget_instance
* instance
)
1664 Widget widget
= instance
->widget
;
1665 /* recycle the dialog boxes */
1666 /* Disable the recycling until we can find a way to have the dialog box
1667 get reasonable layout after we modify its contents. */
1669 && XtClass (widget
) == xmDialogShellWidgetClass
)
1671 destroyed_instance
* dead_instance
=
1672 make_destroyed_instance (instance
->info
->name
,
1673 instance
->info
->type
,
1676 instance
->pop_up_p
);
1677 dead_instance
->next
= all_destroyed_instances
;
1678 all_destroyed_instances
= dead_instance
;
1679 XtUnmanageChild (first_child (instance
->widget
));
1680 XFlush (XtDisplay (instance
->widget
));
1681 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1682 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1686 /* This might not be necessary now that the nosel is attached to
1687 popdown instead of destroy, but it can't hurt. */
1688 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1689 xm_nosel_callback
, (XtPointer
)instance
);
1690 XtDestroyWidget (instance
->widget
);
1694 \f/* popup utility */
1696 xm_popup_menu (Widget widget
, XEvent
*event
)
1698 XButtonPressedEvent dummy
;
1702 dummy
.type
= ButtonPress
;
1704 dummy
.send_event
= 0;
1705 dummy
.display
= XtDisplay (widget
);
1706 dummy
.window
= XtWindow (XtParent (widget
));
1709 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1710 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1711 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1712 event
= (XEvent
*) &dummy
;
1715 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1717 /* Setting the menuPost resource only required by Motif 1.1 and
1718 LessTif 0.84 and earlier. With later versions of LessTif,
1719 setting menuPost is unnecessary and may cause problems, so
1721 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1723 /* This is so totally ridiculous: there's NO WAY to tell Motif
1724 that *any* button can select a menu item. Only one button
1725 can have that honor. */
1728 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1729 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1730 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1731 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1732 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1733 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1737 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1740 XtManageChild (widget
);
1744 set_min_dialog_size (Widget w
)
1748 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1749 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1753 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1755 Widget widget
= instance
->widget
;
1757 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1759 Widget widget_to_manage
= first_child (widget
);
1762 XtManageChild (widget_to_manage
);
1763 set_min_dialog_size (widget
);
1764 XtSetKeyboardFocus (instance
->parent
, widget
);
1767 XtUnmanageChild (widget_to_manage
);
1772 XtManageChild (widget
);
1774 XtUnmanageChild (widget
);
1779 /* motif callback */
1782 do_call (Widget widget
,
1784 enum do_call_type type
)
1788 XtPointer user_data
;
1789 widget_instance
* instance
= (widget_instance
*)closure
;
1790 Widget instance_widget
;
1795 if (widget
->core
.being_destroyed
)
1798 instance_widget
= instance
->widget
;
1799 if (!instance_widget
)
1802 id
= instance
->info
->id
;
1805 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1806 XtGetValues (widget
, al
, ac
);
1811 if (instance
->info
->pre_activate_cb
)
1812 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1816 if (instance
->info
->selection_cb
)
1817 instance
->info
->selection_cb (widget
, id
, user_data
);
1821 if (instance
->info
->selection_cb
)
1822 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1826 if (instance
->info
->post_activate_cb
)
1827 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1835 /* Like lw_internal_update_other_instances except that it does not do
1836 anything if its shell parent is not managed. This is to protect
1837 lw_internal_update_other_instances to dereference freed memory
1838 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1841 xm_internal_update_other_instances (Widget widget
,
1843 XtPointer call_data
)
1846 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1847 if (XtIsShell (parent
))
1849 else if (!XtIsManaged (parent
))
1851 lw_internal_update_other_instances (widget
, closure
, call_data
);
1855 xm_generic_callback (Widget widget
,
1857 XtPointer call_data
)
1859 lw_internal_update_other_instances (widget
, closure
, call_data
);
1860 do_call (widget
, closure
, selection
);
1864 xm_nosel_callback (Widget widget
,
1866 XtPointer call_data
)
1868 /* This callback is only called when a dialog box is dismissed with
1869 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1870 box to be destroyed in that case, not just unmapped, so that it
1871 releases its keyboard grabs. But there are problems with running
1872 our callbacks while the widget is in the process of being
1873 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1874 XmDESTROY and then destroy it ourself after having run the
1876 do_call (widget
, closure
, no_selection
);
1877 XtDestroyWidget (widget
);
1881 xm_pull_down_callback (Widget widget
,
1883 XtPointer call_data
)
1885 Widget parent
= XtParent (widget
);
1887 if (XmIsRowColumn (parent
))
1889 unsigned char type
= 0xff;
1890 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1891 if (type
== XmMENU_BAR
)
1892 do_call (widget
, closure
, pre_activate
);
1897 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1898 CLOSURE is a pointer to the widget_instance of the shell,
1900 Note that this callback is called for each cascade button in a
1901 menu, whether or not its submenu is visible. */
1904 xm_pop_down_callback (Widget widget
,
1906 XtPointer call_data
)
1908 widget_instance
*instance
= (widget_instance
*) closure
;
1910 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1911 || XtParent (widget
) == instance
->parent
)
1912 do_call (widget
, closure
, post_activate
);
1916 /* set the keyboard focus */
1918 xm_set_keyboard_focus (Widget parent
, Widget w
)
1920 XmProcessTraversal (w
, 0);
1921 XtSetKeyboardFocus (parent
, w
);
1924 /* Motif hack to set the main window areas. */
1926 xm_set_main_areas (Widget parent
,
1930 XmMainWindowSetAreas (parent
,
1931 menubar
, /* menubar (maybe 0) */
1932 0, /* command area (psheets) */
1933 0, /* horizontal scroll */
1934 0, /* vertical scroll */
1935 work_area
); /* work area */
1938 /* Motif hack to control resizing on the menubar. */
1940 xm_manage_resizing (Widget w
, Boolean flag
)
1942 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);