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>
40 #include <Xm/MenuShell.h>
41 #include <Xm/MessageB.h>
43 #include <Xm/PushBG.h>
44 #include <Xm/ArrowB.h>
45 #include <Xm/SelectioB.h>
48 #include <Xm/ToggleB.h>
49 #include <Xm/ToggleBG.h>
50 #include <Xm/RowColumn.h>
51 #include <Xm/ScrolledW.h>
52 #include <Xm/Separator.h>
53 #include <Xm/DialogS.h>
56 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
57 static void xm_internal_update_other_instances (Widget
, XtPointer
,
59 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
60 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
61 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
64 xm_update_menu (widget_instance
* instance
, Widget widget
, widget_value
* val
,
67 \f/* Structures to keep destroyed instances */
68 typedef struct _destroyed_instance
75 struct _destroyed_instance
* next
;
78 static destroyed_instance
*
79 all_destroyed_instances
= NULL
;
81 static destroyed_instance
*
82 make_destroyed_instance (char* name
, char* type
, Widget widget
, Widget parent
,
85 destroyed_instance
* instance
=
86 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
87 instance
->name
= strdup (name
);
88 instance
->type
= strdup (type
);
89 instance
->widget
= widget
;
90 instance
->parent
= parent
;
91 instance
->pop_up_p
= pop_up_p
;
92 instance
->next
= NULL
;
97 free_destroyed_instance (destroyed_instance
* instance
)
99 free (instance
->name
);
100 free (instance
->type
);
104 \f/* motif utility functions */
106 first_child (Widget widget
)
108 return ((CompositeWidget
)widget
)->composite
.children
[0];
112 lw_motif_widget_p (Widget widget
)
115 XtClass (widget
) == xmDialogShellWidgetClass
116 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
120 resource_motif_string (Widget widget
, char* name
)
125 resource
.resource_name
= name
;
126 resource
.resource_class
= XmCXmString
;
127 resource
.resource_type
= XmRXmString
;
128 resource
.resource_size
= sizeof (XmString
);
129 resource
.resource_offset
= 0;
130 resource
.default_type
= XtRImmediate
;
131 resource
.default_addr
= 0;
133 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
134 "DialogString", &resource
, 1, NULL
, 0);
139 destroy_all_children (Widget widget
)
145 children
= XtCompositeChildren (widget
, &number
);
148 /* Unmanage all children and destroy them. They will only be
149 * really destroyed when we get out of DispatchEvent. */
150 for (i
= 0; i
< number
; i
++)
152 Widget child
= children
[i
];
153 if (!child
->core
.being_destroyed
)
155 XtUnmanageChild (child
);
156 XtDestroyWidget (child
);
159 XtFree ((char *) children
);
163 \f/* update the label of anything subclass of a label */
165 xm_update_label (widget_instance
* instance
, Widget widget
, widget_value
* val
)
167 XmString res_string
= 0;
168 XmString built_string
= 0;
169 XmString key_string
= 0;
177 res_string
= resource_motif_string (widget
, val
->value
);
181 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
186 XmStringCreateLtoR (val
->value
, XmSTRING_DEFAULT_CHARSET
);
187 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
189 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
194 key_string
= XmStringCreateLtoR (val
->key
, XmSTRING_DEFAULT_CHARSET
);
195 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
199 XtSetValues (widget
, al
, ac
);
202 XmStringFree (built_string
);
205 XmStringFree (key_string
);
208 \f/* update of list */
210 xm_update_list (widget_instance
* instance
, Widget widget
, widget_value
* val
)
214 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
215 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
217 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
220 XmString xmstr
= XmStringCreate (cur
->value
, XmSTRING_DEFAULT_CHARSET
);
222 XmListAddItem (widget
, xmstr
, 0);
224 XmListSelectPos (widget
, i
, False
);
225 XmStringFree (xmstr
);
229 \f/* update of buttons */
231 xm_update_pushbutton (widget_instance
* instance
, Widget widget
,
234 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, 0);
235 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
236 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
240 xm_update_cascadebutton (widget_instance
* instance
, Widget widget
,
243 /* Should also rebuild the menu by calling ...update_menu... */
244 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
245 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
249 \f/* update toggle and radiobox */
251 xm_update_toggle (widget_instance
* instance
, Widget widget
, widget_value
* val
)
253 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
254 XtAddCallback (widget
, XmNvalueChangedCallback
,
255 xm_internal_update_other_instances
, instance
);
256 XtVaSetValues (widget
, XmNset
, val
->selected
,
257 XmNalignment
, XmALIGNMENT_BEGINNING
, 0);
261 xm_update_radiobox (widget_instance
* instance
, Widget widget
,
267 /* update the callback */
268 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
269 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
271 /* first update all the toggles */
272 /* Energize kernel interface is currently bad. It sets the selected widget
273 with the selected flag but returns it by its name. So we currently
274 have to support both setting the selection with the selected slot
275 of val contents and setting it with the "value" slot of val. The latter
276 has a higher priority. This to be removed when the kernel is fixed. */
277 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
279 toggle
= XtNameToWidget (widget
, cur
->value
);
282 XtVaSetValues (toggle
, XmNsensitive
, cur
->enabled
, 0);
283 if (!val
->value
&& cur
->selected
)
284 XtVaSetValues (toggle
, XmNset
, cur
->selected
, 0);
285 if (val
->value
&& strcmp (val
->value
, cur
->value
))
286 XtVaSetValues (toggle
, XmNset
, False
, 0);
290 /* The selected was specified by the value slot */
293 toggle
= XtNameToWidget (widget
, val
->value
);
295 XtVaSetValues (toggle
, XmNset
, True
, 0);
299 \f/* update a popup menu, pulldown menu or a menubar */
301 all_dashes_p (char* s
)
311 make_menu_in_widget (widget_instance
* instance
, Widget widget
,
314 Widget
* children
= 0;
324 /* Allocate the children array */
325 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
);
326 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
328 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
330 XtSetArg (al
[0], XmNisHomogeneous
, &menubar_p
);
331 XtGetValues (widget
, al
, 1);
333 /* add the unmap callback for popups and pulldowns */
334 /*** this sounds bogus ***/
336 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
337 xm_pop_down_callback
, (XtPointer
)instance
);
339 for (child_index
= 0, cur
= val
; cur
; child_index
++, cur
= cur
->next
)
342 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
343 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
344 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
346 if (all_dashes_p (cur
->name
))
348 button
= XmCreateSeparator (widget
, cur
->name
, NULL
, 0);
350 else if (!cur
->contents
)
353 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
354 else if (!cur
->call_data
)
355 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
357 button
= XmCreatePushButtonGadget (widget
, cur
->name
, al
, ac
);
359 xm_update_label (instance
, button
, cur
);
361 /* don't add a callback to a simple label */
363 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
364 (XtPointer
)instance
);
368 menu
= XmCreatePulldownMenu (widget
, "pulldown", NULL
, 0);
369 make_menu_in_widget (instance
, menu
, cur
->contents
);
370 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
371 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
373 xm_update_label (instance
, button
, cur
);
375 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
376 (XtPointer
)instance
);
379 children
[child_index
] = button
;
382 XtManageChildren (children
, num_children
);
384 /* Last entry is the help button. Has to be done after managing
385 * the buttons otherwise the menubar is only 4 pixels high... */
389 XtSetArg (al
[ac
], XmNmenuHelpWidget
, button
); ac
++;
390 XtSetValues (widget
, al
, ac
);
393 XtFree ((char *) children
);
397 update_one_menu_entry (widget_instance
* instance
, Widget widget
,
398 widget_value
* val
, Boolean deep_p
)
403 widget_value
* contents
;
405 if (val
->change
== NO_CHANGE
)
408 /* update the sensitivity and userdata */
409 /* Common to all widget types */
410 XtVaSetValues (widget
,
411 XmNsensitive
, val
->enabled
,
412 XmNuserData
, val
->call_data
,
415 /* update the menu button as a label. */
416 if (val
->change
>= VISIBLE_CHANGE
)
417 xm_update_label (instance
, widget
, val
);
419 /* update the pulldown/pullaside as needed */
422 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
423 XtGetValues (widget
, al
, ac
);
425 contents
= val
->contents
;
431 menu
= XmCreatePulldownMenu (widget
, "pulldown", NULL
, 0);
432 make_menu_in_widget (instance
, menu
, contents
);
434 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
435 XtSetValues (widget
, al
, ac
);
441 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
442 XtSetValues (widget
, al
, ac
);
443 XtDestroyWidget (menu
);
445 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
446 xm_update_menu (instance
, menu
, val
, 1);
450 xm_update_menu (widget_instance
* instance
, Widget widget
, widget_value
* val
,
453 /* Widget is a RowColumn widget whose contents have to be updated
454 * to reflect the list of items in val->contents */
455 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
457 destroy_all_children (widget
);
458 make_menu_in_widget (instance
, widget
, val
->contents
);
462 /* Update all the buttons of the RowColumn in order. */
464 unsigned int num_children
;
468 children
= XtCompositeChildren (widget
, &num_children
);
471 for (i
= 0, cur
= val
->contents
; i
< num_children
; i
++)
475 if (children
[i
]->core
.being_destroyed
476 || strcmp (XtName (children
[i
]), cur
->name
))
478 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
481 XtFree ((char *) children
);
489 /* update text widgets */
492 xm_update_text (widget_instance
* instance
, Widget widget
, widget_value
* val
)
494 XmTextSetString (widget
, val
->value
? val
->value
: "");
495 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
496 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
497 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
498 XtAddCallback (widget
, XmNvalueChangedCallback
,
499 xm_internal_update_other_instances
, instance
);
503 xm_update_text_field (widget_instance
* instance
, Widget widget
,
506 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
507 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
508 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
509 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
510 XtAddCallback (widget
, XmNvalueChangedCallback
,
511 xm_internal_update_other_instances
, instance
);
515 /* update a motif widget */
518 xm_update_one_widget (widget_instance
* instance
, Widget widget
,
519 widget_value
* val
, Boolean deep_p
)
523 /* Mark as not edited */
526 /* Common to all widget types */
527 XtVaSetValues (widget
,
528 XmNsensitive
, val
->enabled
,
529 XmNuserData
, val
->call_data
,
532 /* Common to all label like widgets */
533 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
534 xm_update_label (instance
, widget
, val
);
536 class = XtClass (widget
);
537 /* Class specific things */
538 if (class == xmPushButtonWidgetClass
||
539 class == xmArrowButtonWidgetClass
)
541 xm_update_pushbutton (instance
, widget
, val
);
543 else if (class == xmCascadeButtonWidgetClass
)
545 xm_update_cascadebutton (instance
, widget
, val
);
547 else if (class == xmToggleButtonWidgetClass
548 || class == xmToggleButtonGadgetClass
)
550 xm_update_toggle (instance
, widget
, val
);
552 else if (class == xmRowColumnWidgetClass
)
554 Boolean radiobox
= 0;
558 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
559 XtGetValues (widget
, al
, ac
);
562 xm_update_radiobox (instance
, widget
, val
);
564 xm_update_menu (instance
, widget
, val
, deep_p
);
566 else if (class == xmTextWidgetClass
)
568 xm_update_text (instance
, widget
, val
);
570 else if (class == xmTextFieldWidgetClass
)
572 xm_update_text_field (instance
, widget
, val
);
574 else if (class == xmListWidgetClass
)
576 xm_update_list (instance
, widget
, val
);
580 \f/* getting the value back */
582 xm_update_one_value (widget_instance
* instance
, Widget widget
,
585 WidgetClass
class = XtClass (widget
);
586 widget_value
*old_wv
;
588 /* copy the call_data slot into the "return" widget_value */
589 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
590 if (!strcmp (val
->name
, old_wv
->name
))
592 val
->call_data
= old_wv
->call_data
;
596 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
598 XtVaGetValues (widget
, XmNset
, &val
->selected
, 0);
601 else if (class == xmTextWidgetClass
)
605 val
->value
= XmTextGetString (widget
);
608 else if (class == xmTextFieldWidgetClass
)
612 val
->value
= XmTextFieldGetString (widget
);
615 else if (class == xmRowColumnWidgetClass
)
617 Boolean radiobox
= 0;
621 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
622 XtGetValues (widget
, al
, ac
);
626 CompositeWidget radio
= (CompositeWidget
)widget
;
628 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
631 Widget toggle
= radio
->composite
.children
[i
];
633 XtVaGetValues (toggle
, XmNset
, &set
, 0);
638 val
->value
= strdup (XtName (toggle
));
644 else if (class == xmListWidgetClass
)
648 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
652 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
656 cur
->selected
= False
;
658 for (j
= 0; j
< pos_cnt
; j
++)
659 if (pos_list
[j
] == i
)
661 cur
->selected
= True
;
662 val
->value
= strdup (cur
->name
);
666 XtFree ((char *) pos_list
);
672 /* This function is for activating a button from a program. It's wrong because
673 we pass a NULL argument in the call_data which is not Motif compatible.
674 This is used from the XmNdefaultAction callback of the List widgets to
675 have a dble-click put down a dialog box like the button woudl do.
676 I could not find a way to do that with accelerators.
679 activate_button (Widget widget
, XtPointer closure
, XtPointer call_data
)
681 Widget button
= (Widget
)closure
;
682 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
685 /* creation functions */
689 make_dialog (char* name
, Widget parent
, Boolean pop_up_p
,
690 char* shell_title
, char* icon_name
, Boolean text_input_slot
,
691 Boolean radio_box
, Boolean list
,
692 int left_buttons
, int right_buttons
)
698 Widget icon_separator
;
703 Widget children
[16]; /* for the final XtManageChildren */
705 Arg al
[64]; /* Arg List */
706 int ac
; /* Arg Count */
712 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
713 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
714 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
715 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
717 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
718 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
719 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
720 form
= XmCreateForm (result
, shell_title
, al
, ac
);
725 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
726 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
727 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
732 XtSetArg(al
[ac
], XmNpacking
, XmPACK_COLUMN
); ac
++;
733 XtSetArg(al
[ac
], XmNorientation
, XmVERTICAL
); ac
++;
734 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
735 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
736 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
737 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
738 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
739 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
740 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
741 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
742 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
743 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
744 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
745 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
746 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
747 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
748 row
= XmCreateRowColumn (form
, "row", al
, ac
);
751 for (i
= 0; i
< left_buttons
; i
++)
753 char button_name
[16];
754 sprintf (button_name
, "button%d", i
+ 1);
758 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
759 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
761 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
762 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
766 button
= children
[n_children
];
768 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
769 XtSetValues (row
, al
, ac
);
775 /* invisible seperator button */
777 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
778 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
781 for (i
= 0; i
< right_buttons
; i
++)
783 char button_name
[16];
784 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
786 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
787 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
788 if (! button
) button
= children
[n_children
];
792 XtManageChildren (children
, n_children
);
795 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
796 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
797 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
798 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
799 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
800 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
801 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
802 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
803 separator
= XmCreateSeparator (form
, "", al
, ac
);
806 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
807 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
808 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
809 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
810 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
811 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
812 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
813 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
816 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
817 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
818 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
819 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
820 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
821 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
822 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
823 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
824 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
825 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
830 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
831 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
832 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
833 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
834 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
835 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
836 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
837 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
838 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
839 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
840 value
= XmCreateTextField (form
, "value", al
, ac
);
846 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
847 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
848 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
849 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
850 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
851 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
852 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
853 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
854 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
855 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
856 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
857 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
858 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
859 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
862 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
863 children
[i
++] = radio_butt
;
864 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
865 children
[i
++] = radio_butt
;
866 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
867 children
[i
++] = radio_butt
;
868 XtManageChildren (children
, i
);
873 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
874 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
875 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
876 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
877 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
878 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
879 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
880 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
881 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
882 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
883 value
= XmCreateScrolledList (form
, "list", al
, ac
);
885 /* this is the easiest way I found to have the dble click in the
886 list activate the default button */
887 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
891 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
892 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
893 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
894 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
895 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
896 XtSetArg(al
[ac
], XmNbottomWidget
,
897 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
898 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
899 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
900 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
901 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
902 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
903 message
= XmCreateLabel (form
, "message", al
, ac
);
906 XtManageChild (value
);
909 children
[i
] = row
; i
++;
910 children
[i
] = separator
; i
++;
911 if (text_input_slot
|| radio_box
)
913 children
[i
] = value
; i
++;
915 children
[i
] = message
; i
++;
916 children
[i
] = icon
; i
++;
917 children
[i
] = icon_separator
; i
++;
918 XtManageChildren (children
, i
);
920 if (text_input_slot
|| list
)
922 XtInstallAccelerators (value
, button
);
923 XtSetKeyboardFocus (result
, value
);
927 XtInstallAccelerators (form
, button
);
928 XtSetKeyboardFocus (result
, button
);
934 static destroyed_instance
*
935 find_matching_instance (widget_instance
* instance
)
937 destroyed_instance
* cur
;
938 destroyed_instance
* prev
;
939 char* type
= instance
->info
->type
;
940 char* name
= instance
->info
->name
;
942 for (prev
= NULL
, cur
= all_destroyed_instances
;
944 prev
= cur
, cur
= cur
->next
)
946 if (!strcmp (cur
->name
, name
)
947 && !strcmp (cur
->type
, type
)
948 && cur
->parent
== instance
->parent
949 && cur
->pop_up_p
== instance
->pop_up_p
)
952 prev
->next
= cur
->next
;
954 all_destroyed_instances
= cur
->next
;
957 /* do some cleanup */
958 else if (!cur
->widget
)
961 prev
->next
= cur
->next
;
963 all_destroyed_instances
= cur
->next
;
964 free_destroyed_instance (cur
);
965 cur
= prev
? prev
: all_destroyed_instances
;
972 mark_dead_instance_destroyed (Widget widget
, XtPointer closure
,
975 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
976 instance
->widget
= NULL
;
980 recenter_widget (Widget widget
)
982 Widget parent
= XtParent (widget
);
983 Screen
* screen
= XtScreen (widget
);
984 Dimension screen_width
= WidthOfScreen (screen
);
985 Dimension screen_height
= HeightOfScreen (screen
);
986 Dimension parent_width
= 0;
987 Dimension parent_height
= 0;
988 Dimension child_width
= 0;
989 Dimension child_height
= 0;
993 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, 0);
994 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
997 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
998 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1000 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1002 if (x
+ child_width
> screen_width
)
1003 x
= screen_width
- child_width
;
1007 if (y
+ child_height
> screen_height
)
1008 y
= screen_height
- child_height
;
1012 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, 0);
1016 recycle_instance (destroyed_instance
* instance
)
1018 Widget widget
= instance
->widget
;
1020 /* widget is NULL if the parent was destroyed. */
1026 /* Remove the destroy callback as the instance is not in the list
1028 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1029 mark_dead_instance_destroyed
,
1030 (XtPointer
)instance
);
1032 /* Give the focus to the initial item */
1033 focus
= XtNameToWidget (widget
, "*value");
1035 focus
= XtNameToWidget (widget
, "*button1");
1037 XtSetKeyboardFocus (widget
, focus
);
1039 /* shrink the separator label back to their original size */
1040 separator
= XtNameToWidget (widget
, "*separator_button");
1042 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, 0);
1044 /* Center the dialog in its parent */
1045 recenter_widget (widget
);
1047 free_destroyed_instance (instance
);
1052 xm_create_dialog (widget_instance
* instance
)
1054 char* name
= instance
->info
->type
;
1055 Widget parent
= instance
->parent
;
1057 Boolean pop_up_p
= instance
->pop_up_p
;
1058 char* shell_name
= 0;
1060 Boolean text_input_slot
= False
;
1061 Boolean radio_box
= False
;
1062 Boolean list
= False
;
1064 int left_buttons
= 0;
1065 int right_buttons
= 1;
1066 destroyed_instance
* dead_one
;
1068 /* try to find a widget to recycle */
1069 dead_one
= find_matching_instance (instance
);
1072 Widget recycled_widget
= recycle_instance (dead_one
);
1073 if (recycled_widget
)
1074 return recycled_widget
;
1079 icon_name
= "dbox-error";
1080 shell_name
= "Error";
1084 icon_name
= "dbox-info";
1085 shell_name
= "Information";
1090 icon_name
= "dbox-question";
1091 shell_name
= "Prompt";
1095 text_input_slot
= True
;
1096 icon_name
= "dbox-question";
1097 shell_name
= "Prompt";
1101 icon_name
= "dbox-question";
1102 shell_name
= "Question";
1106 total_buttons
= name
[1] - '0';
1108 if (name
[3] == 'T' || name
[3] == 't')
1110 text_input_slot
= False
;
1114 right_buttons
= name
[4] - '0';
1116 left_buttons
= total_buttons
- right_buttons
;
1118 widget
= make_dialog (name
, parent
, pop_up_p
,
1119 shell_name
, icon_name
, text_input_slot
, radio_box
,
1120 list
, left_buttons
, right_buttons
);
1122 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1123 (XtPointer
) instance
);
1128 make_menubar (widget_instance
* instance
)
1130 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, NULL
, 0);
1134 remove_grabs (Widget shell
, XtPointer closure
, XtPointer call_data
)
1136 XmRowColumnWidget menu
= (XmRowColumnWidget
) closure
;
1137 XmRemoveFromPostFromList (menu
, XtParent (XtParent ((Widget
) menu
)));
1141 make_popup_menu (widget_instance
* instance
)
1143 Widget parent
= instance
->parent
;
1144 Window parent_window
= parent
->core
.window
;
1147 /* sets the parent window to 0 to fool Motif into not generating a grab */
1148 parent
->core
.window
= 0;
1149 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1150 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1152 parent
->core
.window
= parent_window
;
1156 \f/* Table of functions to create widgets */
1160 /* interface with the XDesigner generated functions */
1161 typedef Widget (*widget_maker
) (Widget
);
1162 extern Widget
create_project_p_sheet (Widget parent
);
1163 extern Widget
create_debugger_p_sheet (Widget parent
);
1164 extern Widget
create_breaklist_p_sheet (Widget parent
);
1165 extern Widget
create_le_browser_p_sheet (Widget parent
);
1166 extern Widget
create_class_browser_p_sheet (Widget parent
);
1167 extern Widget
create_call_browser_p_sheet (Widget parent
);
1168 extern Widget
create_build_dialog (Widget parent
);
1169 extern Widget
create_editmode_dialog (Widget parent
);
1170 extern Widget
create_search_dialog (Widget parent
);
1171 extern Widget
create_project_display_dialog (Widget parent
);
1174 make_one (widget_instance
* instance
, widget_maker fn
)
1180 if (instance
->pop_up_p
)
1182 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1183 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1184 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1185 (XtPointer
) instance
);
1190 result
= (*fn
) (instance
->parent
);
1191 XtRealizeWidget (result
);
1197 make_project_p_sheet (widget_instance
* instance
)
1199 return make_one (instance
, create_project_p_sheet
);
1203 make_debugger_p_sheet (widget_instance
* instance
)
1205 return make_one (instance
, create_debugger_p_sheet
);
1209 make_breaklist_p_sheet (widget_instance
* instance
)
1211 return make_one (instance
, create_breaklist_p_sheet
);
1215 make_le_browser_p_sheet (widget_instance
* instance
)
1217 return make_one (instance
, create_le_browser_p_sheet
);
1221 make_class_browser_p_sheet (widget_instance
* instance
)
1223 return make_one (instance
, create_class_browser_p_sheet
);
1227 make_call_browser_p_sheet (widget_instance
* instance
)
1229 return make_one (instance
, create_call_browser_p_sheet
);
1233 make_build_dialog (widget_instance
* instance
)
1235 return make_one (instance
, create_build_dialog
);
1239 make_editmode_dialog (widget_instance
* instance
)
1241 return make_one (instance
, create_editmode_dialog
);
1245 make_search_dialog (widget_instance
* instance
)
1247 return make_one (instance
, create_search_dialog
);
1251 make_project_display_dialog (widget_instance
* instance
)
1253 return make_one (instance
, create_project_display_dialog
);
1256 #endif /* ENERGIZE */
1258 widget_creation_entry
1259 xm_creation_table
[] =
1261 {"menubar", make_menubar
},
1262 {"popup", make_popup_menu
},
1264 {"project_p_sheet", make_project_p_sheet
},
1265 {"debugger_p_sheet", make_debugger_p_sheet
},
1266 {"breaklist_psheet", make_breaklist_p_sheet
},
1267 {"leb_psheet", make_le_browser_p_sheet
},
1268 {"class_browser_psheet", make_class_browser_p_sheet
},
1269 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1270 {"build", make_build_dialog
},
1271 {"editmode", make_editmode_dialog
},
1272 {"search", make_search_dialog
},
1273 {"project_display", make_project_display_dialog
},
1274 #endif /* ENERGIZE */
1278 \f/* Destruction of instances */
1280 xm_destroy_instance (widget_instance
* instance
)
1282 Widget widget
= instance
->widget
;
1283 /* recycle the dialog boxes */
1284 /* Disable the recycling until we can find a way to have the dialog box
1285 get reasonable layout after we modify its contents. */
1287 && XtClass (widget
) == xmDialogShellWidgetClass
)
1289 destroyed_instance
* dead_instance
=
1290 make_destroyed_instance (instance
->info
->name
,
1291 instance
->info
->type
,
1294 instance
->pop_up_p
);
1295 dead_instance
->next
= all_destroyed_instances
;
1296 all_destroyed_instances
= dead_instance
;
1297 XtUnmanageChild (first_child (instance
->widget
));
1298 XFlush (XtDisplay (instance
->widget
));
1299 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1300 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1304 /* This might not be necessary now that the nosel is attached to
1305 popdown instead of destroy, but it can't hurt. */
1306 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1307 xm_nosel_callback
, (XtPointer
)instance
);
1308 XtDestroyWidget (instance
->widget
);
1312 \f/* popup utility */
1314 xm_popup_menu (Widget widget
)
1316 XButtonPressedEvent dummy
;
1319 dummy
.type
= ButtonPress
;
1321 dummy
.send_event
= 0;
1322 dummy
.display
= XtDisplay (widget
);
1323 dummy
.window
= XtWindow (XtParent (widget
));
1326 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1327 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1328 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1329 event
= (XEvent
*) &dummy
;
1331 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1333 /* This is so totally ridiculous: there's NO WAY to tell Motif
1334 that *any* button can select a menu item. Only one button
1335 can have that honor.
1338 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1339 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1340 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1341 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1342 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1343 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, 0);
1344 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1346 XtManageChild (widget
);
1350 set_min_dialog_size (Widget w
)
1354 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, 0);
1355 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, 0);
1359 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1361 Widget widget
= instance
->widget
;
1363 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1365 Widget widget_to_manage
= first_child (widget
);
1368 XtManageChild (widget_to_manage
);
1369 set_min_dialog_size (widget
);
1370 XtSetKeyboardFocus (instance
->parent
, widget
);
1373 XtUnmanageChild (widget_to_manage
);
1378 XtManageChild (widget
);
1380 XtUnmanageChild (widget
);
1385 /* motif callback */
1387 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
1390 do_call (Widget widget
, XtPointer closure
, enum do_call_type type
)
1394 XtPointer user_data
;
1395 widget_instance
* instance
= (widget_instance
*)closure
;
1396 Widget instance_widget
;
1401 if (widget
->core
.being_destroyed
)
1404 instance_widget
= instance
->widget
;
1405 if (!instance_widget
)
1408 id
= instance
->info
->id
;
1411 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1412 XtGetValues (widget
, al
, ac
);
1416 if (instance
->info
->pre_activate_cb
)
1417 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1420 if (instance
->info
->selection_cb
)
1421 instance
->info
->selection_cb (widget
, id
, user_data
);
1424 if (instance
->info
->selection_cb
)
1425 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1428 if (instance
->info
->post_activate_cb
)
1429 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1436 /* Like lw_internal_update_other_instances except that it does not do
1437 anything if its shell parent is not managed. This is to protect
1438 lw_internal_update_other_instances to dereference freed memory
1439 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1442 xm_internal_update_other_instances (Widget widget
, XtPointer closure
,
1443 XtPointer call_data
)
1446 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1447 if (XtIsShell (parent
))
1449 else if (!XtIsManaged (parent
))
1451 lw_internal_update_other_instances (widget
, closure
, call_data
);
1455 xm_generic_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1457 lw_internal_update_other_instances (widget
, closure
, call_data
);
1458 do_call (widget
, closure
, selection
);
1462 xm_nosel_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1464 /* This callback is only called when a dialog box is dismissed with the wm's
1465 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1466 in that case, not just unmapped, so that it releases its keyboard grabs.
1467 But there are problems with running our callbacks while the widget is in
1468 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1469 instead of XmDESTROY and then destroy it ourself after having run the
1472 do_call (widget
, closure
, no_selection
);
1473 XtDestroyWidget (widget
);
1477 xm_pull_down_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1479 do_call (widget
, closure
, pre_activate
);
1483 xm_pop_down_callback (Widget widget
, XtPointer closure
, XtPointer call_data
)
1485 do_call (widget
, closure
, post_activate
);
1489 /* set the keyboard focus */
1491 xm_set_keyboard_focus (Widget parent
, Widget w
)
1493 XmProcessTraversal (w
, 0);
1494 XtSetKeyboardFocus (parent
, w
);