1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
5 Copyright (C) 1992 Lucid, Inc.
7 This file is part of the Lucid Widget Library.
9 The Lucid Widget Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 1, or (at your option)
14 The Lucid Widget Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
32 #include <X11/StringDefs.h>
33 #include <X11/IntrinsicP.h>
34 #include <X11/ObjectP.h>
35 #include <X11/CoreP.h>
36 #include <X11/CompositeP.h>
38 #include "../src/lisp.h"
41 #include "lwlib-utils.h"
43 #include <Xm/BulletinB.h>
44 #include <Xm/CascadeB.h>
45 #include <Xm/CascadeBG.h>
46 #include <Xm/DrawingA.h>
47 #include <Xm/FileSB.h>
51 #include <Xm/MenuShell.h>
52 #include <Xm/MessageB.h>
53 #include <Xm/PanedW.h>
55 #include <Xm/PushBG.h>
56 #include <Xm/ArrowB.h>
57 #include <Xm/SelectioB.h>
60 #include <Xm/ToggleB.h>
61 #include <Xm/ToggleBG.h>
62 #include <Xm/RowColumn.h>
63 #include <Xm/ScrolledW.h>
64 #include <Xm/Separator.h>
65 #include <Xm/DialogS.h>
68 enum do_call_type
{ pre_activate
, selection
, no_selection
, post_activate
};
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
79 struct _destroyed_instance
* next
;
82 static destroyed_instance
*make_destroyed_instance (char *, char *,
85 static void free_destroyed_instance (destroyed_instance
*);
86 Widget
first_child (Widget
);
87 Boolean
lw_motif_widget_p (Widget
);
88 static XmString
resource_motif_string (Widget
, char *);
89 static void destroy_all_children (Widget
, int);
90 static void xm_update_label (widget_instance
*, Widget
, widget_value
*);
91 static void xm_update_list (widget_instance
*, Widget
, widget_value
*);
92 static void xm_update_pushbutton (widget_instance
*, Widget
,
94 static void xm_update_cascadebutton (widget_instance
*, Widget
,
96 static void xm_update_toggle (widget_instance
*, Widget
, widget_value
*);
97 static void xm_update_radiobox (widget_instance
*, Widget
, widget_value
*);
98 static void make_menu_in_widget (widget_instance
*, Widget
,
100 static void update_one_menu_entry (widget_instance
*, Widget
,
101 widget_value
*, Boolean
);
102 static void xm_update_menu (widget_instance
*, Widget
, widget_value
*,
104 static void xm_update_text (widget_instance
*, Widget
, widget_value
*);
105 static void xm_update_text_field (widget_instance
*, Widget
,
107 void xm_update_one_value (widget_instance
*, Widget
, widget_value
*);
108 static void activate_button (Widget
, XtPointer
, XtPointer
);
109 static Widget
make_dialog (char *, Widget
, Boolean
, char *, char *,
110 Boolean
, Boolean
, Boolean
, int, int);
111 static destroyed_instance
* find_matching_instance (widget_instance
*);
112 static void mark_dead_instance_destroyed (Widget
, XtPointer
, XtPointer
);
113 static void recenter_widget (Widget
);
114 static Widget
recycle_instance (destroyed_instance
*);
115 Widget
xm_create_dialog (widget_instance
*);
116 static Widget
make_menubar (widget_instance
*);
117 static void remove_grabs (Widget
, XtPointer
, XtPointer
);
118 static Widget
make_popup_menu (widget_instance
*);
119 static Widget
make_main (widget_instance
*);
120 void xm_destroy_instance (widget_instance
*);
121 void xm_popup_menu (Widget
, XEvent
*);
122 static void set_min_dialog_size (Widget
);
123 static void do_call (Widget
, XtPointer
, enum do_call_type
);
124 static void xm_generic_callback (Widget
, XtPointer
, XtPointer
);
125 static void xm_nosel_callback (Widget
, XtPointer
, XtPointer
);
126 static void xm_pull_down_callback (Widget
, XtPointer
, XtPointer
);
127 static void xm_pop_down_callback (Widget
, XtPointer
, XtPointer
);
128 void xm_set_keyboard_focus (Widget
, Widget
);
129 void xm_set_main_areas (Widget
, Widget
, Widget
);
130 static void xm_internal_update_other_instances (Widget
, XtPointer
,
132 static void xm_arm_callback (Widget
, XtPointer
, XtPointer
);
135 void xm_update_one_widget (widget_instance
*, Widget
, widget_value
*,
137 void xm_pop_instance (widget_instance
*, Boolean
);
138 void xm_manage_resizing (Widget
, Boolean
);
144 /* Print the complete X resource name of widget WIDGET to stderr.
145 This is sometimes handy to have available. */
148 x_print_complete_resource_name (Widget widget
)
153 for (i
= 0; i
< 100 && widget
!= NULL
; ++i
)
155 names
[i
] = XtName (widget
);
156 widget
= XtParent (widget
);
159 for (--i
; i
>= 1; --i
)
160 fprintf (stderr
, "%s.", names
[i
]);
161 fprintf (stderr
, "%s\n", names
[0]);
167 static destroyed_instance
*all_destroyed_instances
= NULL
;
169 static destroyed_instance
*
170 make_destroyed_instance (char* name
,
176 destroyed_instance
* instance
=
177 (destroyed_instance
*)malloc (sizeof (destroyed_instance
));
178 instance
->name
= safe_strdup (name
);
179 instance
->type
= safe_strdup (type
);
180 instance
->widget
= widget
;
181 instance
->parent
= parent
;
182 instance
->pop_up_p
= pop_up_p
;
183 instance
->next
= NULL
;
188 free_destroyed_instance (destroyed_instance
* instance
)
190 free (instance
->name
);
191 free (instance
->type
);
195 \f/* motif utility functions */
197 first_child (Widget widget
)
199 return ((CompositeWidget
)widget
)->composite
.children
[0];
203 lw_motif_widget_p (Widget widget
)
206 XtClass (widget
) == xmDialogShellWidgetClass
207 || XmIsPrimitive (widget
) || XmIsManager (widget
) || XmIsGadget (widget
);
211 resource_motif_string (Widget widget
,
217 resource
.resource_name
= name
;
218 resource
.resource_class
= XmCXmString
;
219 resource
.resource_type
= XmRXmString
;
220 resource
.resource_size
= sizeof (XmString
);
221 resource
.resource_offset
= 0;
222 resource
.default_type
= XtRImmediate
;
223 resource
.default_addr
= 0;
225 XtGetSubresources (widget
, (XtPointer
)&result
, "dialogString",
226 "DialogString", &resource
, 1, NULL
, 0);
230 /* Destroy all of the children of WIDGET
231 starting with number FIRST_CHILD_TO_DESTROY. */
234 destroy_all_children (Widget widget
,
235 int first_child_to_destroy
)
241 children
= XtCompositeChildren (widget
, &number
);
244 XtUnmanageChildren (children
+ first_child_to_destroy
,
245 number
- first_child_to_destroy
);
247 /* Unmanage all children and destroy them. They will only be
248 really destroyed when we get out of DispatchEvent. */
249 for (i
= first_child_to_destroy
; i
< number
; i
++)
253 /* Cascade buttons have submenus,and these submenus
254 need to be freed. But they are not included in
255 XtCompositeChildren. So get it out of the cascade button
256 and free it. If this child is not a cascade button,
257 then submenu should remain unchanged. */
258 XtSetArg (al
[0], XmNsubMenuId
, &submenu
);
259 XtGetValues (children
[i
], al
, 1);
262 destroy_all_children (submenu
, 0);
263 XtDestroyWidget (submenu
);
265 XtDestroyWidget (children
[i
]);
268 XtFree ((char *) children
);
274 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
275 menu. CLIENT_DATA contains a pointer to the widget_value
276 corresponding to widget W. CALL_DATA contains a
277 XmPushButtonCallbackStruct containing the reason why the callback
281 xm_arm_callback (Widget w
, XtPointer client_data
, XtPointer call_data
)
283 XmPushButtonCallbackStruct
*cbs
= (XmPushButtonCallbackStruct
*) call_data
;
284 widget_value
*wv
= (widget_value
*) client_data
;
285 widget_instance
*instance
;
287 /* Get the id of the menu bar or popup menu this widget is in. */
290 if (XmIsRowColumn (w
))
292 unsigned char type
= 0xff;
294 XtVaGetValues (w
, XmNrowColumnType
, &type
, NULL
);
295 if (type
== XmMENU_BAR
|| type
== XmMENU_POPUP
)
304 instance
= lw_get_widget_instance (w
);
305 if (instance
&& instance
->info
->highlight_cb
)
307 call_data
= cbs
->reason
== XmCR_DISARM
? NULL
: wv
;
308 instance
->info
->highlight_cb (w
, instance
->info
->id
, call_data
);
315 /* Update the label of widget WIDGET. WIDGET must be a Label widget
316 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
321 Emacs fills VAL->name with the text to display in the menu, and
322 sets VAL->value to null. Function make_menu_in_widget creates
323 widgets with VAL->name as resource name. This works because the
324 Label widget uses its resource name for display if no
325 XmNlabelString is set.
329 VAL->name is again set to the resource name, but VAL->value is
330 not null, and contains the label string to display. */
333 xm_update_label (widget_instance
* instance
,
337 XmString res_string
= 0;
338 XmString built_string
= 0;
339 XmString key_string
= 0;
347 /* A label string is specified, i.e. we are in a dialog. First
348 see if it is overridden by something from the resource file. */
349 res_string
= resource_motif_string (widget
, val
->value
);
353 XtSetArg (al
[ac
], XmNlabelString
, res_string
); ac
++;
358 XmStringCreateLocalized (val
->value
);
359 XtSetArg (al
[ac
], XmNlabelString
, built_string
); ac
++;
362 XtSetArg (al
[ac
], XmNlabelType
, XmSTRING
); ac
++;
367 key_string
= XmStringCreateLocalized (val
->key
);
368 XtSetArg (al
[ac
], XmNacceleratorText
, key_string
); ac
++;
372 XtSetValues (widget
, al
, ac
);
375 XmStringFree (built_string
);
378 XmStringFree (key_string
);
381 \f/* update of list */
383 xm_update_list (widget_instance
* instance
,
389 XtRemoveAllCallbacks (widget
, XmNsingleSelectionCallback
);
390 XtAddCallback (widget
, XmNsingleSelectionCallback
, xm_generic_callback
,
392 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
395 XmString xmstr
= XmStringCreateLocalized (cur
->value
);
397 XmListAddItem (widget
, xmstr
, 0);
399 XmListSelectPos (widget
, i
, False
);
400 XmStringFree (xmstr
);
404 \f/* update of buttons */
406 xm_update_pushbutton (widget_instance
* instance
,
410 XtVaSetValues (widget
, XmNalignment
, XmALIGNMENT_CENTER
, NULL
);
411 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
412 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
416 xm_update_cascadebutton (widget_instance
* instance
,
420 /* Should also rebuild the menu by calling ...update_menu... */
421 XtRemoveAllCallbacks (widget
, XmNcascadingCallback
);
422 XtAddCallback (widget
, XmNcascadingCallback
, xm_pull_down_callback
,
426 \f/* update toggle and radiobox */
428 xm_update_toggle (widget_instance
* instance
,
432 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
433 XtAddCallback (widget
, XmNvalueChangedCallback
,
434 xm_generic_callback
, instance
);
435 XtVaSetValues (widget
, XmNset
, val
->selected
,
436 XmNalignment
, XmALIGNMENT_BEGINNING
, NULL
);
440 xm_update_radiobox (widget_instance
* instance
,
448 /* update the callback */
449 XtRemoveAllCallbacks (widget
, XmNentryCallback
);
450 XtAddCallback (widget
, XmNentryCallback
, xm_generic_callback
, instance
);
452 /* first update all the toggles */
453 /* Energize kernel interface is currently bad. It sets the selected widget
454 with the selected flag but returns it by its name. So we currently
455 have to support both setting the selection with the selected slot
456 of val contents and setting it with the "value" slot of val. The latter
457 has a higher priority. This to be removed when the kernel is fixed. */
458 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
460 toggle
= XtNameToWidget (widget
, cur
->value
);
463 XtSetSensitive (toggle
, cur
->enabled
);
464 if (!val
->value
&& cur
->selected
)
465 XtVaSetValues (toggle
, XmNset
, cur
->selected
, NULL
);
466 if (val
->value
&& strcmp (val
->value
, cur
->value
))
467 XtVaSetValues (toggle
, XmNset
, False
, NULL
);
471 /* The selected was specified by the value slot */
474 toggle
= XtNameToWidget (widget
, val
->value
);
476 XtVaSetValues (toggle
, XmNset
, True
, NULL
);
481 /* update a popup menu, pulldown menu or a menubar */
483 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
486 make_menu_in_widget (widget_instance
* instance
,
489 int keep_first_children
)
491 Widget
* children
= 0;
503 Widget
* old_children
;
504 unsigned int old_num_children
;
506 /* Disable drag and drop for labels in menu bar. */
507 static char overrideTrans
[] = "<Btn2Down>: Noop()";
508 XtTranslations override
= XtParseTranslationTable (overrideTrans
);
510 old_children
= XtCompositeChildren (widget
, &old_num_children
);
512 /* Allocate the children array */
513 for (num_children
= 0, cur
= val
; cur
; num_children
++, cur
= cur
->next
)
515 children
= (Widget
*)XtMalloc (num_children
* sizeof (Widget
));
517 /* WIDGET should be a RowColumn. */
518 if (!XmIsRowColumn (widget
))
521 /* Determine whether WIDGET is a menu bar. */
523 XtSetArg (al
[0], XmNrowColumnType
, &type
);
524 XtGetValues (widget
, al
, 1);
525 if (type
!= XmMENU_BAR
&& type
!= XmMENU_PULLDOWN
&& type
!= XmMENU_POPUP
)
527 menubar_p
= type
== XmMENU_BAR
;
529 /* Add a callback to popups and pulldowns that is called when
530 it is made invisible again. */
532 XtAddCallback (XtParent (widget
), XmNpopdownCallback
,
533 xm_pop_down_callback
, (XtPointer
)instance
);
535 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
536 for (child_index
= 0, cur
= val
; child_index
< keep_first_children
;
537 child_index
++, cur
= cur
->next
)
538 children
[child_index
] = old_children
[child_index
];
540 /* Check that those are all we have
541 (the caller should have deleted the rest). */
542 if (old_num_children
!= keep_first_children
)
545 /* Create the rest. */
546 for (child_index
= keep_first_children
; cur
; child_index
++, cur
= cur
->next
)
548 enum menu_separator separator
;
551 XtSetArg (al
[ac
], XmNsensitive
, cur
->enabled
); ac
++;
552 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
553 XtSetArg (al
[ac
], XmNuserData
, cur
->call_data
); ac
++;
555 if (instance
->pop_up_p
&& !cur
->contents
&& !cur
->call_data
556 && !lw_separator_p (cur
->name
, &separator
, 1))
559 XtSetArg (al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
560 title
= button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
562 else if (lw_separator_p (cur
->name
, &separator
, 1))
565 XtSetArg (al
[ac
], XmNseparatorType
, separator
); ++ac
;
566 button
= XmCreateSeparator (widget
, cur
->name
, al
, ac
);
568 else if (!cur
->contents
)
571 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
572 else if (!cur
->call_data
)
573 button
= XmCreateLabel (widget
, cur
->name
, al
, ac
);
574 else if (cur
->button_type
== BUTTON_TYPE_TOGGLE
575 || cur
->button_type
== BUTTON_TYPE_RADIO
)
577 XtSetArg (al
[ac
], XmNset
, cur
->selected
); ++ac
;
578 XtSetArg (al
[ac
], XmNvisibleWhenOff
, True
); ++ac
;
579 XtSetArg (al
[ac
], XmNindicatorType
,
580 (cur
->button_type
== BUTTON_TYPE_TOGGLE
581 ? XmN_OF_MANY
: XmONE_OF_MANY
));
583 button
= XmCreateToggleButton (widget
, cur
->name
, al
, ac
);
584 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
585 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
589 button
= XmCreatePushButton (widget
, cur
->name
, al
, ac
);
590 XtAddCallback (button
, XmNarmCallback
, xm_arm_callback
, cur
);
591 XtAddCallback (button
, XmNdisarmCallback
, xm_arm_callback
, cur
);
594 xm_update_label (instance
, button
, cur
);
596 /* Add a callback that is called when the button is
597 selected. Toggle buttons don't support
598 XmNactivateCallback, we use XmNvalueChangedCallback in
599 that case. Don't add a callback to a simple label. */
600 if (cur
->button_type
)
601 xm_update_toggle (instance
, button
, cur
);
602 else if (cur
->call_data
)
603 XtAddCallback (button
, XmNactivateCallback
, xm_generic_callback
,
604 (XtPointer
)instance
);
608 menu
= XmCreatePulldownMenu (widget
, cur
->name
, NULL
, 0);
610 make_menu_in_widget (instance
, menu
, cur
->contents
, 0);
611 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
612 button
= XmCreateCascadeButton (widget
, cur
->name
, al
, ac
);
614 xm_update_label (instance
, button
, cur
);
616 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
617 (XtPointer
)instance
);
618 XtOverrideTranslations (button
, override
);
622 children
[child_index
] = button
;
625 /* Last entry is the help button. The original comment read "Has to
626 be done after managing the buttons otherwise the menubar is only
627 4 pixels high." This is no longer true, and to make
628 XmNmenuHelpWidget work, we need to set it before managing the
629 children.. --gerd. */
631 XtVaSetValues (widget
, XmNmenuHelpWidget
, button
, NULL
);
634 XtManageChildren (children
, num_children
);
636 XtFree ((char *) children
);
638 XtFree ((char *) old_children
);
642 update_one_menu_entry (widget_instance
* instance
,
650 widget_value
* contents
;
652 if (val
->this_one_change
== NO_CHANGE
)
655 /* update the sensitivity and userdata */
656 /* Common to all widget types */
657 XtSetSensitive (widget
, val
->enabled
);
658 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
660 /* update the menu button as a label. */
661 if (val
->this_one_change
>= VISIBLE_CHANGE
)
663 xm_update_label (instance
, widget
, val
);
664 if (val
->button_type
)
665 xm_update_toggle (instance
, widget
, val
);
668 /* update the pulldown/pullaside as needed */
671 XtSetArg (al
[ac
], XmNsubMenuId
, &menu
); ac
++;
672 XtGetValues (widget
, al
, ac
);
674 contents
= val
->contents
;
680 unsigned int old_num_children
, i
;
684 parent
= XtParent (widget
);
685 widget_list
= XtCompositeChildren (parent
, &old_num_children
);
687 /* Find the widget position within the parent's widget list. */
688 for (i
= 0; i
< old_num_children
; i
++)
689 if (strcmp (XtName (widget_list
[i
]), XtName (widget
)) == 0)
691 if (i
== old_num_children
)
693 if (XmIsCascadeButton (widget_list
[i
]))
695 menu
= XmCreatePulldownMenu (parent
, XtName(widget
), NULL
, 0);
696 make_menu_in_widget (instance
, menu
, contents
, 0);
698 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
699 XtSetValues (widget
, al
, ac
);
705 /* The current menuitem is a XmPushButtonGadget, it
706 needs to be replaced by a CascadeButtonGadget */
707 XtDestroyWidget (widget_list
[i
]);
708 menu
= XmCreatePulldownMenu (parent
, val
->name
, NULL
, 0);
709 make_menu_in_widget (instance
, menu
, contents
, 0);
711 XtSetArg (al
[ac
], XmNsubMenuId
, menu
); ac
++;
712 /* Non-zero values don't work reliably in
713 conjunction with Emacs' event loop */
714 XtSetArg (al
[ac
], XmNmappingDelay
, 0); ac
++;
715 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
716 /* Tell Motif to put it in the right place */
717 XtSetArg (al
[ac
], XmNpositionIndex
, i
); ac
++;
719 button
= XmCreateCascadeButton (parent
, val
->name
, al
, ac
);
720 xm_update_label (instance
, button
, val
);
722 XtAddCallback (button
, XmNcascadingCallback
, xm_pull_down_callback
,
723 (XtPointer
)instance
);
724 XtManageChild (button
);
728 XtFree ((char*) widget_list
);
734 XtSetArg (al
[ac
], XmNsubMenuId
, NULL
); ac
++;
735 XtSetValues (widget
, al
, ac
);
736 XtDestroyWidget (menu
);
738 else if (deep_p
&& contents
->change
!= NO_CHANGE
)
739 xm_update_menu (instance
, menu
, val
, 1);
743 xm_update_menu (widget_instance
* instance
,
749 unsigned int num_children
;
750 int num_children_to_keep
= 0;
754 children
= XtCompositeChildren (widget
, &num_children
);
756 /* Widget is a RowColumn widget whose contents have to be updated
757 * to reflect the list of items in val->contents */
759 /* See how many buttons we can keep, and how many we
760 must completely replace. */
761 if (val
->contents
== 0)
762 num_children_to_keep
= 0;
763 else if (val
->contents
->change
== STRUCTURAL_CHANGE
)
767 for (i
= 0, cur
= val
->contents
;
769 && cur
); /* how else to ditch unwanted children ?? - mgd */
770 i
++, cur
= cur
->next
)
772 if (cur
->this_one_change
== STRUCTURAL_CHANGE
)
776 num_children_to_keep
= i
;
780 num_children_to_keep
= num_children
;
782 /* Update all the buttons of the RowColumn, in order,
783 except for those we are going to replace entirely. */
786 for (i
= 0, cur
= val
->contents
; i
< num_children_to_keep
; i
++)
790 num_children_to_keep
= i
;
793 if (children
[i
]->core
.being_destroyed
794 || strcmp (XtName (children
[i
]), cur
->name
))
796 update_one_menu_entry (instance
, children
[i
], cur
, deep_p
);
801 /* Now replace from scratch all the buttons after the last
802 place that the top-level structure changed. */
803 if (val
->contents
->change
== STRUCTURAL_CHANGE
)
805 destroy_all_children (widget
, num_children_to_keep
);
806 make_menu_in_widget (instance
, widget
, val
->contents
,
807 num_children_to_keep
);
810 XtFree ((char *) children
);
814 /* update text widgets */
817 xm_update_text (widget_instance
* instance
,
821 XmTextSetString (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 xm_update_text_field (widget_instance
* instance
,
834 XmTextFieldSetString (widget
, val
->value
? val
->value
: "");
835 XtRemoveAllCallbacks (widget
, XmNactivateCallback
);
836 XtAddCallback (widget
, XmNactivateCallback
, xm_generic_callback
, instance
);
837 XtRemoveAllCallbacks (widget
, XmNvalueChangedCallback
);
838 XtAddCallback (widget
, XmNvalueChangedCallback
,
839 xm_internal_update_other_instances
, instance
);
843 /* update a motif widget */
846 xm_update_one_widget (widget_instance
* instance
,
853 /* Mark as not edited */
856 /* Common to all widget types */
857 XtSetSensitive (widget
, val
->enabled
);
858 XtVaSetValues (widget
, XmNuserData
, val
->call_data
, NULL
);
860 /* Common to all label like widgets */
861 if (XtIsSubclass (widget
, xmLabelWidgetClass
))
862 xm_update_label (instance
, widget
, val
);
864 class = XtClass (widget
);
865 /* Class specific things */
866 if (class == xmPushButtonWidgetClass
||
867 class == xmArrowButtonWidgetClass
)
869 xm_update_pushbutton (instance
, widget
, val
);
871 else if (class == xmCascadeButtonWidgetClass
)
873 xm_update_cascadebutton (instance
, widget
, val
);
875 else if (class == xmToggleButtonWidgetClass
876 || class == xmToggleButtonGadgetClass
)
878 xm_update_toggle (instance
, widget
, val
);
880 else if (class == xmRowColumnWidgetClass
)
882 Boolean radiobox
= 0;
886 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
887 XtGetValues (widget
, al
, ac
);
890 xm_update_radiobox (instance
, widget
, val
);
892 xm_update_menu (instance
, widget
, val
, deep_p
);
894 else if (class == xmTextWidgetClass
)
896 xm_update_text (instance
, widget
, val
);
898 else if (class == xmTextFieldWidgetClass
)
900 xm_update_text_field (instance
, widget
, val
);
902 else if (class == xmListWidgetClass
)
904 xm_update_list (instance
, widget
, val
);
908 \f/* getting the value back */
910 xm_update_one_value (widget_instance
* instance
,
914 WidgetClass
class = XtClass (widget
);
915 widget_value
*old_wv
;
917 /* copy the call_data slot into the "return" widget_value */
918 for (old_wv
= instance
->info
->val
->contents
; old_wv
; old_wv
= old_wv
->next
)
919 if (!strcmp (val
->name
, old_wv
->name
))
921 val
->call_data
= old_wv
->call_data
;
925 if (class == xmToggleButtonWidgetClass
|| class == xmToggleButtonGadgetClass
)
927 XtVaGetValues (widget
, XmNset
, &val
->selected
, NULL
);
930 else if (class == xmTextWidgetClass
)
933 val
->value
= XmTextGetString (widget
);
936 else if (class == xmTextFieldWidgetClass
)
939 val
->value
= XmTextFieldGetString (widget
);
942 else if (class == xmRowColumnWidgetClass
)
944 Boolean radiobox
= 0;
948 XtSetArg (al
[ac
], XmNradioBehavior
, &radiobox
); ac
++;
949 XtGetValues (widget
, al
, ac
);
953 CompositeWidget radio
= (CompositeWidget
)widget
;
955 for (i
= 0; i
< radio
->composite
.num_children
; i
++)
958 Widget toggle
= radio
->composite
.children
[i
];
960 XtVaGetValues (toggle
, XmNset
, &set
, NULL
);
964 val
->value
= safe_strdup (XtName (toggle
));
970 else if (class == xmListWidgetClass
)
974 if (XmListGetSelectedPos (widget
, &pos_list
, &pos_cnt
))
978 for (cur
= val
->contents
, i
= 0; cur
; cur
= cur
->next
)
982 cur
->selected
= False
;
984 for (j
= 0; j
< pos_cnt
; j
++)
985 if (pos_list
[j
] == i
)
987 cur
->selected
= True
;
988 val
->value
= safe_strdup (cur
->name
);
992 XtFree ((char *) pos_list
);
998 /* This function is for activating a button from a program. It's wrong because
999 we pass a NULL argument in the call_data which is not Motif compatible.
1000 This is used from the XmNdefaultAction callback of the List widgets to
1001 have a double-click put down a dialog box like the button would do.
1002 I could not find a way to do that with accelerators.
1005 activate_button (Widget widget
,
1007 XtPointer call_data
)
1009 Widget button
= (Widget
)closure
;
1010 XtCallCallbacks (button
, XmNactivateCallback
, NULL
);
1013 /* creation functions */
1015 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1017 dialog_key_cb (Widget widget
,
1020 Boolean
*continue_to_dispatch
)
1023 Modifiers modif_ret
;
1025 XtTranslateKeycode (event
->xkey
.display
, event
->xkey
.keycode
, 0,
1028 if (sym
== osfXK_Cancel
)
1030 Widget w
= *((Widget
*) closure
);
1032 while (w
&& ! XtIsShell (w
))
1035 if (XtIsShell (w
)) XtPopdown (w
);
1038 *continue_to_dispatch
= TRUE
;
1043 make_dialog (char* name
,
1048 Boolean text_input_slot
,
1058 Widget icon_separator
;
1063 Widget children
[16]; /* for the final XtManageChildren */
1065 Arg al
[64]; /* Arg List */
1066 int ac
; /* Arg Count */
1072 XtSetArg(al
[ac
], XmNtitle
, shell_title
); ac
++;
1073 XtSetArg(al
[ac
], XtNallowShellResize
, True
); ac
++;
1074 XtSetArg(al
[ac
], XmNdeleteResponse
, XmUNMAP
); ac
++;
1075 result
= XmCreateDialogShell (parent
, "dialog", al
, ac
);
1077 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1078 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1079 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1080 form
= XmCreateForm (result
, shell_title
, al
, ac
);
1085 XtSetArg(al
[ac
], XmNautoUnmanage
, FALSE
); ac
++;
1086 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1087 form
= XmCreateForm (parent
, shell_title
, al
, ac
);
1091 n_children
= left_buttons
+ right_buttons
+ 1;
1093 XtSetArg(al
[ac
], XmNpacking
, n_children
== 3?
1094 XmPACK_COLUMN
: XmPACK_TIGHT
); ac
++;
1095 XtSetArg(al
[ac
], XmNorientation
, n_children
== 3?
1096 XmVERTICAL
: XmHORIZONTAL
); ac
++;
1097 XtSetArg(al
[ac
], XmNnumColumns
, left_buttons
+ right_buttons
+ 1); ac
++;
1098 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1099 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1100 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1101 XtSetArg(al
[ac
], XmNadjustLast
, False
); ac
++;
1102 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1103 XtSetArg(al
[ac
], XmNisAligned
, True
); ac
++;
1104 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1105 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_FORM
); ac
++;
1106 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1107 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1108 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1109 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1110 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1111 row
= XmCreateRowColumn (form
, "row", al
, ac
);
1114 for (i
= 0; i
< left_buttons
; i
++)
1116 char button_name
[16];
1117 sprintf (button_name
, "button%d", i
+ 1);
1121 XtSetArg(al
[ac
], XmNhighlightThickness
, 1); ac
++;
1122 XtSetArg(al
[ac
], XmNshowAsDefault
, TRUE
); ac
++;
1124 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1125 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1126 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1127 XtAddEventHandler (children
[n_children
],
1128 KeyPressMask
, False
, dialog_key_cb
, result
);
1132 button
= children
[n_children
];
1134 XtSetArg(al
[ac
], XmNdefaultButton
, button
); ac
++;
1135 XtSetValues (row
, al
, ac
);
1141 /* invisible separator button */
1143 XtSetArg (al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1144 children
[n_children
] = XmCreateLabel (row
, "separator_button", al
, ac
);
1147 for (i
= 0; i
< right_buttons
; i
++)
1149 char button_name
[16];
1150 sprintf (button_name
, "button%d", left_buttons
+ i
+ 1);
1152 XtSetArg(al
[ac
], XmNmarginWidth
, 10); ac
++;
1153 XtSetArg(al
[ac
], XmNnavigationType
, XmTAB_GROUP
); ac
++;
1154 children
[n_children
] = XmCreatePushButton (row
, button_name
, al
, ac
);
1155 XtAddEventHandler (children
[n_children
],
1156 KeyPressMask
, False
, dialog_key_cb
, result
);
1158 if (! button
) button
= children
[n_children
];
1162 XtManageChildren (children
, n_children
);
1165 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1166 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1167 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1168 XtSetArg(al
[ac
], XmNbottomWidget
, row
); ac
++;
1169 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1170 XtSetArg(al
[ac
], XmNleftOffset
, 0); ac
++;
1171 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1172 XtSetArg(al
[ac
], XmNrightOffset
, 0); ac
++;
1173 separator
= XmCreateSeparator (form
, "", al
, ac
);
1176 XtSetArg(al
[ac
], XmNlabelType
, XmPIXMAP
); ac
++;
1177 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1178 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1179 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_NONE
); ac
++;
1180 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_FORM
); ac
++;
1181 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1182 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1183 icon
= XmCreateLabel (form
, icon_name
, al
, ac
);
1186 XtSetArg(al
[ac
], XmNmappedWhenManaged
, FALSE
); ac
++;
1187 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
1188 XtSetArg(al
[ac
], XmNtopOffset
, 6); ac
++;
1189 XtSetArg(al
[ac
], XmNtopWidget
, icon
); ac
++;
1190 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1191 XtSetArg(al
[ac
], XmNbottomOffset
, 6); ac
++;
1192 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1193 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_NONE
); ac
++;
1194 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_NONE
); ac
++;
1195 icon_separator
= XmCreateLabel (form
, "", al
, ac
);
1197 if (text_input_slot
)
1200 XtSetArg(al
[ac
], XmNcolumns
, 50); ac
++;
1201 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1202 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1203 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1204 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1205 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1206 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1207 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1208 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1209 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1210 value
= XmCreateTextField (form
, "value", al
, ac
);
1216 XtSetArg(al
[ac
], XmNmarginWidth
, 0); ac
++;
1217 XtSetArg(al
[ac
], XmNmarginHeight
, 0); ac
++;
1218 XtSetArg(al
[ac
], XmNspacing
, 13); ac
++;
1219 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_CENTER
); ac
++;
1220 XtSetArg(al
[ac
], XmNorientation
, XmHORIZONTAL
); ac
++;
1221 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1222 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1223 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1224 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1225 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1226 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1227 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1228 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1229 value
= XmCreateRadioBox (form
, "radiobutton1", al
, ac
);
1232 radio_butt
= XmCreateToggleButtonGadget (value
, "radio1", al
, ac
);
1233 children
[i
++] = radio_butt
;
1234 radio_butt
= XmCreateToggleButtonGadget (value
, "radio2", al
, ac
);
1235 children
[i
++] = radio_butt
;
1236 radio_butt
= XmCreateToggleButtonGadget (value
, "radio3", al
, ac
);
1237 children
[i
++] = radio_butt
;
1238 XtManageChildren (children
, i
);
1243 XtSetArg(al
[ac
], XmNvisibleItemCount
, 5); ac
++;
1244 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_NONE
); ac
++;
1245 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1246 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1247 XtSetArg(al
[ac
], XmNbottomWidget
, separator
); ac
++;
1248 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1249 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1250 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1251 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1252 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1253 value
= XmCreateScrolledList (form
, "list", al
, ac
);
1255 /* this is the easiest way I found to have the dble click in the
1256 list activate the default button */
1257 XtAddCallback (value
, XmNdefaultActionCallback
, activate_button
, button
);
1261 XtSetArg(al
[ac
], XmNalignment
, XmALIGNMENT_BEGINNING
); ac
++;
1262 XtSetArg(al
[ac
], XmNtopAttachment
, XmATTACH_FORM
); ac
++;
1263 XtSetArg(al
[ac
], XmNtopOffset
, 13); ac
++;
1264 XtSetArg(al
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1265 XtSetArg(al
[ac
], XmNbottomOffset
, 13); ac
++;
1266 XtSetArg(al
[ac
], XmNbottomWidget
,
1267 text_input_slot
|| radio_box
|| list
? value
: separator
); ac
++;
1268 XtSetArg(al
[ac
], XmNleftAttachment
, XmATTACH_WIDGET
); ac
++;
1269 XtSetArg(al
[ac
], XmNleftOffset
, 13); ac
++;
1270 XtSetArg(al
[ac
], XmNleftWidget
, icon
); ac
++;
1271 XtSetArg(al
[ac
], XmNrightAttachment
, XmATTACH_FORM
); ac
++;
1272 XtSetArg(al
[ac
], XmNrightOffset
, 13); ac
++;
1273 message
= XmCreateLabel (form
, "message", al
, ac
);
1276 XtManageChild (value
);
1279 children
[i
] = row
; i
++;
1280 children
[i
] = separator
; i
++;
1281 if (text_input_slot
|| radio_box
)
1283 children
[i
] = value
; i
++;
1285 children
[i
] = message
; i
++;
1286 children
[i
] = icon
; i
++;
1287 children
[i
] = icon_separator
; i
++;
1288 XtManageChildren (children
, i
);
1290 if (text_input_slot
|| list
)
1292 XtInstallAccelerators (value
, button
);
1293 XtSetKeyboardFocus (result
, value
);
1297 XtInstallAccelerators (form
, button
);
1298 XtSetKeyboardFocus (result
, button
);
1304 static destroyed_instance
*
1305 find_matching_instance (widget_instance
* instance
)
1307 destroyed_instance
* cur
;
1308 destroyed_instance
* prev
;
1309 char* type
= instance
->info
->type
;
1310 char* name
= instance
->info
->name
;
1312 for (prev
= NULL
, cur
= all_destroyed_instances
;
1314 prev
= cur
, cur
= cur
->next
)
1316 if (!strcmp (cur
->name
, name
)
1317 && !strcmp (cur
->type
, type
)
1318 && cur
->parent
== instance
->parent
1319 && cur
->pop_up_p
== instance
->pop_up_p
)
1322 prev
->next
= cur
->next
;
1324 all_destroyed_instances
= cur
->next
;
1327 /* do some cleanup */
1328 else if (!cur
->widget
)
1331 prev
->next
= cur
->next
;
1333 all_destroyed_instances
= cur
->next
;
1334 free_destroyed_instance (cur
);
1335 cur
= prev
? prev
: all_destroyed_instances
;
1342 mark_dead_instance_destroyed (Widget widget
,
1344 XtPointer call_data
)
1346 destroyed_instance
* instance
= (destroyed_instance
*)closure
;
1347 instance
->widget
= NULL
;
1351 recenter_widget (Widget widget
)
1353 Widget parent
= XtParent (widget
);
1354 Screen
* screen
= XtScreen (widget
);
1355 Dimension screen_width
= WidthOfScreen (screen
);
1356 Dimension screen_height
= HeightOfScreen (screen
);
1357 Dimension parent_width
= 0;
1358 Dimension parent_height
= 0;
1359 Dimension child_width
= 0;
1360 Dimension child_height
= 0;
1364 XtVaGetValues (widget
, XtNwidth
, &child_width
, XtNheight
, &child_height
, NULL
);
1365 XtVaGetValues (parent
, XtNwidth
, &parent_width
, XtNheight
, &parent_height
,
1368 x
= (((Position
)parent_width
) - ((Position
)child_width
)) / 2;
1369 y
= (((Position
)parent_height
) - ((Position
)child_height
)) / 2;
1371 XtTranslateCoords (parent
, x
, y
, &x
, &y
);
1373 if (x
+ child_width
> screen_width
)
1374 x
= screen_width
- child_width
;
1378 if (y
+ child_height
> screen_height
)
1379 y
= screen_height
- child_height
;
1383 XtVaSetValues (widget
, XtNx
, x
, XtNy
, y
, NULL
);
1387 recycle_instance (destroyed_instance
* instance
)
1389 Widget widget
= instance
->widget
;
1391 /* widget is NULL if the parent was destroyed. */
1397 /* Remove the destroy callback as the instance is not in the list
1399 XtRemoveCallback (instance
->parent
, XtNdestroyCallback
,
1400 mark_dead_instance_destroyed
,
1401 (XtPointer
)instance
);
1403 /* Give the focus to the initial item */
1404 focus
= XtNameToWidget (widget
, "*value");
1406 focus
= XtNameToWidget (widget
, "*button1");
1408 XtSetKeyboardFocus (widget
, focus
);
1410 /* shrink the separator label back to their original size */
1411 separator
= XtNameToWidget (widget
, "*separator_button");
1413 XtVaSetValues (separator
, XtNwidth
, 5, XtNheight
, 5, NULL
);
1415 /* Center the dialog in its parent */
1416 recenter_widget (widget
);
1418 free_destroyed_instance (instance
);
1423 xm_create_dialog (widget_instance
* instance
)
1425 char* name
= instance
->info
->type
;
1426 Widget parent
= instance
->parent
;
1428 Boolean pop_up_p
= instance
->pop_up_p
;
1429 char* shell_name
= 0;
1430 char* icon_name
= 0;
1431 Boolean text_input_slot
= False
;
1432 Boolean radio_box
= False
;
1433 Boolean list
= False
;
1435 int left_buttons
= 0;
1436 int right_buttons
= 1;
1437 destroyed_instance
* dead_one
;
1439 /* try to find a widget to recycle */
1440 dead_one
= find_matching_instance (instance
);
1443 Widget recycled_widget
= recycle_instance (dead_one
);
1444 if (recycled_widget
)
1445 return recycled_widget
;
1450 icon_name
= "dbox-error";
1451 shell_name
= "Error";
1455 icon_name
= "dbox-info";
1456 shell_name
= "Information";
1461 icon_name
= "dbox-question";
1462 shell_name
= "Prompt";
1466 text_input_slot
= True
;
1467 icon_name
= "dbox-question";
1468 shell_name
= "Prompt";
1472 icon_name
= "dbox-question";
1473 shell_name
= "Question";
1477 total_buttons
= name
[1] - '0';
1479 if (name
[3] == 'T' || name
[3] == 't')
1481 text_input_slot
= False
;
1485 right_buttons
= name
[4] - '0';
1487 left_buttons
= total_buttons
- right_buttons
;
1489 widget
= make_dialog (name
, parent
, pop_up_p
,
1490 shell_name
, icon_name
, text_input_slot
, radio_box
,
1491 list
, left_buttons
, right_buttons
);
1493 XtAddCallback (widget
, XmNpopdownCallback
, xm_nosel_callback
,
1494 (XtPointer
) instance
);
1499 /* Create a menu bar. We turn off the f10 key
1500 because we have not yet managed to make it work right in Motif. */
1503 make_menubar (widget_instance
* instance
)
1509 XtSetArg(al
[ac
], XmNmenuAccelerator
, 0); ++ac
;
1510 return XmCreateMenuBar (instance
->parent
, instance
->info
->name
, al
, ac
);
1514 remove_grabs (Widget shell
,
1516 XtPointer call_data
)
1518 Widget menu
= (Widget
) closure
;
1519 XmRemoveFromPostFromList (menu
, XtParent (XtParent (menu
)));
1523 make_popup_menu (widget_instance
* instance
)
1525 Widget parent
= instance
->parent
;
1526 Window parent_window
= parent
->core
.window
;
1529 /* sets the parent window to 0 to fool Motif into not generating a grab */
1530 parent
->core
.window
= 0;
1531 result
= XmCreatePopupMenu (parent
, instance
->info
->name
, NULL
, 0);
1532 XtAddCallback (XtParent (result
), XmNpopdownCallback
, remove_grabs
,
1534 parent
->core
.window
= parent_window
;
1539 make_main (widget_instance
* instance
)
1541 Widget parent
= instance
->parent
;
1547 XtSetArg (al
[ac
], XtNborderWidth
, 0); ac
++;
1548 XtSetArg (al
[ac
], XmNspacing
, 0); ac
++;
1549 result
= XmCreateMainWindow (parent
, instance
->info
->name
, al
, ac
);
1553 \f/* Table of functions to create widgets */
1557 /* interface with the XDesigner generated functions */
1558 typedef Widget (*widget_maker
) (Widget
);
1559 extern Widget
create_project_p_sheet (Widget parent
);
1560 extern Widget
create_debugger_p_sheet (Widget parent
);
1561 extern Widget
create_breaklist_p_sheet (Widget parent
);
1562 extern Widget
create_le_browser_p_sheet (Widget parent
);
1563 extern Widget
create_class_browser_p_sheet (Widget parent
);
1564 extern Widget
create_call_browser_p_sheet (Widget parent
);
1565 extern Widget
create_build_dialog (Widget parent
);
1566 extern Widget
create_editmode_dialog (Widget parent
);
1567 extern Widget
create_search_dialog (Widget parent
);
1568 extern Widget
create_project_display_dialog (Widget parent
);
1571 make_one (widget_instance
* instance
, widget_maker fn
)
1577 if (instance
->pop_up_p
)
1579 XtSetArg (al
[ac
], XmNallowShellResize
, TRUE
); ac
++;
1580 result
= XmCreateDialogShell (instance
->parent
, "dialog", NULL
, 0);
1581 XtAddCallback (result
, XmNpopdownCallback
, &xm_nosel_callback
,
1582 (XtPointer
) instance
);
1587 result
= (*fn
) (instance
->parent
);
1588 XtRealizeWidget (result
);
1594 make_project_p_sheet (widget_instance
* instance
)
1596 return make_one (instance
, create_project_p_sheet
);
1600 make_debugger_p_sheet (widget_instance
* instance
)
1602 return make_one (instance
, create_debugger_p_sheet
);
1606 make_breaklist_p_sheet (widget_instance
* instance
)
1608 return make_one (instance
, create_breaklist_p_sheet
);
1612 make_le_browser_p_sheet (widget_instance
* instance
)
1614 return make_one (instance
, create_le_browser_p_sheet
);
1618 make_class_browser_p_sheet (widget_instance
* instance
)
1620 return make_one (instance
, create_class_browser_p_sheet
);
1624 make_call_browser_p_sheet (widget_instance
* instance
)
1626 return make_one (instance
, create_call_browser_p_sheet
);
1630 make_build_dialog (widget_instance
* instance
)
1632 return make_one (instance
, create_build_dialog
);
1636 make_editmode_dialog (widget_instance
* instance
)
1638 return make_one (instance
, create_editmode_dialog
);
1642 make_search_dialog (widget_instance
* instance
)
1644 return make_one (instance
, create_search_dialog
);
1648 make_project_display_dialog (widget_instance
* instance
)
1650 return make_one (instance
, create_project_display_dialog
);
1653 #endif /* ENERGIZE */
1655 widget_creation_entry
1656 xm_creation_table
[] =
1658 {"menubar", make_menubar
},
1659 {"popup", make_popup_menu
},
1660 {"main", make_main
},
1662 {"project_p_sheet", make_project_p_sheet
},
1663 {"debugger_p_sheet", make_debugger_p_sheet
},
1664 {"breaklist_psheet", make_breaklist_p_sheet
},
1665 {"leb_psheet", make_le_browser_p_sheet
},
1666 {"class_browser_psheet", make_class_browser_p_sheet
},
1667 {"ctree_browser_psheet", make_call_browser_p_sheet
},
1668 {"build", make_build_dialog
},
1669 {"editmode", make_editmode_dialog
},
1670 {"search", make_search_dialog
},
1671 {"project_display", make_project_display_dialog
},
1672 #endif /* ENERGIZE */
1676 \f/* Destruction of instances */
1678 xm_destroy_instance ( widget_instance
* instance
)
1680 Widget widget
= instance
->widget
;
1681 /* recycle the dialog boxes */
1682 /* Disable the recycling until we can find a way to have the dialog box
1683 get reasonable layout after we modify its contents. */
1685 && XtClass (widget
) == xmDialogShellWidgetClass
)
1687 destroyed_instance
* dead_instance
=
1688 make_destroyed_instance (instance
->info
->name
,
1689 instance
->info
->type
,
1692 instance
->pop_up_p
);
1693 dead_instance
->next
= all_destroyed_instances
;
1694 all_destroyed_instances
= dead_instance
;
1695 XtUnmanageChild (first_child (instance
->widget
));
1696 XFlush (XtDisplay (instance
->widget
));
1697 XtAddCallback (instance
->parent
, XtNdestroyCallback
,
1698 mark_dead_instance_destroyed
, (XtPointer
)dead_instance
);
1702 /* This might not be necessary now that the nosel is attached to
1703 popdown instead of destroy, but it can't hurt. */
1704 XtRemoveCallback (instance
->widget
, XtNdestroyCallback
,
1705 xm_nosel_callback
, (XtPointer
)instance
);
1706 XtDestroyWidget (instance
->widget
);
1710 \f/* popup utility */
1712 xm_popup_menu (Widget widget
, XEvent
*event
)
1714 XButtonPressedEvent dummy
;
1718 dummy
.type
= ButtonPress
;
1720 dummy
.send_event
= 0;
1721 dummy
.display
= XtDisplay (widget
);
1722 dummy
.window
= XtWindow (XtParent (widget
));
1725 XQueryPointer (dummy
.display
, dummy
.window
, &dummy
.root
,
1726 &dummy
.subwindow
, &dummy
.x_root
, &dummy
.y_root
,
1727 &dummy
.x
, &dummy
.y
, &dummy
.state
);
1728 event
= (XEvent
*) &dummy
;
1731 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1733 /* Setting the menuPost resource only required by Motif 1.1 and
1734 LessTif 0.84 and earlier. With later versions of LessTif,
1735 setting menuPost is unnecessary and may cause problems, so
1737 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1739 /* This is so totally ridiculous: there's NO WAY to tell Motif
1740 that *any* button can select a menu item. Only one button
1741 can have that honor. */
1744 if (event
->xbutton
.state
& Button5Mask
) trans
= "<Btn5Down>";
1745 else if (event
->xbutton
.state
& Button4Mask
) trans
= "<Btn4Down>";
1746 else if (event
->xbutton
.state
& Button3Mask
) trans
= "<Btn3Down>";
1747 else if (event
->xbutton
.state
& Button2Mask
) trans
= "<Btn2Down>";
1748 else if (event
->xbutton
.state
& Button1Mask
) trans
= "<Btn1Down>";
1749 if (trans
) XtVaSetValues (widget
, XmNmenuPost
, trans
, NULL
);
1753 XmMenuPosition (widget
, (XButtonPressedEvent
*) event
);
1756 XtManageChild (widget
);
1760 set_min_dialog_size (Widget w
)
1764 XtVaGetValues (w
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1765 XtVaSetValues (w
, XmNminWidth
, width
, XmNminHeight
, height
, NULL
);
1769 xm_pop_instance (widget_instance
* instance
, Boolean up
)
1771 Widget widget
= instance
->widget
;
1773 if (XtClass (widget
) == xmDialogShellWidgetClass
)
1775 Widget widget_to_manage
= first_child (widget
);
1778 XtManageChild (widget_to_manage
);
1779 set_min_dialog_size (widget
);
1780 XtSetKeyboardFocus (instance
->parent
, widget
);
1783 XtUnmanageChild (widget_to_manage
);
1788 XtManageChild (widget
);
1790 XtUnmanageChild (widget
);
1795 /* motif callback */
1798 do_call (Widget widget
,
1800 enum do_call_type type
)
1804 XtPointer user_data
;
1805 widget_instance
* instance
= (widget_instance
*)closure
;
1806 Widget instance_widget
;
1811 if (widget
->core
.being_destroyed
)
1814 instance_widget
= instance
->widget
;
1815 if (!instance_widget
)
1818 id
= instance
->info
->id
;
1821 XtSetArg (al
[ac
], XmNuserData
, &user_data
); ac
++;
1822 XtGetValues (widget
, al
, ac
);
1827 if (instance
->info
->pre_activate_cb
)
1828 instance
->info
->pre_activate_cb (widget
, id
, user_data
);
1832 if (instance
->info
->selection_cb
)
1833 instance
->info
->selection_cb (widget
, id
, user_data
);
1837 if (instance
->info
->selection_cb
)
1838 instance
->info
->selection_cb (widget
, id
, (XtPointer
) -1);
1842 if (instance
->info
->post_activate_cb
)
1843 instance
->info
->post_activate_cb (widget
, id
, user_data
);
1851 /* Like lw_internal_update_other_instances except that it does not do
1852 anything if its shell parent is not managed. This is to protect
1853 lw_internal_update_other_instances to dereference freed memory
1854 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1857 xm_internal_update_other_instances (Widget widget
,
1859 XtPointer call_data
)
1862 for (parent
= widget
; parent
; parent
= XtParent (parent
))
1863 if (XtIsShell (parent
))
1865 else if (!XtIsManaged (parent
))
1867 lw_internal_update_other_instances (widget
, closure
, call_data
);
1871 xm_generic_callback (Widget widget
,
1873 XtPointer call_data
)
1875 lw_internal_update_other_instances (widget
, closure
, call_data
);
1876 do_call (widget
, closure
, selection
);
1880 xm_nosel_callback (Widget widget
,
1882 XtPointer call_data
)
1884 /* This callback is only called when a dialog box is dismissed with
1885 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1886 box to be destroyed in that case, not just unmapped, so that it
1887 releases its keyboard grabs. But there are problems with running
1888 our callbacks while the widget is in the process of being
1889 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1890 XmDESTROY and then destroy it ourself after having run the
1892 do_call (widget
, closure
, no_selection
);
1893 XtDestroyWidget (widget
);
1897 xm_pull_down_callback (Widget widget
,
1899 XtPointer call_data
)
1901 Widget parent
= XtParent (widget
);
1903 if (XmIsRowColumn (parent
))
1905 unsigned char type
= 0xff;
1906 XtVaGetValues (parent
, XmNrowColumnType
, &type
, NULL
);
1907 if (type
== XmMENU_BAR
)
1908 do_call (widget
, closure
, pre_activate
);
1913 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1914 CLOSURE is a pointer to the widget_instance of the shell,
1916 Note that this callback is called for each cascade button in a
1917 menu, whether or not its submenu is visible. */
1920 xm_pop_down_callback (Widget widget
,
1922 XtPointer call_data
)
1924 widget_instance
*instance
= (widget_instance
*) closure
;
1926 if ((!instance
->pop_up_p
&& XtParent (widget
) == instance
->widget
)
1927 || XtParent (widget
) == instance
->parent
)
1928 do_call (widget
, closure
, post_activate
);
1932 /* set the keyboard focus */
1934 xm_set_keyboard_focus (Widget parent
, Widget w
)
1936 XmProcessTraversal (w
, 0);
1937 XtSetKeyboardFocus (parent
, w
);
1940 /* Motif hack to set the main window areas. */
1942 xm_set_main_areas (Widget parent
,
1946 XmMainWindowSetAreas (parent
,
1947 menubar
, /* menubar (maybe 0) */
1948 0, /* command area (psheets) */
1949 0, /* horizontal scroll */
1950 0, /* vertical scroll */
1951 work_area
); /* work area */
1954 /* Motif hack to control resizing on the menubar. */
1956 xm_manage_resizing (Widget w
, Boolean flag
)
1958 XtVaSetValues (w
, XtNallowShellResize
, flag
, NULL
);
1961 /* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965
1962 (do not change this comment) */