(uninstall): Ignore exit code of `rm'.
[emacs.git] / lwlib / lwlib-Xm.c
blob2cbcba4c1a0912a169c66e56808d8b297da08558
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)
9 any later version.
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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
34 #include "lwlib-Xm.h"
35 #include "lwlib-utils.h"
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Label.h>
43 #include <Xm/List.h>
44 #include <Xm/MainW.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
48 #include <Xm/PushB.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
52 #include <Xm/Text.h>
53 #include <Xm/TextF.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
60 #include <Xm/Form.h>
62 #if defined __STDC__ || defined PROTOTYPES
63 #define P_(X) X
64 #else
65 #define P_(X) ()
66 #endif
68 enum do_call_type { pre_activate, selection, no_selection, post_activate };
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
83 Widget, Widget,
84 Boolean));
85 static void free_destroyed_instance P_ ((destroyed_instance*));
86 Widget first_child P_ ((Widget));
87 Boolean lw_motif_widget_p P_ ((Widget));
88 static XmString resource_motif_string P_ ((Widget, char *));
89 static void destroy_all_children P_ ((Widget, int));
90 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
91 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
92 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
93 widget_value *));
94 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
95 widget_value *));
96 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
98 static void make_menu_in_widget P_ ((widget_instance *, Widget,
99 widget_value *, int));
100 static void update_one_menu_entry P_ ((widget_instance *, Widget,
101 widget_value *, Boolean));
102 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
103 Boolean));
104 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
105 static void xm_update_text_field P_ ((widget_instance *, Widget,
106 widget_value *));
107 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
108 static void activate_button P_ ((Widget, XtPointer, XtPointer));
109 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
110 Boolean, Boolean, Boolean, int, int));
111 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
112 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
113 static void recenter_widget P_ ((Widget));
114 static Widget recycle_instance P_ ((destroyed_instance*));
115 Widget xm_create_dialog P_ ((widget_instance*));
116 static Widget make_menubar P_ ((widget_instance*));
117 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
118 static Widget make_popup_menu P_ ((widget_instance*));
119 static Widget make_main P_ ((widget_instance*));
120 void xm_destroy_instance P_ ((widget_instance*));
121 void xm_popup_menu P_ ((Widget, XEvent *));
122 static void set_min_dialog_size P_ ((Widget));
123 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
124 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
125 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
126 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_unmap_callback P_ ((Widget, XtPointer, XtPointer));
129 void xm_set_keyboard_focus P_ ((Widget, Widget));
130 void xm_set_main_areas P_ ((Widget, Widget, Widget));
131 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
132 XtPointer));
133 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
135 #if 0
136 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
137 Boolean));
138 void xm_pop_instance P_ ((widget_instance*, Boolean));
139 void xm_manage_resizing P_ ((Widget, Boolean));
140 #endif
143 static destroyed_instance *all_destroyed_instances = NULL;
145 static destroyed_instance*
146 make_destroyed_instance (name, type, widget, parent, pop_up_p)
147 char* name;
148 char* type;
149 Widget widget;
150 Widget parent;
151 Boolean pop_up_p;
153 destroyed_instance* instance =
154 (destroyed_instance*)malloc (sizeof (destroyed_instance));
155 instance->name = safe_strdup (name);
156 instance->type = safe_strdup (type);
157 instance->widget = widget;
158 instance->parent = parent;
159 instance->pop_up_p = pop_up_p;
160 instance->next = NULL;
161 return instance;
164 static void
165 free_destroyed_instance (instance)
166 destroyed_instance* instance;
168 free (instance->name);
169 free (instance->type);
170 free (instance);
173 \f/* motif utility functions */
174 Widget
175 first_child (widget)
176 Widget widget;
178 return ((CompositeWidget)widget)->composite.children [0];
181 Boolean
182 lw_motif_widget_p (widget)
183 Widget widget;
185 return
186 XtClass (widget) == xmDialogShellWidgetClass
187 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
190 static XmString
191 resource_motif_string (widget, name)
192 Widget widget;
193 char* name;
195 XtResource resource;
196 XmString result = 0;
198 resource.resource_name = name;
199 resource.resource_class = XmCXmString;
200 resource.resource_type = XmRXmString;
201 resource.resource_size = sizeof (XmString);
202 resource.resource_offset = 0;
203 resource.default_type = XtRImmediate;
204 resource.default_addr = 0;
206 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
207 "DialogString", &resource, 1, NULL, 0);
208 return result;
211 /* Destroy all of the children of WIDGET
212 starting with number FIRST_CHILD_TO_DESTROY. */
214 static void
215 destroy_all_children (widget, first_child_to_destroy)
216 Widget widget;
217 int first_child_to_destroy;
219 Widget* children;
220 unsigned int number;
221 int i;
223 children = XtCompositeChildren (widget, &number);
224 if (children)
226 XtUnmanageChildren (children + first_child_to_destroy,
227 number - first_child_to_destroy);
229 /* Unmanage all children and destroy them. They will only be
230 really destroyed when we get out of DispatchEvent. */
231 for (i = first_child_to_destroy; i < number; i++)
233 Arg al[2];
234 Widget submenu = 0;
235 /* Cascade buttons have submenus,and these submenus
236 need to be freed. But they are not included in
237 XtCompositeChildren. So get it out of the cascade button
238 and free it. If this child is not a cascade button,
239 then submenu should remain unchanged. */
240 XtSetArg (al[0], XmNsubMenuId, &submenu);
241 XtGetValues (children[i], al, 1);
242 if (submenu)
243 XtDestroyWidget (submenu);
244 XtDestroyWidget (children[i]);
247 XtFree ((char *) children);
253 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
254 menu. CLIENT_DATA contains a pointer to the widget_value
255 corresponding to widget W. CALL_DATA contains a
256 XmPushButtonCallbackStruct containing the reason why the callback
257 is called. */
259 static void
260 xm_arm_callback (w, client_data, call_data)
261 Widget w;
262 XtPointer client_data, call_data;
264 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
265 widget_value *wv = (widget_value *) client_data;
266 widget_instance *instance;
268 /* Get the id of the menu bar or popup menu this widget is in. */
269 while (w != None)
271 if (XmIsRowColumn (w))
273 unsigned char type = 0xff;
275 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
276 if (type == XmMENU_BAR || type == XmMENU_POPUP)
277 break;
280 w = XtParent (w);
283 if (w != None)
285 instance = lw_get_widget_instance (w);
286 if (instance && instance->info->highlight_cb)
288 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
289 instance->info->highlight_cb (w, instance->info->id, call_data);
296 /* Update the label of widget WIDGET. WIDGET must be a Label widget
297 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
298 the value to update.
300 Menus:
302 Emacs fills VAL->name with the text to display in the menu, and
303 sets VAL->value to null. Function make_menu_in_widget creates
304 widgets with VAL->name as resource name. This works because the
305 Label widget uses its resource name for display if no
306 XmNlabelString is set.
308 Dialogs:
310 VAL->name is again set to the resource name, but VAL->value is
311 not null, and contains the label string to display. */
313 static void
314 xm_update_label (instance, widget, val)
315 widget_instance* instance;
316 Widget widget;
317 widget_value* val;
319 XmString res_string = 0;
320 XmString built_string = 0;
321 XmString key_string = 0;
322 Arg al [256];
323 int ac;
325 ac = 0;
327 if (val->value)
329 /* A label string is specified, i.e. we are in a dialog. First
330 see if it is overridden by something from the resource file. */
331 res_string = resource_motif_string (widget, val->value);
333 if (res_string)
335 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
337 else
339 built_string =
340 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
341 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
344 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
347 if (val->key)
349 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
350 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
353 if (ac)
354 XtSetValues (widget, al, ac);
356 if (built_string)
357 XmStringFree (built_string);
359 if (key_string)
360 XmStringFree (key_string);
363 \f/* update of list */
364 static void
365 xm_update_list (instance, widget, val)
366 widget_instance* instance;
367 Widget widget;
368 widget_value* val;
370 widget_value* cur;
371 int i;
372 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
373 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
374 instance);
375 for (cur = val->contents, i = 0; cur; cur = cur->next)
376 if (cur->value)
378 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
379 i += 1;
380 XmListAddItem (widget, xmstr, 0);
381 if (cur->selected)
382 XmListSelectPos (widget, i, False);
383 XmStringFree (xmstr);
387 \f/* update of buttons */
388 static void
389 xm_update_pushbutton (instance, widget, val)
390 widget_instance* instance;
391 Widget widget;
392 widget_value* val;
394 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
395 XtRemoveAllCallbacks (widget, XmNactivateCallback);
396 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
399 static void
400 xm_update_cascadebutton (instance, widget, val)
401 widget_instance* instance;
402 Widget widget;
403 widget_value* val;
405 /* Should also rebuild the menu by calling ...update_menu... */
406 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
407 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
408 instance);
411 \f/* update toggle and radiobox */
412 static void
413 xm_update_toggle (instance, widget, val)
414 widget_instance* instance;
415 Widget widget;
416 widget_value* val;
418 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
419 XtAddCallback (widget, XmNvalueChangedCallback,
420 xm_generic_callback, instance);
421 XtVaSetValues (widget, XmNset, val->selected,
422 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
425 static void
426 xm_update_radiobox (instance, widget, val)
427 widget_instance* instance;
428 Widget widget;
429 widget_value* val;
432 Widget toggle;
433 widget_value* cur;
435 /* update the callback */
436 XtRemoveAllCallbacks (widget, XmNentryCallback);
437 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
439 /* first update all the toggles */
440 /* Energize kernel interface is currently bad. It sets the selected widget
441 with the selected flag but returns it by its name. So we currently
442 have to support both setting the selection with the selected slot
443 of val contents and setting it with the "value" slot of val. The latter
444 has a higher priority. This to be removed when the kernel is fixed. */
445 for (cur = val->contents; cur; cur = cur->next)
447 toggle = XtNameToWidget (widget, cur->value);
448 if (toggle)
450 XtVaSetValues (toggle, XmNsensitive, cur->enabled, NULL);
451 if (!val->value && cur->selected)
452 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
453 if (val->value && strcmp (val->value, cur->value))
454 XtVaSetValues (toggle, XmNset, False, NULL);
458 /* The selected was specified by the value slot */
459 if (val->value)
461 toggle = XtNameToWidget (widget, val->value);
462 if (toggle)
463 XtVaSetValues (toggle, XmNset, True, NULL);
468 /* update a popup menu, pulldown menu or a menubar */
470 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
472 static void
473 make_menu_in_widget (instance, widget, val, keep_first_children)
474 widget_instance* instance;
475 Widget widget;
476 widget_value* val;
477 int keep_first_children;
479 Widget* children = 0;
480 int num_children;
481 int child_index;
482 widget_value* cur;
483 Widget button = 0;
484 Widget title = 0;
485 Widget menu;
486 Arg al [256];
487 int ac;
488 Boolean menubar_p;
489 unsigned char type;
491 Widget* old_children;
492 unsigned int old_num_children;
494 old_children = XtCompositeChildren (widget, &old_num_children);
496 /* Allocate the children array */
497 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
498 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
500 /* WIDGET should be a RowColumn. */
501 if (!XmIsRowColumn (widget))
502 abort ();
504 /* Determine whether WIDGET is a menu bar. */
505 type = -1;
506 XtSetArg (al[0], XmNrowColumnType, &type);
507 XtGetValues (widget, al, 1);
508 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
509 abort ();
510 menubar_p = type == XmMENU_BAR;
512 #if 0 /* This can't be used in LessTif as of 2000-01-24 because it's
513 impossible to decide from this plus the cascading callback if a
514 popup is still posted or not. When selecting cascade button A,
515 then B, then clicking on the frame, the sequence of callbacks is
516 `cascading A', cascading B', `popdown for all cascade buttons in
517 the menu bar. */
518 /* Add a callback to popups and pulldowns that is called when
519 it is made invisible again. */
520 if (!menubar_p)
521 XtAddCallback (XtParent (widget), XmNpopdownCallback,
522 xm_pop_down_callback, (XtPointer)instance);
523 #endif
525 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
526 for (child_index = 0, cur = val; child_index < keep_first_children;
527 child_index++, cur = cur->next)
528 children[child_index] = old_children[child_index];
530 /* Check that those are all we have
531 (the caller should have deleted the rest). */
532 if (old_num_children != keep_first_children)
533 abort ();
535 /* Create the rest. */
536 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
538 enum menu_separator separator;
540 ac = 0;
541 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
542 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
543 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
545 if (instance->pop_up_p && !cur->contents && !cur->call_data
546 && !lw_separator_p (cur->name, &separator, 1))
548 ac = 0;
549 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
550 title = button = XmCreateLabel (widget, cur->name, al, ac);
552 else if (lw_separator_p (cur->name, &separator, 1))
554 ac = 0;
555 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
556 button = XmCreateSeparator (widget, cur->name, al, ac);
558 else if (!cur->contents)
560 if (menubar_p)
561 button = XmCreateCascadeButton (widget, cur->name, al, ac);
562 else if (!cur->call_data)
563 button = XmCreateLabel (widget, cur->name, al, ac);
564 else if (cur->button_type == BUTTON_TYPE_TOGGLE
565 || cur->button_type == BUTTON_TYPE_RADIO)
567 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
568 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
569 XtSetArg (al[ac], XmNindicatorType,
570 (cur->button_type == BUTTON_TYPE_TOGGLE
571 ? XmN_OF_MANY : XmONE_OF_MANY));
572 ++ac;
573 button = XmCreateToggleButton (widget, cur->name, al, ac);
574 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
575 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
577 else
579 button = XmCreatePushButton (widget, cur->name, al, ac);
580 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
581 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
584 xm_update_label (instance, button, cur);
586 /* Add a callback that is called when the button is
587 selected. Toggle buttons don't support
588 XmNactivateCallback, we use XmNvalueChangedCallback in
589 that case. Don't add a callback to a simple label. */
590 if (cur->button_type)
591 xm_update_toggle (instance, button, cur);
592 else if (cur->call_data)
593 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
594 (XtPointer)instance);
596 else
598 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
600 /* XmNpopdownCallback is working strangely under LessTif.
601 Using XmNunmapCallback is the only way to go there. */
602 if (menubar_p)
603 XtAddCallback (menu, XmNunmapCallback, xm_unmap_callback,
604 (XtPointer) instance);
606 make_menu_in_widget (instance, menu, cur->contents, 0);
607 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
608 button = XmCreateCascadeButton (widget, cur->name, al, ac);
610 xm_update_label (instance, button, cur);
612 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
613 (XtPointer)instance);
616 children[child_index] = button;
619 /* Last entry is the help button. The original comment read "Has to
620 be done after managing the buttons otherwise the menubar is only
621 4 pixels high." This is no longer true, and to make
622 XmNmenuHelpWidget work, we need to set it before managing the
623 children.. --gerd. */
624 if (button)
625 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
627 /* LessTif apparently doesn't recompute centered text when more
628 widgets are added. So, do it after all widgets have been
629 created. */
630 if (title)
631 XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, NULL);
633 if (num_children)
634 XtManageChildren (children, num_children);
636 XtFree ((char *) children);
637 if (old_children)
638 XtFree ((char *) old_children);
641 static void
642 update_one_menu_entry (instance, widget, val, deep_p)
643 widget_instance* instance;
644 Widget widget;
645 widget_value* val;
646 Boolean deep_p;
648 Arg al [256];
649 int ac;
650 Widget menu;
651 widget_value* contents;
653 if (val->this_one_change == NO_CHANGE)
654 return;
656 /* update the sensitivity and userdata */
657 /* Common to all widget types */
658 XtVaSetValues (widget,
659 XmNsensitive, val->enabled,
660 XmNuserData, val->call_data,
661 NULL);
663 /* update the menu button as a label. */
664 if (val->this_one_change >= VISIBLE_CHANGE)
666 xm_update_label (instance, widget, val);
667 if (val->button_type)
668 xm_update_toggle (instance, widget, val);
671 /* update the pulldown/pullaside as needed */
672 ac = 0;
673 menu = NULL;
674 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
675 XtGetValues (widget, al, ac);
677 contents = val->contents;
679 if (!menu)
681 if (contents)
683 unsigned int old_num_children, i;
684 Widget parent;
685 Widget *widget_list;
687 parent = XtParent (widget);
688 widget_list = XtCompositeChildren (parent, &old_num_children);
690 /* Find the widget position within the parent's widget list. */
691 for (i = 0; i < old_num_children; i++)
692 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
693 break;
694 if (i == old_num_children)
695 abort ();
696 if (XmIsCascadeButton (widget_list[i]))
698 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
699 make_menu_in_widget (instance, menu, contents, 0);
700 ac = 0;
701 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
702 XtSetValues (widget, al, ac);
704 else
706 Widget button;
708 /* The current menuitem is a XmPushButtonGadget, it
709 needs to be replaced by a CascadeButtonGadget */
710 XtDestroyWidget (widget_list[i]);
711 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
712 make_menu_in_widget (instance, menu, contents, 0);
713 ac = 0;
714 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
715 /* Non-zero values don't work reliably in
716 conjunction with Emacs' event loop */
717 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
718 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
719 /* Tell Motif to put it in the right place */
720 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
721 #endif
722 button = XmCreateCascadeButton (parent, val->name, al, ac);
723 xm_update_label (instance, button, val);
725 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
726 (XtPointer)instance);
727 XtManageChild (button);
731 else if (!contents)
733 ac = 0;
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);
742 static void
743 xm_update_menu (instance, widget, val, deep_p)
744 widget_instance* instance;
745 Widget widget;
746 widget_value* val;
747 Boolean deep_p;
749 Widget* children;
750 unsigned int num_children;
751 int num_children_to_keep = 0;
752 int i;
753 widget_value* cur;
755 children = XtCompositeChildren (widget, &num_children);
757 /* Widget is a RowColumn widget whose contents have to be updated
758 * to reflect the list of items in val->contents */
760 /* See how many buttons we can keep, and how many we
761 must completely replace. */
762 if (val->contents == 0)
763 num_children_to_keep = 0;
764 else if (val->contents->change == STRUCTURAL_CHANGE)
766 if (children)
768 for (i = 0, cur = val->contents;
769 (i < num_children
770 && cur); /* how else to ditch unwanted children ?? - mgd */
771 i++, cur = cur->next)
773 if (cur->this_one_change == STRUCTURAL_CHANGE)
774 break;
777 num_children_to_keep = i;
780 else
781 num_children_to_keep = num_children;
783 /* Update all the buttons of the RowColumn, in order,
784 except for those we are going to replace entirely. */
785 if (children)
787 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
789 if (!cur)
791 num_children_to_keep = i;
792 break;
794 if (children [i]->core.being_destroyed
795 || strcmp (XtName (children [i]), cur->name))
796 continue;
797 update_one_menu_entry (instance, children [i], cur, deep_p);
798 cur = cur->next;
802 /* Now replace from scratch all the buttons after the last
803 place that the top-level structure changed. */
804 if (val->contents->change == STRUCTURAL_CHANGE)
806 destroy_all_children (widget, num_children_to_keep);
807 make_menu_in_widget (instance, widget, val->contents,
808 num_children_to_keep);
811 XtFree ((char *) children);
815 /* update text widgets */
817 static void
818 xm_update_text (instance, widget, val)
819 widget_instance* instance;
820 Widget widget;
821 widget_value* val;
823 XmTextSetString (widget, val->value ? val->value : "");
824 XtRemoveAllCallbacks (widget, XmNactivateCallback);
825 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
826 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
827 XtAddCallback (widget, XmNvalueChangedCallback,
828 xm_internal_update_other_instances, instance);
831 static void
832 xm_update_text_field (instance, widget, val)
833 widget_instance* instance;
834 Widget widget;
835 widget_value* val;
837 XmTextFieldSetString (widget, val->value ? val->value : "");
838 XtRemoveAllCallbacks (widget, XmNactivateCallback);
839 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
840 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
841 XtAddCallback (widget, XmNvalueChangedCallback,
842 xm_internal_update_other_instances, instance);
846 /* update a motif widget */
848 void
849 xm_update_one_widget (instance, widget, val, deep_p)
850 widget_instance* instance;
851 Widget widget;
852 widget_value* val;
853 Boolean deep_p;
855 WidgetClass class;
857 /* Mark as not edited */
858 val->edited = False;
860 /* Common to all widget types */
861 XtVaSetValues (widget,
862 XmNsensitive, val->enabled,
863 XmNuserData, val->call_data,
864 NULL);
866 /* Common to all label like widgets */
867 if (XtIsSubclass (widget, xmLabelWidgetClass))
868 xm_update_label (instance, widget, val);
870 class = XtClass (widget);
871 /* Class specific things */
872 if (class == xmPushButtonWidgetClass ||
873 class == xmArrowButtonWidgetClass)
875 xm_update_pushbutton (instance, widget, val);
877 else if (class == xmCascadeButtonWidgetClass)
879 xm_update_cascadebutton (instance, widget, val);
881 else if (class == xmToggleButtonWidgetClass
882 || class == xmToggleButtonGadgetClass)
884 xm_update_toggle (instance, widget, val);
886 else if (class == xmRowColumnWidgetClass)
888 Boolean radiobox = 0;
889 int ac = 0;
890 Arg al [1];
892 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
893 XtGetValues (widget, al, ac);
895 if (radiobox)
896 xm_update_radiobox (instance, widget, val);
897 else
898 xm_update_menu (instance, widget, val, deep_p);
900 else if (class == xmTextWidgetClass)
902 xm_update_text (instance, widget, val);
904 else if (class == xmTextFieldWidgetClass)
906 xm_update_text_field (instance, widget, val);
908 else if (class == xmListWidgetClass)
910 xm_update_list (instance, widget, val);
914 \f/* getting the value back */
915 void
916 xm_update_one_value (instance, widget, val)
917 widget_instance* instance;
918 Widget widget;
919 widget_value* val;
921 WidgetClass class = XtClass (widget);
922 widget_value *old_wv;
924 /* copy the call_data slot into the "return" widget_value */
925 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
926 if (!strcmp (val->name, old_wv->name))
928 val->call_data = old_wv->call_data;
929 break;
932 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
934 XtVaGetValues (widget, XmNset, &val->selected, NULL);
935 val->edited = True;
937 else if (class == xmTextWidgetClass)
939 if (val->value)
940 free (val->value);
941 val->value = XmTextGetString (widget);
942 val->edited = True;
944 else if (class == xmTextFieldWidgetClass)
946 if (val->value)
947 free (val->value);
948 val->value = XmTextFieldGetString (widget);
949 val->edited = True;
951 else if (class == xmRowColumnWidgetClass)
953 Boolean radiobox = 0;
954 int ac = 0;
955 Arg al [1];
957 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
958 XtGetValues (widget, al, ac);
960 if (radiobox)
962 CompositeWidget radio = (CompositeWidget)widget;
963 int i;
964 for (i = 0; i < radio->composite.num_children; i++)
966 int set = False;
967 Widget toggle = radio->composite.children [i];
969 XtVaGetValues (toggle, XmNset, &set, NULL);
970 if (set)
972 if (val->value)
973 free (val->value);
974 val->value = safe_strdup (XtName (toggle));
977 val->edited = True;
980 else if (class == xmListWidgetClass)
982 int pos_cnt;
983 int* pos_list;
984 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
986 int i;
987 widget_value* cur;
988 for (cur = val->contents, i = 0; cur; cur = cur->next)
989 if (cur->value)
991 int j;
992 cur->selected = False;
993 i += 1;
994 for (j = 0; j < pos_cnt; j++)
995 if (pos_list [j] == i)
997 cur->selected = True;
998 val->value = safe_strdup (cur->name);
1001 val->edited = 1;
1002 XtFree ((char *) pos_list);
1008 /* This function is for activating a button from a program. It's wrong because
1009 we pass a NULL argument in the call_data which is not Motif compatible.
1010 This is used from the XmNdefaultAction callback of the List widgets to
1011 have a double-click put down a dialog box like the button would do.
1012 I could not find a way to do that with accelerators.
1014 static void
1015 activate_button (widget, closure, call_data)
1016 Widget widget;
1017 XtPointer closure;
1018 XtPointer call_data;
1020 Widget button = (Widget)closure;
1021 XtCallCallbacks (button, XmNactivateCallback, NULL);
1024 /* creation functions */
1026 /* dialogs */
1027 static Widget
1028 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1029 radio_box, list, left_buttons, right_buttons)
1030 char* name;
1031 Widget parent;
1032 Boolean pop_up_p;
1033 char* shell_title;
1034 char* icon_name;
1035 Boolean text_input_slot;
1036 Boolean radio_box;
1037 Boolean list;
1038 int left_buttons;
1039 int right_buttons;
1041 Widget result;
1042 Widget form;
1043 Widget row;
1044 Widget icon;
1045 Widget icon_separator;
1046 Widget message;
1047 Widget value = 0;
1048 Widget separator;
1049 Widget button = 0;
1050 Widget children [16]; /* for the final XtManageChildren */
1051 int n_children;
1052 Arg al[64]; /* Arg List */
1053 int ac; /* Arg Count */
1054 int i;
1056 if (pop_up_p)
1058 ac = 0;
1059 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1060 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1061 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1062 result = XmCreateDialogShell (parent, "dialog", al, ac);
1063 ac = 0;
1064 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1065 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1066 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1067 form = XmCreateForm (result, shell_title, al, ac);
1069 else
1071 ac = 0;
1072 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1073 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1074 form = XmCreateForm (parent, shell_title, al, ac);
1075 result = form;
1078 n_children = left_buttons + right_buttons + 1;
1079 ac = 0;
1080 XtSetArg(al[ac], XmNpacking, n_children == 3?
1081 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1082 XtSetArg(al[ac], XmNorientation, n_children == 3?
1083 XmVERTICAL: XmHORIZONTAL); ac++;
1084 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1085 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1086 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1087 XtSetArg(al[ac], XmNspacing, 13); ac++;
1088 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1089 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1090 XtSetArg(al[ac], XmNisAligned, True); ac++;
1091 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1092 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1093 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1094 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1095 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1096 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1097 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1098 row = XmCreateRowColumn (form, "row", al, ac);
1100 n_children = 0;
1101 for (i = 0; i < left_buttons; i++)
1103 char button_name [16];
1104 sprintf (button_name, "button%d", i + 1);
1105 ac = 0;
1106 if (i == 0)
1108 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1109 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1111 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1112 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1113 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1115 if (i == 0)
1117 button = children [n_children];
1118 ac = 0;
1119 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1120 XtSetValues (row, al, ac);
1123 n_children++;
1126 /* invisible separator button */
1127 ac = 0;
1128 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1129 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1130 n_children++;
1132 for (i = 0; i < right_buttons; i++)
1134 char button_name [16];
1135 sprintf (button_name, "button%d", left_buttons + i + 1);
1136 ac = 0;
1137 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1138 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1139 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1140 if (! button) button = children [n_children];
1141 n_children++;
1144 XtManageChildren (children, n_children);
1146 ac = 0;
1147 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1148 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1149 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1150 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1151 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1152 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1153 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1154 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1155 separator = XmCreateSeparator (form, "", al, ac);
1157 ac = 0;
1158 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1159 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1160 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1161 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1162 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1163 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1164 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1165 icon = XmCreateLabel (form, icon_name, al, ac);
1167 ac = 0;
1168 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1169 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1170 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1171 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1172 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1173 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1174 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1175 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1176 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1177 icon_separator = XmCreateLabel (form, "", al, ac);
1179 if (text_input_slot)
1181 ac = 0;
1182 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1183 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1184 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1185 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1186 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1187 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1188 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1189 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1190 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1191 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1192 value = XmCreateTextField (form, "value", al, ac);
1194 else if (radio_box)
1196 Widget radio_butt;
1197 ac = 0;
1198 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1199 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1200 XtSetArg(al[ac], XmNspacing, 13); ac++;
1201 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1202 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1203 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1204 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1205 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1206 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1207 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1208 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1209 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1210 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1211 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1212 ac = 0;
1213 i = 0;
1214 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1215 children [i++] = radio_butt;
1216 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1217 children [i++] = radio_butt;
1218 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1219 children [i++] = radio_butt;
1220 XtManageChildren (children, i);
1222 else if (list)
1224 ac = 0;
1225 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1226 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1227 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1228 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1229 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1230 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1231 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1232 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1233 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1234 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1235 value = XmCreateScrolledList (form, "list", al, ac);
1237 /* this is the easiest way I found to have the dble click in the
1238 list activate the default button */
1239 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1242 ac = 0;
1243 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1244 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1245 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1246 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1247 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1248 XtSetArg(al[ac], XmNbottomWidget,
1249 text_input_slot || radio_box || list ? value : separator); ac++;
1250 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1251 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1252 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1253 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1254 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1255 message = XmCreateLabel (form, "message", al, ac);
1257 if (list)
1258 XtManageChild (value);
1260 i = 0;
1261 children [i] = row; i++;
1262 children [i] = separator; i++;
1263 if (text_input_slot || radio_box)
1265 children [i] = value; i++;
1267 children [i] = message; i++;
1268 children [i] = icon; i++;
1269 children [i] = icon_separator; i++;
1270 XtManageChildren (children, i);
1272 if (text_input_slot || list)
1274 XtInstallAccelerators (value, button);
1275 XtSetKeyboardFocus (result, value);
1277 else
1279 XtInstallAccelerators (form, button);
1280 XtSetKeyboardFocus (result, button);
1283 return result;
1286 static destroyed_instance*
1287 find_matching_instance (instance)
1288 widget_instance* instance;
1290 destroyed_instance* cur;
1291 destroyed_instance* prev;
1292 char* type = instance->info->type;
1293 char* name = instance->info->name;
1295 for (prev = NULL, cur = all_destroyed_instances;
1296 cur;
1297 prev = cur, cur = cur->next)
1299 if (!strcmp (cur->name, name)
1300 && !strcmp (cur->type, type)
1301 && cur->parent == instance->parent
1302 && cur->pop_up_p == instance->pop_up_p)
1304 if (prev)
1305 prev->next = cur->next;
1306 else
1307 all_destroyed_instances = cur->next;
1308 return cur;
1310 /* do some cleanup */
1311 else if (!cur->widget)
1313 if (prev)
1314 prev->next = cur->next;
1315 else
1316 all_destroyed_instances = cur->next;
1317 free_destroyed_instance (cur);
1318 cur = prev ? prev : all_destroyed_instances;
1321 return NULL;
1324 static void
1325 mark_dead_instance_destroyed (widget, closure, call_data)
1326 Widget widget;
1327 XtPointer closure;
1328 XtPointer call_data;
1330 destroyed_instance* instance = (destroyed_instance*)closure;
1331 instance->widget = NULL;
1334 static void
1335 recenter_widget (widget)
1336 Widget widget;
1338 Widget parent = XtParent (widget);
1339 Screen* screen = XtScreen (widget);
1340 Dimension screen_width = WidthOfScreen (screen);
1341 Dimension screen_height = HeightOfScreen (screen);
1342 Dimension parent_width = 0;
1343 Dimension parent_height = 0;
1344 Dimension child_width = 0;
1345 Dimension child_height = 0;
1346 Position x;
1347 Position y;
1349 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1350 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1351 NULL);
1353 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1354 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1356 XtTranslateCoords (parent, x, y, &x, &y);
1358 if (x + child_width > screen_width)
1359 x = screen_width - child_width;
1360 if (x < 0)
1361 x = 0;
1363 if (y + child_height > screen_height)
1364 y = screen_height - child_height;
1365 if (y < 0)
1366 y = 0;
1368 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1371 static Widget
1372 recycle_instance (instance)
1373 destroyed_instance* instance;
1375 Widget widget = instance->widget;
1377 /* widget is NULL if the parent was destroyed. */
1378 if (widget)
1380 Widget focus;
1381 Widget separator;
1383 /* Remove the destroy callback as the instance is not in the list
1384 anymore */
1385 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1386 mark_dead_instance_destroyed,
1387 (XtPointer)instance);
1389 /* Give the focus to the initial item */
1390 focus = XtNameToWidget (widget, "*value");
1391 if (!focus)
1392 focus = XtNameToWidget (widget, "*button1");
1393 if (focus)
1394 XtSetKeyboardFocus (widget, focus);
1396 /* shrink the separator label back to their original size */
1397 separator = XtNameToWidget (widget, "*separator_button");
1398 if (separator)
1399 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1401 /* Center the dialog in its parent */
1402 recenter_widget (widget);
1404 free_destroyed_instance (instance);
1405 return widget;
1408 Widget
1409 xm_create_dialog (instance)
1410 widget_instance* instance;
1412 char* name = instance->info->type;
1413 Widget parent = instance->parent;
1414 Widget widget;
1415 Boolean pop_up_p = instance->pop_up_p;
1416 char* shell_name = 0;
1417 char* icon_name;
1418 Boolean text_input_slot = False;
1419 Boolean radio_box = False;
1420 Boolean list = False;
1421 int total_buttons;
1422 int left_buttons = 0;
1423 int right_buttons = 1;
1424 destroyed_instance* dead_one;
1426 /* try to find a widget to recycle */
1427 dead_one = find_matching_instance (instance);
1428 if (dead_one)
1430 Widget recycled_widget = recycle_instance (dead_one);
1431 if (recycled_widget)
1432 return recycled_widget;
1435 switch (name [0]){
1436 case 'E': case 'e':
1437 icon_name = "dbox-error";
1438 shell_name = "Error";
1439 break;
1441 case 'I': case 'i':
1442 icon_name = "dbox-info";
1443 shell_name = "Information";
1444 break;
1446 case 'L': case 'l':
1447 list = True;
1448 icon_name = "dbox-question";
1449 shell_name = "Prompt";
1450 break;
1452 case 'P': case 'p':
1453 text_input_slot = True;
1454 icon_name = "dbox-question";
1455 shell_name = "Prompt";
1456 break;
1458 case 'Q': case 'q':
1459 icon_name = "dbox-question";
1460 shell_name = "Question";
1461 break;
1464 total_buttons = name [1] - '0';
1466 if (name [3] == 'T' || name [3] == 't')
1468 text_input_slot = False;
1469 radio_box = True;
1471 else if (name [3])
1472 right_buttons = name [4] - '0';
1474 left_buttons = total_buttons - right_buttons;
1476 widget = make_dialog (name, parent, pop_up_p,
1477 shell_name, icon_name, text_input_slot, radio_box,
1478 list, left_buttons, right_buttons);
1480 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1481 (XtPointer) instance);
1482 return widget;
1485 /* Create a menu bar. We turn off the f10 key
1486 because we have not yet managed to make it work right in Motif. */
1488 static Widget
1489 make_menubar (instance)
1490 widget_instance* instance;
1492 Arg al[3];
1493 int ac;
1495 ac = 0;
1496 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1498 #if 0
1499 /* As of 2000-01-17, the LessTif menu bar resizes to height 0 when
1500 all its children are removed, causing an annoying flickering
1501 behavior. Prevent that by not allowing resizing. */
1502 XtSetArg(al[ac], XmNresizeHeight, False); ++ac;
1503 XtSetArg(al[ac], XmNresizeWidth, False); ++ac;
1504 #endif
1506 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1509 static void
1510 remove_grabs (shell, closure, call_data)
1511 Widget shell;
1512 XtPointer closure;
1513 XtPointer call_data;
1515 Widget menu = (Widget) closure;
1516 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1519 static Widget
1520 make_popup_menu (instance)
1521 widget_instance* instance;
1523 Widget parent = instance->parent;
1524 Window parent_window = parent->core.window;
1525 Widget result;
1527 /* sets the parent window to 0 to fool Motif into not generating a grab */
1528 parent->core.window = 0;
1529 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1530 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1531 (XtPointer)result);
1532 parent->core.window = parent_window;
1533 return result;
1536 static Widget
1537 make_main (instance)
1538 widget_instance* instance;
1540 Widget parent = instance->parent;
1541 Widget result;
1542 Arg al[2];
1543 int ac;
1545 ac = 0;
1546 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1547 XtSetArg (al[ac], XmNspacing, 0); ac++;
1548 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1549 return result;
1552 \f/* Table of functions to create widgets */
1554 #ifdef ENERGIZE
1556 /* interface with the XDesigner generated functions */
1557 typedef Widget (*widget_maker) (Widget);
1558 extern Widget create_project_p_sheet (Widget parent);
1559 extern Widget create_debugger_p_sheet (Widget parent);
1560 extern Widget create_breaklist_p_sheet (Widget parent);
1561 extern Widget create_le_browser_p_sheet (Widget parent);
1562 extern Widget create_class_browser_p_sheet (Widget parent);
1563 extern Widget create_call_browser_p_sheet (Widget parent);
1564 extern Widget create_build_dialog (Widget parent);
1565 extern Widget create_editmode_dialog (Widget parent);
1566 extern Widget create_search_dialog (Widget parent);
1567 extern Widget create_project_display_dialog (Widget parent);
1569 static Widget
1570 make_one (widget_instance* instance, widget_maker fn)
1572 Widget result;
1573 Arg al [64];
1574 int ac = 0;
1576 if (instance->pop_up_p)
1578 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1579 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1580 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1581 (XtPointer) instance);
1582 (*fn) (result);
1584 else
1586 result = (*fn) (instance->parent);
1587 XtRealizeWidget (result);
1589 return result;
1592 static Widget
1593 make_project_p_sheet (widget_instance* instance)
1595 return make_one (instance, create_project_p_sheet);
1598 static Widget
1599 make_debugger_p_sheet (widget_instance* instance)
1601 return make_one (instance, create_debugger_p_sheet);
1604 static Widget
1605 make_breaklist_p_sheet (widget_instance* instance)
1607 return make_one (instance, create_breaklist_p_sheet);
1610 static Widget
1611 make_le_browser_p_sheet (widget_instance* instance)
1613 return make_one (instance, create_le_browser_p_sheet);
1616 static Widget
1617 make_class_browser_p_sheet (widget_instance* instance)
1619 return make_one (instance, create_class_browser_p_sheet);
1622 static Widget
1623 make_call_browser_p_sheet (widget_instance* instance)
1625 return make_one (instance, create_call_browser_p_sheet);
1628 static Widget
1629 make_build_dialog (widget_instance* instance)
1631 return make_one (instance, create_build_dialog);
1634 static Widget
1635 make_editmode_dialog (widget_instance* instance)
1637 return make_one (instance, create_editmode_dialog);
1640 static Widget
1641 make_search_dialog (widget_instance* instance)
1643 return make_one (instance, create_search_dialog);
1646 static Widget
1647 make_project_display_dialog (widget_instance* instance)
1649 return make_one (instance, create_project_display_dialog);
1652 #endif /* ENERGIZE */
1654 widget_creation_entry
1655 xm_creation_table [] =
1657 {"menubar", make_menubar},
1658 {"popup", make_popup_menu},
1659 {"main", make_main},
1660 #ifdef ENERGIZE
1661 {"project_p_sheet", make_project_p_sheet},
1662 {"debugger_p_sheet", make_debugger_p_sheet},
1663 {"breaklist_psheet", make_breaklist_p_sheet},
1664 {"leb_psheet", make_le_browser_p_sheet},
1665 {"class_browser_psheet", make_class_browser_p_sheet},
1666 {"ctree_browser_psheet", make_call_browser_p_sheet},
1667 {"build", make_build_dialog},
1668 {"editmode", make_editmode_dialog},
1669 {"search", make_search_dialog},
1670 {"project_display", make_project_display_dialog},
1671 #endif /* ENERGIZE */
1672 {NULL, NULL}
1675 \f/* Destruction of instances */
1676 void
1677 xm_destroy_instance (instance)
1678 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. */
1684 if (0
1685 && XtClass (widget) == xmDialogShellWidgetClass)
1687 destroyed_instance* dead_instance =
1688 make_destroyed_instance (instance->info->name,
1689 instance->info->type,
1690 instance->widget,
1691 instance->parent,
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);
1700 else
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 */
1711 void
1712 xm_popup_menu (widget, event)
1713 Widget widget;
1714 XEvent *event;
1716 XButtonPressedEvent dummy;
1718 if (event == 0)
1720 dummy.type = ButtonPress;
1721 dummy.serial = 0;
1722 dummy.send_event = 0;
1723 dummy.display = XtDisplay (widget);
1724 dummy.window = XtWindow (XtParent (widget));
1725 dummy.time = 0;
1726 dummy.button = 0;
1727 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1728 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1729 &dummy.x, &dummy.y, &dummy.state);
1730 event = (XEvent *) &dummy;
1733 if (event->type == ButtonPress || event->type == ButtonRelease)
1735 /* This is so totally ridiculous: there's NO WAY to tell Motif
1736 that *any* button can select a menu item. Only one button
1737 can have that honor.
1739 char *trans = 0;
1740 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1741 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1742 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1743 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1744 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1745 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1746 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1748 XtManageChild (widget);
1751 static void
1752 set_min_dialog_size (w)
1753 Widget w;
1755 short width;
1756 short height;
1757 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1758 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1761 void
1762 xm_pop_instance (instance, up)
1763 widget_instance* instance;
1764 Boolean up;
1766 Widget widget = instance->widget;
1768 if (XtClass (widget) == xmDialogShellWidgetClass)
1770 Widget widget_to_manage = first_child (widget);
1771 if (up)
1773 XtManageChild (widget_to_manage);
1774 set_min_dialog_size (widget);
1775 XtSetKeyboardFocus (instance->parent, widget);
1777 else
1778 XtUnmanageChild (widget_to_manage);
1780 else
1782 if (up)
1783 XtManageChild (widget);
1784 else
1785 XtUnmanageChild (widget);
1790 /* motif callback */
1792 static void
1793 do_call (widget, closure, type)
1794 Widget widget;
1795 XtPointer closure;
1796 enum do_call_type type;
1798 Arg al [256];
1799 int ac;
1800 XtPointer user_data;
1801 widget_instance* instance = (widget_instance*)closure;
1802 Widget instance_widget;
1803 LWLIB_ID id;
1805 if (!instance)
1806 return;
1807 if (widget->core.being_destroyed)
1808 return;
1810 instance_widget = instance->widget;
1811 if (!instance_widget)
1812 return;
1814 id = instance->info->id;
1815 ac = 0;
1816 user_data = NULL;
1817 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1818 XtGetValues (widget, al, ac);
1819 switch (type)
1821 case pre_activate:
1822 if (instance->info->pre_activate_cb)
1823 instance->info->pre_activate_cb (widget, id, user_data);
1824 break;
1825 case selection:
1826 if (instance->info->selection_cb)
1827 instance->info->selection_cb (widget, id, user_data);
1828 break;
1829 case no_selection:
1830 if (instance->info->selection_cb)
1831 instance->info->selection_cb (widget, id, (XtPointer) -1);
1832 break;
1833 case post_activate:
1834 if (instance->info->post_activate_cb)
1835 instance->info->post_activate_cb (widget, id, user_data);
1836 break;
1837 default:
1838 abort ();
1842 /* Like lw_internal_update_other_instances except that it does not do
1843 anything if its shell parent is not managed. This is to protect
1844 lw_internal_update_other_instances to dereference freed memory
1845 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1846 list */
1847 static void
1848 xm_internal_update_other_instances (widget, closure, call_data)
1849 Widget widget;
1850 XtPointer closure;
1851 XtPointer call_data;
1853 Widget parent;
1854 for (parent = widget; parent; parent = XtParent (parent))
1855 if (XtIsShell (parent))
1856 break;
1857 else if (!XtIsManaged (parent))
1858 return;
1859 lw_internal_update_other_instances (widget, closure, call_data);
1862 static void
1863 xm_generic_callback (widget, closure, call_data)
1864 Widget widget;
1865 XtPointer closure;
1866 XtPointer call_data;
1868 lw_internal_update_other_instances (widget, closure, call_data);
1869 do_call (widget, closure, selection);
1872 static void
1873 xm_nosel_callback (widget, closure, call_data)
1874 Widget widget;
1875 XtPointer closure;
1876 XtPointer call_data;
1878 /* This callback is only called when a dialog box is dismissed with the wm's
1879 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1880 in that case, not just unmapped, so that it releases its keyboard grabs.
1881 But there are problems with running our callbacks while the widget is in
1882 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1883 instead of XmDESTROY and then destroy it ourself after having run the
1884 callback.
1886 do_call (widget, closure, no_selection);
1887 XtDestroyWidget (widget);
1890 static void
1891 xm_pull_down_callback (widget, closure, call_data)
1892 Widget widget;
1893 XtPointer closure;
1894 XtPointer call_data;
1896 Widget parent = XtParent (widget);
1898 if (XmIsRowColumn (parent))
1900 unsigned char type = 0xff;
1901 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1902 if (type == XmMENU_BAR)
1903 do_call (widget, closure, pre_activate);
1908 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1909 CLOSURE is a pointer to the widget_instance of the shell, CALL_DATA
1910 is always null under LessTif.
1912 2000-01-23: This callback is called for each cascade button in
1913 a menu, whether or not its submenu is visible. */
1915 static void
1916 xm_pop_down_callback (widget, closure, call_data)
1917 Widget widget;
1918 XtPointer closure;
1919 XtPointer call_data;
1921 widget_instance *instance = (widget_instance *) closure;
1923 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1924 || (XtParent (widget) == instance->parent))
1925 do_call (widget, closure, post_activate);
1928 static void
1929 xm_unmap_callback (widget, closure, call_data)
1930 Widget widget;
1931 XtPointer closure;
1932 XtPointer call_data;
1934 widget_instance *instance = (widget_instance *) closure;
1935 if (!instance->pop_up_p)
1936 do_call (widget, closure, post_activate);
1940 /* set the keyboard focus */
1941 void
1942 xm_set_keyboard_focus (parent, w)
1943 Widget parent;
1944 Widget w;
1946 XmProcessTraversal (w, 0);
1947 XtSetKeyboardFocus (parent, w);
1950 /* Motif hack to set the main window areas. */
1951 void
1952 xm_set_main_areas (parent, menubar, work_area)
1953 Widget parent;
1954 Widget menubar;
1955 Widget work_area;
1957 XmMainWindowSetAreas (parent,
1958 menubar, /* menubar (maybe 0) */
1959 0, /* command area (psheets) */
1960 0, /* horizontal scroll */
1961 0, /* vertical scroll */
1962 work_area); /* work area */
1965 /* Motif hack to control resizing on the menubar. */
1966 void
1967 xm_manage_resizing (w, flag)
1968 Widget w;
1969 Boolean flag;
1971 XtVaSetValues (w, XtNallowShellResize, flag, NULL);