1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
25 #include <X11/StringDefs.h>
26 #include <X11/IntrinsicP.h>
27 #include <X11/ObjectP.h>
28 #include <X11/CoreP.h>
29 #include <X11/CompositeP.h>
32 #include "lwlib-utils.h"
34 #include <Xm/BulletinB.h>
35 #include <Xm/CascadeB.h>
36 #include <Xm/DrawingA.h>
37 #include <Xm/FileSB.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/MessageB.h>
43 #include <Xm/PanedW.h>
45 #include <Xm/PushBG.h>
46 #include <Xm/ArrowB.h>
47 #include <Xm/SelectioB.h>
50 #include <Xm/ToggleB.h>
51 #include <Xm/ToggleBG.h>
52 #include <Xm/RowColumn.h>
53 #include <Xm/ScrolledW.h>
54 #include <Xm/Separator.h>
55 #include <Xm/DialogS.h>
58 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
59 static void xm_internal_update_other_instances (Widget
, XtPointer
,
61 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
62 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
63 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
66 xm_update_menu (widget_instance
* instance
, Widget widget
, widget_value
* val
,
69 \f/* Structures to keep destroyed instances */
70 typedef struct _destroyed_instance
77 struct _destroyed_instance
* next
;
80 static destroyed_instance
*
81 all_destroyed_instances
= NULL
;
83 static destroyed_instance
*
84 make_destroyed_instance (char* name
, char* type
, Widget widget
, Widget parent
,
87 destroyed_instance
* instance
=
88 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
89 instance
->name
= safe_strdup (name
);
90 instance
->type
= safe_strdup (type
);
91 instance
->widget
= widget
;
92 instance
->parent
= parent
;
93 instance
->pop_up_p
= pop_up_p
;
94 instance
->next
= NULL
;
99 free_destroyed_instance (destroyed_instance
* instance
)
101 free (instance
->name
);
102 free (instance
->type
);
106 \f/* motif utility functions */
108 first_child (Widget widget
)
110 return ((CompositeWidget
)widget
)->composite
.children
[0];
114 lw_motif_widget_p (Widget widget
)
117 XtClass (widget
) == xmDialogShellWidgetClass
118 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
122 resource_motif_string (Widget widget
, char* name
)
127 resource
.resource_name
= name
;
128 resource
.resource_class
= XmCXmString
;
129 resource
.resource_type
= XmRXmString
;
130 resource
.resource_size
= sizeof (XmString
);
131 resource
.resource_offset
= 0;
132 resource
.default_type
= XtRImmediate
;
133 resource
.default_addr
= 0;
135 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
136 "DialogString", &resource
, 1, NULL
, 0);
141 destroy_all_children (Widget widget
)
147 children
= XtCompositeChildren (widget
, &number
);
150 /* Unmanage all children and destroy them. They will only be
151 * really destroyed when we get out of DispatchEvent. */
152 for (i
= 0; i
< number
; i
++)
154 Widget child
= children
[i
];
155 if (!child
->core
.being_destroyed
)
157 XtUnmanageChild (child
);
158 XtDestroyWidget (child
);
161 XtFree ((char *) children
);
165 \f/* update the label of anything subclass of a label */
167 xm_update_label (widget_instance
* instance
, Widget widget
, widget_value
* val
)
169 XmString res_string
= 0;
170 XmString built_string
= 0;
171 XmString key_string
= 0;
179 res_string
= resource_motif_string (widget
, val
->value
);
183 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
188 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
189 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
191 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
196 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
197 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
201 XtSetValues (widget
, al
, ac
);
204 XmStringFree (built_string
);
207 XmStringFree (key_string
);
210 \f/* update of list */
212 xm_update_list (widget_instance
* instance
, Widget widget
, widget_value
* val
)
216 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
217 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
219 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
222 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
224 XmListAddItem (widget
, xmstr
, 0);
226 XmListSelectPos (widget
, i
, False
);
227 XmStringFree (xmstr
);
231 \f/* update of buttons */
233 xm_update_pushbutton (widget_instance
* instance
, Widget widget
,
236 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, 0);
237 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
238 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
242 xm_update_cascadebutton (widget_instance
* instance
, Widget widget
,
245 /* Should also rebuild the menu by calling ...update_menu... */
246 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
247 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
251 \f/* update toggle and radiobox */
253 xm_update_toggle (widget_instance
* instance
, Widget widget
, widget_value
* val
)
255 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
256 XtAddCallback (widget
, XmNvalueChangedCallback
,
257 xm_internal_update_other_instances
, instance
);
258 XtVaSetValues (widget
, XmNset
, val
->selected
,
259 XmNalignment
, XmALIGNMENT_BEGINNING
, 0);
263 xm_update_radiobox (widget_instance
* instance
, Widget widget
,
269 /* update the callback */
270 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
271 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
273 /* first update all the toggles */
274 /* Energize kernel interface is currently bad. It sets the selected widget
275 with the selected flag but returns it by its name. So we currently
276 have to support both setting the selection with the selected slot
277 of val contents and setting it with the "value" slot of val. The latter
278 has a higher priority. This to be removed when the kernel is fixed. */
279 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
281 toggle
= XtNameToWidget (widget
, cur
->value
);
284 XtVaSetValues (toggle
, XmNsensitive
, cur
->enabled
, 0);
285 if (!val
->value
&& cur
->selected
)
286 XtVaSetValues (toggle
, XmNset
, cur
->selected
, 0);
287 if (val
->value
&& strcmp (val
->value
, cur
->value
))
288 XtVaSetValues (toggle
, XmNset
, False
, 0);
292 /* The selected was specified by the value slot */
295 toggle
= XtNameToWidget (widget
, val
->value
);
297 XtVaSetValues (toggle
, XmNset
, True
, 0);
301 \f/* update a popup menu, pulldown menu or a menubar */
303 all_dashes_p (char* s
)
313 make_menu_in_widget (widget_instance
* instance
, Widget widget
,
316 Widget
* children
= 0;
326 /* Allocate the children array */
327 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
);
328 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
330 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
332 XtSetArg (al
[0], XmNisHomogeneous
, &menubar_p
);
333 XtGetValues (widget
, al
, 1);
335 /* add the unmap callback for popups and pulldowns */
336 /*** this sounds bogus ***/
338 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
339 xm_pop_down_callback
, (XtPointer
)instance
);
341 for (child_index
= 0, cur
= val
; cur
; child_index
++, cur
= cur
->next
)
344 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
345 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
346 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
348 if (all_dashes_p (cur
->name
))
350 button
= XmCreateSeparator (widget
, cur
->name
, NULL
, 0);
352 else if (!cur
->contents
)
355 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
356 else if (!cur
->call_data
)
357 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
359 button
= XmCreatePushButtonGadget (widget
, cur
->name
, al
, ac
);
361 xm_update_label (instance
, button
, cur
);
363 /* don't add a callback to a simple label */
365 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
366 (XtPointer
)instance
);
370 menu
= XmCreatePulldownMenu (widget
, "pulldown", NULL
, 0);
371 make_menu_in_widget (instance
, menu
, cur
->contents
);
372 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
373 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
375 xm_update_label (instance
, button
, cur
);
377 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
378 (XtPointer
)instance
);
381 children
[child_index
] = button
;
384 XtManageChildren (children
, num_children
);
386 /* Last entry is the help button. Has to be done after managing
387 * the buttons otherwise the menubar is only 4 pixels high... */
391 XtSetArg (al
[ac
], XmNmenuHelpWidget
, button
); ac
++;
392 XtSetValues (widget
, al
, ac
);
395 XtFree ((char *) children
);
399 update_one_menu_entry (widget_instance
* instance
, Widget widget
,
400 widget_value
* val
, Boolean deep_p
)
405 widget_value
* contents
;
407 if (val
->change
== NO_CHANGE
)
410 /* update the sensitivity and userdata */
411 /* Common to all widget types */
412 XtVaSetValues (widget
,
413 XmNsensitive
, val
->enabled
,
414 XmNuserData
, val
->call_data
,
417 /* update the menu button as a label. */
418 if (val
->change
>= VISIBLE_CHANGE
)
419 xm_update_label (instance
, widget
, val
);
421 /* update the pulldown/pullaside as needed */
424 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
425 XtGetValues (widget
, al
, ac
);
427 contents
= val
->contents
;
433 menu
= XmCreatePulldownMenu (widget
, "pulldown", NULL
, 0);
434 make_menu_in_widget (instance
, menu
, contents
);
436 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
437 XtSetValues (widget
, al
, ac
);
443 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
444 XtSetValues (widget
, al
, ac
);
445 XtDestroyWidget (menu
);
447 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
448 xm_update_menu (instance
, menu
, val
, 1);
452 xm_update_menu (widget_instance
* instance
, Widget widget
, widget_value
* val
,
455 /* Widget is a RowColumn widget whose contents have to be updated
456 * to reflect the list of items in val->contents */
457 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
459 destroy_all_children (widget
);
460 make_menu_in_widget (instance
, widget
, val
->contents
);
464 /* Update all the buttons of the RowColumn in order. */
466 unsigned int num_children
;
470 children
= XtCompositeChildren (widget
, &num_children
);
473 for (i
= 0, cur
= val
->contents
; i
< num_children
; i
++)
477 if (children
[i
]->core
.being_destroyed
478 || strcmp (XtName (children
[i
]), cur
->name
))
480 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
483 XtFree ((char *) children
);
491 /* update text widgets */
494 xm_update_text (widget_instance
* instance
, Widget widget
, widget_value
* val
)
496 XmTextSetString (widget
, val
->value
? val
->value
: "");
497 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
498 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
499 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
500 XtAddCallback (widget
, XmNvalueChangedCallback
,
501 xm_internal_update_other_instances
, instance
);
505 xm_update_text_field (widget_instance
* instance
, Widget widget
,
508 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
509 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
510 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
511 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
512 XtAddCallback (widget
, XmNvalueChangedCallback
,
513 xm_internal_update_other_instances
, instance
);
517 /* update a motif widget */
520 xm_update_one_widget (widget_instance
* instance
, Widget widget
,
521 widget_value
* val
, Boolean deep_p
)
525 /* Mark as not edited */
528 /* Common to all widget types */
529 XtVaSetValues (widget
,
530 XmNsensitive
, val
->enabled
,
531 XmNuserData
, val
->call_data
,
534 /* Common to all label like widgets */
535 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
536 xm_update_label (instance
, widget
, val
);
538 class = XtClass (widget
);
539 /* Class specific things */
540 if (class == xmPushButtonWidgetClass
||
541 class == xmArrowButtonWidgetClass
)
543 xm_update_pushbutton (instance
, widget
, val
);
545 else if (class == xmCascadeButtonWidgetClass
)
547 xm_update_cascadebutton (instance
, widget
, val
);
549 else if (class == xmToggleButtonWidgetClass
550 || class == xmToggleButtonGadgetClass
)
552 xm_update_toggle (instance
, widget
, val
);
554 else if (class == xmRowColumnWidgetClass
)
556 Boolean radiobox
= 0;
560 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
561 XtGetValues (widget
, al
, ac
);
564 xm_update_radiobox (instance
, widget
, val
);
566 xm_update_menu (instance
, widget
, val
, deep_p
);
568 else if (class == xmTextWidgetClass
)
570 xm_update_text (instance
, widget
, val
);
572 else if (class == xmTextFieldWidgetClass
)
574 xm_update_text_field (instance
, widget
, val
);
576 else if (class == xmListWidgetClass
)
578 xm_update_list (instance
, widget
, val
);
582 \f/* getting the value back */
584 xm_update_one_value (widget_instance
* instance
, Widget widget
,
587 WidgetClass
class = XtClass (widget
);
588 widget_value
*old_wv
;
590 /* copy the call_data slot into the "return" widget_value */
591 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
592 if (!strcmp (val
->name
, old_wv
->name
))
594 val
->call_data
= old_wv
->call_data
;
598 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
600 XtVaGetValues (widget
, XmNset
, &val
->selected
, 0);
603 else if (class == xmTextWidgetClass
)
607 val
->value
= XmTextGetString (widget
);
610 else if (class == xmTextFieldWidgetClass
)
614 val
->value
= XmTextFieldGetString (widget
);
617 else if (class == xmRowColumnWidgetClass
)
619 Boolean radiobox
= 0;
623 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
624 XtGetValues (widget
, al
, ac
);
628 CompositeWidget radio
= (CompositeWidget
)widget
;
630 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
633 Widget toggle
= radio
->composite
.children
[i
];
635 XtVaGetValues (toggle
, XmNset
, &set
, 0);
640 val
->value
= safe_strdup (XtName (toggle
));
646 else if (class == xmListWidgetClass
)
650 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
654 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
658 cur
->selected
= False
;
660 for (j
= 0; j
< pos_cnt
; j
++)
661 if (pos_list
[j
] == i
)
663 cur
->selected
= True
;
664 val
->value
= safe_strdup (cur
->name
);
668 XtFree ((char *) pos_list
);
674 /* This function is for activating a button from a program. It's wrong because
675 we pass a NULL argument in the call_data which is not Motif compatible.
676 This is used from the XmNdefaultAction callback of the List widgets to
677 have a dble-click put down a dialog box like the button woudl do.
678 I could not find a way to do that with accelerators.
681 activate_button (Widget widget
, XtPointer closure
, XtPointer call_data
)
683 Widget button
= (Widget
)closure
;
684 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
687 /* creation functions */
691 make_dialog (char* name
, Widget parent
, Boolean pop_up_p
,
692 char* shell_title
, char* icon_name
, Boolean text_input_slot
,
693 Boolean radio_box
, Boolean list
,
694 int left_buttons
, int right_buttons
)
700 Widget icon_separator
;
705 Widget children
[16]; /* for the final XtManageChildren */
707 Arg al
[64]; /* Arg List */
708 int ac
; /* Arg Count */
714 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
715 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
716 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
717 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
719 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
720 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
721 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
722 form
= XmCreateForm (result
, shell_title
, al
, ac
);
727 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
728 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
729 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
733 n_children
= left_buttons
+ right_buttons
+ 1;
735 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
736 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
737 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
738 XmVERTICAL
: XmHORIZONTAL
); ac
++;
739 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
740 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
741 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
742 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
743 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
744 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
745 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
746 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
747 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
748 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
749 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
750 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
751 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
752 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
753 row
= XmCreateRowColumn (form
, "row", al
, ac
);
756 for (i
= 0; i
< left_buttons
; i
++)
758 char button_name
[16];
759 sprintf (button_name
, "button%d", i
+ 1);
763 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
764 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
766 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
767 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
768 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
772 button
= children
[n_children
];
774 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
775 XtSetValues (row
, al
, ac
);
781 /* invisible seperator button */
783 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
784 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
787 for (i
= 0; i
< right_buttons
; i
++)
789 char button_name
[16];
790 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
792 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
793 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
794 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
795 if (! button
) button
= children
[n_children
];
799 XtManageChildren (children
, n_children
);
802 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
803 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
804 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
805 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
806 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
807 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
808 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
809 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
810 separator
= XmCreateSeparator (form
, "", al
, ac
);
813 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
814 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
815 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
816 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
817 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
818 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
819 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
820 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
823 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
824 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
825 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
826 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
827 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
828 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
829 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
830 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
831 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
832 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
837 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
838 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
839 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
840 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
841 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
842 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
843 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
844 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
845 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
846 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
847 value
= XmCreateTextField (form
, "value", al
, ac
);
853 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
854 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
855 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
856 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
857 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
858 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
859 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
860 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
861 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
862 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
863 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
864 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
865 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
866 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
869 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
870 children
[i
++] = radio_butt
;
871 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
872 children
[i
++] = radio_butt
;
873 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
874 children
[i
++] = radio_butt
;
875 XtManageChildren (children
, i
);
880 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
881 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
882 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
883 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
884 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
885 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
886 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
887 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
888 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
889 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
890 value
= XmCreateScrolledList (form
, "list", al
, ac
);
892 /* this is the easiest way I found to have the dble click in the
893 list activate the default button */
894 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
898 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
899 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
900 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
901 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
902 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
903 XtSetArg(al
[ac
], XmNbottomWidget
,
904 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
905 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
906 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
907 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
908 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
909 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
910 message
= XmCreateLabel (form
, "message", al
, ac
);
913 XtManageChild (value
);
916 children
[i
] = row
; i
++;
917 children
[i
] = separator
; i
++;
918 if (text_input_slot
|| radio_box
)
920 children
[i
] = value
; i
++;
922 children
[i
] = message
; i
++;
923 children
[i
] = icon
; i
++;
924 children
[i
] = icon_separator
; i
++;
925 XtManageChildren (children
, i
);
927 if (text_input_slot
|| list
)
929 XtInstallAccelerators (value
, button
);
930 XtSetKeyboardFocus (result
, value
);
934 XtInstallAccelerators (form
, button
);
935 XtSetKeyboardFocus (result
, button
);
941 static destroyed_instance
*
942 find_matching_instance (widget_instance
* instance
)
944 destroyed_instance
* cur
;
945 destroyed_instance
* prev
;
946 char* type
= instance
->info
->type
;
947 char* name
= instance
->info
->name
;
949 for (prev
= NULL
, cur
= all_destroyed_instances
;
951 prev
= cur
, cur
= cur
->next
)
953 if (!strcmp (cur
->name
, name
)
954 && !strcmp (cur
->type
, type
)
955 && cur
->parent
== instance
->parent
956 && cur
->pop_up_p
== instance
->pop_up_p
)
959 prev
->next
= cur
->next
;
961 all_destroyed_instances
= cur
->next
;
964 /* do some cleanup */
965 else if (!cur
->widget
)
968 prev
->next
= cur
->next
;
970 all_destroyed_instances
= cur
->next
;
971 free_destroyed_instance (cur
);
972 cur
= prev
? prev
: all_destroyed_instances
;
979 mark_dead_instance_destroyed (Widget widget
, XtPointer closure
,
982 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
983 instance
->widget
= NULL
;
987 recenter_widget (Widget widget
)
989 Widget parent
= XtParent (widget
);
990 Screen
* screen
= XtScreen (widget
);
991 Dimension screen_width
= WidthOfScreen (screen
);
992 Dimension screen_height
= HeightOfScreen (screen
);
993 Dimension parent_width
= 0;
994 Dimension parent_height
= 0;
995 Dimension child_width
= 0;
996 Dimension child_height
= 0;
1000 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, 0);
1001 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1004 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1005 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1007 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1009 if (x
+ child_width
> screen_width
)
1010 x
= screen_width
- child_width
;
1014 if (y
+ child_height
> screen_height
)
1015 y
= screen_height
- child_height
;
1019 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, 0);
1023 recycle_instance (destroyed_instance
* instance
)
1025 Widget widget
= instance
->widget
;
1027 /* widget is NULL if the parent was destroyed. */
1033 /* Remove the destroy callback as the instance is not in the list
1035 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1036 mark_dead_instance_destroyed
,
1037 (XtPointer
)instance
);
1039 /* Give the focus to the initial item */
1040 focus
= XtNameToWidget (widget
, "*value");
1042 focus
= XtNameToWidget (widget
, "*button1");
1044 XtSetKeyboardFocus (widget
, focus
);
1046 /* shrink the separator label back to their original size */
1047 separator
= XtNameToWidget (widget
, "*separator_button");
1049 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, 0);
1051 /* Center the dialog in its parent */
1052 recenter_widget (widget
);
1054 free_destroyed_instance (instance
);
1059 xm_create_dialog (widget_instance
* instance
)
1061 char* name
= instance
->info
->type
;
1062 Widget parent
= instance
->parent
;
1064 Boolean pop_up_p
= instance
->pop_up_p
;
1065 char* shell_name
= 0;
1067 Boolean text_input_slot
= False
;
1068 Boolean radio_box
= False
;
1069 Boolean list
= False
;
1071 int left_buttons
= 0;
1072 int right_buttons
= 1;
1073 destroyed_instance
* dead_one
;
1075 /* try to find a widget to recycle */
1076 dead_one
= find_matching_instance (instance
);
1079 Widget recycled_widget
= recycle_instance (dead_one
);
1080 if (recycled_widget
)
1081 return recycled_widget
;
1086 icon_name
= "dbox-error";
1087 shell_name
= "Error";
1091 icon_name
= "dbox-info";
1092 shell_name
= "Information";
1097 icon_name
= "dbox-question";
1098 shell_name
= "Prompt";
1102 text_input_slot
= True
;
1103 icon_name
= "dbox-question";
1104 shell_name
= "Prompt";
1108 icon_name
= "dbox-question";
1109 shell_name
= "Question";
1113 total_buttons
= name
[1] - '0';
1115 if (name
[3] == 'T' || name
[3] == 't')
1117 text_input_slot
= False
;
1121 right_buttons
= name
[4] - '0';
1123 left_buttons
= total_buttons
- right_buttons
;
1125 widget
= make_dialog (name
, parent
, pop_up_p
,
1126 shell_name
, icon_name
, text_input_slot
, radio_box
,
1127 list
, left_buttons
, right_buttons
);
1129 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1130 (XtPointer
) instance
);
1135 make_menubar (widget_instance
* instance
)
1137 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, NULL
, 0);
1141 remove_grabs (Widget shell
, XtPointer closure
, XtPointer call_data
)
1143 XmRowColumnWidget menu
= (XmRowColumnWidget
) closure
;
1144 XmRemoveFromPostFromList (menu
, XtParent (XtParent ((Widget
) menu
)));
1148 make_popup_menu (widget_instance
* instance
)
1150 Widget parent
= instance
->parent
;
1151 Window parent_window
= parent
->core
.window
;
1154 /* sets the parent window to 0 to fool Motif into not generating a grab */
1155 parent
->core
.window
= 0;
1156 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1157 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1159 parent
->core
.window
= parent_window
;
1163 make_main (widget_instance
* instance
)
1165 Widget parent
= instance
->parent
;
1171 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1172 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1173 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1177 \f/* Table of functions to create widgets */
1181 /* interface with the XDesigner generated functions */
1182 typedef Widget (*widget_maker
) (Widget
);
1183 extern Widget
create_project_p_sheet (Widget parent
);
1184 extern Widget
create_debugger_p_sheet (Widget parent
);
1185 extern Widget
create_breaklist_p_sheet (Widget parent
);
1186 extern Widget
create_le_browser_p_sheet (Widget parent
);
1187 extern Widget
create_class_browser_p_sheet (Widget parent
);
1188 extern Widget
create_call_browser_p_sheet (Widget parent
);
1189 extern Widget
create_build_dialog (Widget parent
);
1190 extern Widget
create_editmode_dialog (Widget parent
);
1191 extern Widget
create_search_dialog (Widget parent
);
1192 extern Widget
create_project_display_dialog (Widget parent
);
1195 make_one (widget_instance
* instance
, widget_maker fn
)
1201 if (instance
->pop_up_p
)
1203 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1204 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1205 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1206 (XtPointer
) instance
);
1211 result
= (*fn
) (instance
->parent
);
1212 XtRealizeWidget (result
);
1218 make_project_p_sheet (widget_instance
* instance
)
1220 return make_one (instance
, create_project_p_sheet
);
1224 make_debugger_p_sheet (widget_instance
* instance
)
1226 return make_one (instance
, create_debugger_p_sheet
);
1230 make_breaklist_p_sheet (widget_instance
* instance
)
1232 return make_one (instance
, create_breaklist_p_sheet
);
1236 make_le_browser_p_sheet (widget_instance
* instance
)
1238 return make_one (instance
, create_le_browser_p_sheet
);
1242 make_class_browser_p_sheet (widget_instance
* instance
)
1244 return make_one (instance
, create_class_browser_p_sheet
);
1248 make_call_browser_p_sheet (widget_instance
* instance
)
1250 return make_one (instance
, create_call_browser_p_sheet
);
1254 make_build_dialog (widget_instance
* instance
)
1256 return make_one (instance
, create_build_dialog
);
1260 make_editmode_dialog (widget_instance
* instance
)
1262 return make_one (instance
, create_editmode_dialog
);
1266 make_search_dialog (widget_instance
* instance
)
1268 return make_one (instance
, create_search_dialog
);
1272 make_project_display_dialog (widget_instance
* instance
)
1274 return make_one (instance
, create_project_display_dialog
);
1277 #endif /* ENERGIZE */
1279 widget_creation_entry
1280 xm_creation_table
[] =
1282 {"menubar", make_menubar
},
1283 {"popup", make_popup_menu
},
1284 {"main", make_main
},
1286 {"project_p_sheet", make_project_p_sheet
},
1287 {"debugger_p_sheet", make_debugger_p_sheet
},
1288 {"breaklist_psheet", make_breaklist_p_sheet
},
1289 {"leb_psheet", make_le_browser_p_sheet
},
1290 {"class_browser_psheet", make_class_browser_p_sheet
},
1291 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1292 {"build", make_build_dialog
},
1293 {"editmode", make_editmode_dialog
},
1294 {"search", make_search_dialog
},
1295 {"project_display", make_project_display_dialog
},
1296 #endif /* ENERGIZE */
1300 \f/* Destruction of instances */
1302 xm_destroy_instance (widget_instance
* instance
)
1304 Widget widget
= instance
->widget
;
1305 /* recycle the dialog boxes */
1306 /* Disable the recycling until we can find a way to have the dialog box
1307 get reasonable layout after we modify its contents. */
1309 && XtClass (widget
) == xmDialogShellWidgetClass
)
1311 destroyed_instance
* dead_instance
=
1312 make_destroyed_instance (instance
->info
->name
,
1313 instance
->info
->type
,
1316 instance
->pop_up_p
);
1317 dead_instance
->next
= all_destroyed_instances
;
1318 all_destroyed_instances
= dead_instance
;
1319 XtUnmanageChild (first_child (instance
->widget
));
1320 XFlush (XtDisplay (instance
->widget
));
1321 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1322 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1326 /* This might not be necessary now that the nosel is attached to
1327 popdown instead of destroy, but it can't hurt. */
1328 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1329 xm_nosel_callback
, (XtPointer
)instance
);
1330 XtDestroyWidget (instance
->widget
);
1334 \f/* popup utility */
1336 xm_popup_menu (Widget widget
)
1338 XButtonPressedEvent dummy
;
1341 dummy
.type
= ButtonPress
;
1343 dummy
.send_event
= 0;
1344 dummy
.display
= XtDisplay (widget
);
1345 dummy
.window
= XtWindow (XtParent (widget
));
1348 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1349 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1350 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1351 event
= (XEvent
*) &dummy
;
1353 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1355 /* This is so totally ridiculous: there's NO WAY to tell Motif
1356 that *any* button can select a menu item. Only one button
1357 can have that honor.
1360 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1361 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1362 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1363 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1364 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1365 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, 0);
1366 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1368 XtManageChild (widget
);
1372 set_min_dialog_size (Widget w
)
1376 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, 0);
1377 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, 0);
1381 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1383 Widget widget
= instance
->widget
;
1385 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1387 Widget widget_to_manage
= first_child (widget
);
1390 XtManageChild (widget_to_manage
);
1391 set_min_dialog_size (widget
);
1392 XtSetKeyboardFocus (instance
->parent
, widget
);
1395 XtUnmanageChild (widget_to_manage
);
1400 XtManageChild (widget
);
1402 XtUnmanageChild (widget
);
1407 /* motif callback */
1409 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
1412 do_call (Widget widget
, XtPointer closure
, enum do_call_type type
)
1416 XtPointer user_data
;
1417 widget_instance
* instance
= (widget_instance
*)closure
;
1418 Widget instance_widget
;
1423 if (widget
->core
.being_destroyed
)
1426 instance_widget
= instance
->widget
;
1427 if (!instance_widget
)
1430 id
= instance
->info
->id
;
1433 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1434 XtGetValues (widget
, al
, ac
);
1438 if (instance
->info
->pre_activate_cb
)
1439 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1442 if (instance
->info
->selection_cb
)
1443 instance
->info
->selection_cb (widget
, id
, user_data
);
1446 if (instance
->info
->selection_cb
)
1447 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1450 if (instance
->info
->post_activate_cb
)
1451 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1458 /* Like lw_internal_update_other_instances except that it does not do
1459 anything if its shell parent is not managed. This is to protect
1460 lw_internal_update_other_instances to dereference freed memory
1461 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1464 xm_internal_update_other_instances (Widget widget
, XtPointer closure
,
1465 XtPointer call_data
)
1468 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1469 if (XtIsShell (parent
))
1471 else if (!XtIsManaged (parent
))
1473 lw_internal_update_other_instances (widget
, closure
, call_data
);
1477 xm_generic_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1479 lw_internal_update_other_instances (widget
, closure
, call_data
);
1480 do_call (widget
, closure
, selection
);
1484 xm_nosel_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1486 /* This callback is only called when a dialog box is dismissed with the wm's
1487 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1488 in that case, not just unmapped, so that it releases its keyboard grabs.
1489 But there are problems with running our callbacks while the widget is in
1490 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1491 instead of XmDESTROY and then destroy it ourself after having run the
1494 do_call (widget
, closure
, no_selection
);
1495 XtDestroyWidget (widget
);
1499 xm_pull_down_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1501 do_call (widget
, closure
, pre_activate
);
1505 xm_pop_down_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1507 do_call (widget
, closure
, post_activate
);
1511 /* set the keyboard focus */
1513 xm_set_keyboard_focus (Widget parent
, Widget w
)
1515 XmProcessTraversal (w
, 0);
1516 XtSetKeyboardFocus (parent
, w
);