Merge branch 'master' into comment-cache
[emacs.git] / lwlib / lwlib-Xm.c
blob6e1e0d6921614d157ca0fbe2dbbf668bacdf38f6
1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2017 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
11 any later version.
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <setjmp.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 <lisp.h>
36 #include "lwlib-Xm.h"
37 #include "lwlib-utils.h"
39 #include <Xm/BulletinB.h>
40 #include <Xm/CascadeB.h>
41 #include <Xm/CascadeBG.h>
42 #include <Xm/DrawingA.h>
43 #include <Xm/FileSB.h>
44 #include <Xm/Label.h>
45 #include <Xm/List.h>
46 #include <Xm/MainW.h>
47 #include <Xm/MenuShell.h>
48 #include <Xm/MessageB.h>
49 #include <Xm/PanedW.h>
50 #include <Xm/PushB.h>
51 #include <Xm/PushBG.h>
52 #include <Xm/ArrowB.h>
53 #include <Xm/SelectioB.h>
54 #include <Xm/Text.h>
55 #include <Xm/TextF.h>
56 #include <Xm/ToggleB.h>
57 #include <Xm/ToggleBG.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/ScrolledW.h>
60 #include <Xm/Separator.h>
61 #include <Xm/DialogS.h>
62 #include <Xm/Form.h>
64 enum do_call_type { pre_activate, selection, no_selection, post_activate };
67 \f/* Structures to keep destroyed instances */
68 typedef struct _destroyed_instance
70 char* name;
71 char* type;
72 Widget widget;
73 Widget parent;
74 Boolean pop_up_p;
75 struct _destroyed_instance* next;
76 } destroyed_instance;
78 static destroyed_instance *make_destroyed_instance (char *, char *,
79 Widget, Widget,
80 Boolean);
81 static void free_destroyed_instance (destroyed_instance*);
82 Widget first_child (Widget);
83 static XmString resource_motif_string (Widget, char *);
84 static void destroy_all_children (Widget, int);
85 static void xm_update_label (widget_instance *, Widget, widget_value *);
86 static void xm_update_list (widget_instance *, Widget, widget_value *);
87 static void xm_update_pushbutton (widget_instance *, Widget,
88 widget_value *);
89 static void xm_update_cascadebutton (widget_instance *, Widget,
90 widget_value *);
91 static void xm_update_toggle (widget_instance *, Widget, widget_value *);
92 static void xm_update_radiobox (widget_instance *, Widget, widget_value *);
93 static void make_menu_in_widget (widget_instance *, Widget,
94 widget_value *, int);
95 static void update_one_menu_entry (widget_instance *, Widget,
96 widget_value *, Boolean);
97 static void xm_update_menu (widget_instance *, Widget, widget_value *,
98 Boolean);
99 static void xm_update_text (widget_instance *, Widget, widget_value *);
100 static void xm_update_text_field (widget_instance *, Widget,
101 widget_value *);
102 static void activate_button (Widget, XtPointer, XtPointer);
103 static Widget make_dialog (char *, Widget, Boolean, char *, char *,
104 Boolean, Boolean, Boolean, int, int);
105 static destroyed_instance* find_matching_instance (widget_instance*);
106 static void mark_dead_instance_destroyed (Widget, XtPointer, XtPointer);
107 static void recenter_widget (Widget);
108 static Widget recycle_instance (destroyed_instance*);
109 static Widget make_menubar (widget_instance*);
110 static void remove_grabs (Widget, XtPointer, XtPointer);
111 static Widget make_popup_menu (widget_instance*);
112 static Widget make_main (widget_instance*);
113 static void set_min_dialog_size (Widget);
114 static void do_call (Widget, XtPointer, enum do_call_type);
115 static void xm_generic_callback (Widget, XtPointer, XtPointer);
116 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
117 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
118 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
119 static void xm_internal_update_other_instances (Widget, XtPointer,
120 XtPointer);
121 static void xm_arm_callback (Widget, XtPointer, XtPointer);
123 #if 0
124 void xm_update_one_widget (widget_instance *, Widget, widget_value *,
125 Boolean);
126 void xm_pop_instance (widget_instance*, Boolean);
127 void xm_manage_resizing (Widget, Boolean);
128 #endif
131 #if 0
133 /* Print the complete X resource name of widget WIDGET to stderr.
134 This is sometimes handy to have available. */
136 void
137 x_print_complete_resource_name (Widget widget)
139 int i;
140 String names[100];
142 for (i = 0; i < 100 && widget != NULL; ++i)
144 names[i] = XtName (widget);
145 widget = XtParent (widget);
148 for (--i; i >= 1; --i)
149 fprintf (stderr, "%s.", names[i]);
150 fprintf (stderr, "%s\n", names[0]);
153 #endif /* 0 */
156 static destroyed_instance *all_destroyed_instances = NULL;
158 static destroyed_instance*
159 make_destroyed_instance (char* name,
160 char* type,
161 Widget widget,
162 Widget parent,
163 Boolean pop_up_p)
165 destroyed_instance* instance =
166 (destroyed_instance*) xmalloc (sizeof (destroyed_instance));
167 instance->name = xstrdup (name);
168 instance->type = xstrdup (type);
169 instance->widget = widget;
170 instance->parent = parent;
171 instance->pop_up_p = pop_up_p;
172 instance->next = NULL;
173 return instance;
176 static void
177 free_destroyed_instance (destroyed_instance* instance)
179 xfree (instance->name);
180 xfree (instance->type);
181 xfree (instance);
184 \f/* motif utility functions */
185 Widget
186 first_child (Widget widget)
188 return ((CompositeWidget)widget)->composite.children [0];
191 Boolean
192 lw_motif_widget_p (Widget widget)
194 return
195 XtClass (widget) == xmDialogShellWidgetClass
196 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
199 static XmString
200 resource_motif_string (Widget widget,
201 char* name)
203 XtResource resource;
204 XmString result = 0;
206 resource.resource_name = name;
207 resource.resource_class = XmCXmString;
208 resource.resource_type = XmRXmString;
209 resource.resource_size = sizeof (XmString);
210 resource.resource_offset = 0;
211 resource.default_type = XtRImmediate;
212 resource.default_addr = 0;
214 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
215 "DialogString", &resource, 1, NULL, 0);
216 return result;
219 /* Destroy all of the children of WIDGET
220 starting with number FIRST_CHILD_TO_DESTROY. */
222 static void
223 destroy_all_children (Widget widget,
224 int first_child_to_destroy)
226 Widget* children;
227 unsigned int number;
228 int i;
230 children = XtCompositeChildren (widget, &number);
231 if (children)
233 XtUnmanageChildren (children + first_child_to_destroy,
234 number - first_child_to_destroy);
236 /* Unmanage all children and destroy them. They will only be
237 really destroyed when we get out of DispatchEvent. */
238 for (i = first_child_to_destroy; i < number; i++)
240 Arg al[2];
241 Widget submenu = 0;
242 /* Cascade buttons have submenus,and these submenus
243 need to be freed. But they are not included in
244 XtCompositeChildren. So get it out of the cascade button
245 and free it. If this child is not a cascade button,
246 then submenu should remain unchanged. */
247 XtSetArg (al[0], XmNsubMenuId, &submenu);
248 XtGetValues (children[i], al, 1);
249 if (submenu)
251 destroy_all_children (submenu, 0);
252 XtDestroyWidget (submenu);
254 XtDestroyWidget (children[i]);
257 XtFree ((char *) children);
263 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
264 menu. CLIENT_DATA contains a pointer to the widget_value
265 corresponding to widget W. CALL_DATA contains a
266 XmPushButtonCallbackStruct containing the reason why the callback
267 is called. */
269 static void
270 xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
272 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
273 widget_value *wv = (widget_value *) client_data;
274 widget_instance *instance;
276 /* Get the id of the menu bar or popup menu this widget is in. */
277 while (w != NULL)
279 if (XmIsRowColumn (w))
281 unsigned char type = 0xff;
283 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
284 if (type == XmMENU_BAR || type == XmMENU_POPUP)
285 break;
288 w = XtParent (w);
291 if (w != NULL)
293 instance = lw_get_widget_instance (w);
294 if (instance && instance->info->highlight_cb)
296 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
297 instance->info->highlight_cb (w, instance->info->id, call_data);
304 /* Update the label of widget WIDGET. WIDGET must be a Label widget
305 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
306 the value to update.
308 Menus:
310 Emacs fills VAL->name with the text to display in the menu, and
311 sets VAL->value to null. Function make_menu_in_widget creates
312 widgets with VAL->name as resource name. This works because the
313 Label widget uses its resource name for display if no
314 XmNlabelString is set.
316 Dialogs:
318 VAL->name is again set to the resource name, but VAL->value is
319 not null, and contains the label string to display. */
321 static void
322 xm_update_label (widget_instance* instance,
323 Widget widget,
324 widget_value* val)
326 XmString res_string = 0;
327 XmString built_string = 0;
328 XmString key_string = 0;
329 Arg al [256];
330 int ac;
332 ac = 0;
334 if (val->value)
336 /* A label string is specified, i.e. we are in a dialog. First
337 see if it is overridden by something from the resource file. */
338 res_string = resource_motif_string (widget, val->value);
340 if (res_string)
342 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
344 else
346 built_string =
347 XmStringCreateLocalized (val->value);
348 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
351 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
354 if (val->key)
356 key_string = XmStringCreateLocalized (val->key);
357 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
360 if (ac)
361 XtSetValues (widget, al, ac);
363 if (built_string)
364 XmStringFree (built_string);
366 if (key_string)
367 XmStringFree (key_string);
370 \f/* update of list */
371 static void
372 xm_update_list (widget_instance* instance,
373 Widget widget,
374 widget_value* val)
376 widget_value* cur;
377 int i;
378 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
379 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
380 instance);
381 for (cur = val->contents, i = 0; cur; cur = cur->next)
382 if (cur->value)
384 XmString xmstr = XmStringCreateLocalized (cur->value);
385 i += 1;
386 XmListAddItem (widget, xmstr, 0);
387 if (cur->selected)
388 XmListSelectPos (widget, i, False);
389 XmStringFree (xmstr);
393 \f/* update of buttons */
394 static void
395 xm_update_pushbutton (widget_instance* instance,
396 Widget widget,
397 widget_value* val)
399 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
400 XtRemoveAllCallbacks (widget, XmNactivateCallback);
401 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
404 static void
405 xm_update_cascadebutton (widget_instance* instance,
406 Widget widget,
407 widget_value* val)
409 /* Should also rebuild the menu by calling ...update_menu... */
410 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
411 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
412 instance);
415 \f/* update toggle and radiobox */
416 static void
417 xm_update_toggle (widget_instance* instance,
418 Widget widget,
419 widget_value* val)
421 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
422 XtAddCallback (widget, XmNvalueChangedCallback,
423 xm_generic_callback, instance);
424 XtVaSetValues (widget, XmNset, val->selected,
425 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
428 static void
429 xm_update_radiobox (widget_instance* instance,
430 Widget widget,
431 widget_value* val)
434 Widget toggle;
435 widget_value* cur;
437 /* update the callback */
438 XtRemoveAllCallbacks (widget, XmNentryCallback);
439 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
441 /* first update all the toggles */
442 /* Energize kernel interface is currently bad. It sets the selected widget
443 with the selected flag but returns it by its name. So we currently
444 have to support both setting the selection with the selected slot
445 of val contents and setting it with the "value" slot of val. The latter
446 has a higher priority. This to be removed when the kernel is fixed. */
447 for (cur = val->contents; cur; cur = cur->next)
449 toggle = XtNameToWidget (widget, cur->value);
450 if (toggle)
452 XtSetSensitive (toggle, cur->enabled);
453 if (!val->value && cur->selected)
454 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
455 if (val->value && strcmp (val->value, cur->value))
456 XtVaSetValues (toggle, XmNset, False, NULL);
460 /* The selected was specified by the value slot */
461 if (val->value)
463 toggle = XtNameToWidget (widget, val->value);
464 if (toggle)
465 XtVaSetValues (toggle, XmNset, True, NULL);
470 /* update a popup menu, pulldown menu or a menubar */
472 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
474 static void
475 make_menu_in_widget (widget_instance* instance,
476 Widget widget,
477 widget_value* val,
478 int keep_first_children)
480 Widget* children = 0;
481 int num_children;
482 int child_index;
483 widget_value* cur;
484 Widget button = 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 /* Disable drag and drop for labels in menu bar. */
495 static char overrideTrans[] = "<Btn2Down>: Noop()";
496 XtTranslations override = XtParseTranslationTable (overrideTrans);
498 old_children = XtCompositeChildren (widget, &old_num_children);
500 /* Allocate the children array */
501 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
503 children = (Widget*)(void*)XtMalloc (num_children * sizeof (Widget));
505 /* WIDGET should be a RowColumn. */
506 if (!XmIsRowColumn (widget))
507 abort ();
509 /* Determine whether WIDGET is a menu bar. */
510 type = -1;
511 XtSetArg (al[0], XmNrowColumnType, &type);
512 XtGetValues (widget, al, 1);
513 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
514 abort ();
515 menubar_p = type == XmMENU_BAR;
517 /* Add a callback to popups and pulldowns that is called when
518 it is made invisible again. */
519 if (!menubar_p)
520 XtAddCallback (XtParent (widget), XmNpopdownCallback,
521 xm_pop_down_callback, (XtPointer)instance);
523 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
524 for (child_index = 0, cur = val; child_index < keep_first_children;
525 child_index++, cur = cur->next)
526 children[child_index] = old_children[child_index];
528 /* Check that those are all we have
529 (the caller should have deleted the rest). */
530 if (old_num_children != keep_first_children)
531 abort ();
533 /* Create the rest. */
534 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
536 enum menu_separator separator;
538 ac = 0;
539 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
540 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
541 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
543 if (instance->pop_up_p && !cur->contents && !cur->call_data
544 && !lw_separator_p (cur->name, &separator, 1))
546 ac = 0;
547 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
548 button = XmCreateLabel (widget, cur->name, al, ac);
550 else if (lw_separator_p (cur->name, &separator, 1))
552 ac = 0;
553 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
554 button = XmCreateSeparator (widget, cur->name, al, ac);
556 else if (!cur->contents)
558 if (menubar_p)
559 button = XmCreateCascadeButton (widget, cur->name, al, ac);
560 else if (!cur->call_data)
561 button = XmCreateLabel (widget, cur->name, al, ac);
562 else if (cur->button_type == BUTTON_TYPE_TOGGLE
563 || cur->button_type == BUTTON_TYPE_RADIO)
565 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
566 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
567 XtSetArg (al[ac], XmNindicatorType,
568 (cur->button_type == BUTTON_TYPE_TOGGLE
569 ? XmN_OF_MANY : XmONE_OF_MANY));
570 ++ac;
571 button = XmCreateToggleButton (widget, cur->name, al, ac);
572 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
573 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
575 else
577 button = XmCreatePushButton (widget, cur->name, al, ac);
578 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
579 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
582 xm_update_label (instance, button, cur);
584 /* Add a callback that is called when the button is
585 selected. Toggle buttons don't support
586 XmNactivateCallback, we use XmNvalueChangedCallback in
587 that case. Don't add a callback to a simple label. */
588 if (cur->button_type)
589 xm_update_toggle (instance, button, cur);
590 else if (cur->call_data)
591 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
592 (XtPointer)instance);
594 else
596 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
598 make_menu_in_widget (instance, menu, cur->contents, 0);
599 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
600 button = XmCreateCascadeButton (widget, cur->name, al, ac);
602 xm_update_label (instance, button, cur);
604 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
605 (XtPointer)instance);
606 XtOverrideTranslations (button, override);
610 children[child_index] = button;
613 /* Last entry is the help button. The original comment read "Has to
614 be done after managing the buttons otherwise the menubar is only
615 4 pixels high." This is no longer true, and to make
616 XmNmenuHelpWidget work, we need to set it before managing the
617 children.. --gerd. */
618 if (button)
619 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
621 if (num_children)
622 XtManageChildren (children, num_children);
624 XtFree ((char *) children);
625 if (old_children)
626 XtFree ((char *) old_children);
629 static void
630 update_one_menu_entry (widget_instance* instance,
631 Widget widget,
632 widget_value* val,
633 Boolean deep_p)
635 Arg al [256];
636 int ac;
637 Widget menu;
638 widget_value* contents;
640 if (val->this_one_change == NO_CHANGE)
641 return;
643 /* update the sensitivity and userdata */
644 /* Common to all widget types */
645 XtSetSensitive (widget, val->enabled);
646 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
648 /* update the menu button as a label. */
649 if (val->this_one_change >= VISIBLE_CHANGE)
651 xm_update_label (instance, widget, val);
652 if (val->button_type)
653 xm_update_toggle (instance, widget, val);
656 /* update the pulldown/pullaside as needed */
657 ac = 0;
658 menu = NULL;
659 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
660 XtGetValues (widget, al, ac);
662 contents = val->contents;
664 if (!menu)
666 if (contents)
668 unsigned int old_num_children, i;
669 Widget parent;
670 Widget *widget_list;
672 parent = XtParent (widget);
673 widget_list = XtCompositeChildren (parent, &old_num_children);
675 /* Find the widget position within the parent's widget list. */
676 for (i = 0; i < old_num_children; i++)
677 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
678 break;
679 if (i == old_num_children)
680 abort ();
681 if (XmIsCascadeButton (widget_list[i]))
683 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
684 make_menu_in_widget (instance, menu, contents, 0);
685 ac = 0;
686 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
687 XtSetValues (widget, al, ac);
689 else
691 Widget button;
693 /* The current menuitem is a XmPushButtonGadget, it
694 needs to be replaced by a CascadeButtonGadget */
695 XtDestroyWidget (widget_list[i]);
696 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
697 make_menu_in_widget (instance, menu, contents, 0);
698 ac = 0;
699 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
700 /* Non-zero values don't work reliably in
701 conjunction with Emacs' event loop */
702 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
703 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
704 /* Tell Motif to put it in the right place */
705 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
706 #endif
707 button = XmCreateCascadeButton (parent, val->name, al, ac);
708 xm_update_label (instance, button, val);
710 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
711 (XtPointer)instance);
712 XtManageChild (button);
715 if (widget_list)
716 XtFree ((char*) widget_list);
719 else if (!contents)
721 ac = 0;
722 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
723 XtSetValues (widget, al, ac);
724 XtDestroyWidget (menu);
726 else if (deep_p && contents->change != NO_CHANGE)
727 xm_update_menu (instance, menu, val, 1);
730 static void
731 xm_update_menu (widget_instance* instance,
732 Widget widget,
733 widget_value* val,
734 Boolean deep_p)
736 Widget* children;
737 unsigned int num_children;
738 int num_children_to_keep = 0;
739 int i;
740 widget_value* cur;
742 children = XtCompositeChildren (widget, &num_children);
744 /* Widget is a RowColumn widget whose contents have to be updated
745 * to reflect the list of items in val->contents */
747 /* See how many buttons we can keep, and how many we
748 must completely replace. */
749 if (val->contents == 0)
750 num_children_to_keep = 0;
751 else if (val->contents->change == STRUCTURAL_CHANGE)
753 if (children)
755 for (i = 0, cur = val->contents;
756 (i < num_children
757 && cur); /* how else to ditch unwanted children ?? - mgd */
758 i++, cur = cur->next)
760 if (cur->this_one_change == STRUCTURAL_CHANGE)
761 break;
764 num_children_to_keep = i;
767 else
768 num_children_to_keep = num_children;
770 /* Update all the buttons of the RowColumn, in order,
771 except for those we are going to replace entirely. */
772 if (children)
774 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
776 if (!cur)
778 num_children_to_keep = i;
779 break;
781 if (children [i]->core.being_destroyed
782 || strcmp (XtName (children [i]), cur->name))
783 continue;
784 update_one_menu_entry (instance, children [i], cur, deep_p);
785 cur = cur->next;
789 /* Now replace from scratch all the buttons after the last
790 place that the top-level structure changed. */
791 if (val->contents && val->contents->change == STRUCTURAL_CHANGE)
793 destroy_all_children (widget, num_children_to_keep);
794 make_menu_in_widget (instance, widget, val->contents,
795 num_children_to_keep);
798 XtFree ((char *) children);
802 /* update text widgets */
804 static void
805 xm_update_text (widget_instance* instance,
806 Widget widget,
807 widget_value* val)
809 XmTextSetString (widget, val->value ? val->value : "");
810 XtRemoveAllCallbacks (widget, XmNactivateCallback);
811 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
812 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
813 XtAddCallback (widget, XmNvalueChangedCallback,
814 xm_internal_update_other_instances, instance);
817 static void
818 xm_update_text_field (widget_instance* instance,
819 Widget widget,
820 widget_value* val)
822 XmTextFieldSetString (widget, val->value ? val->value : "");
823 XtRemoveAllCallbacks (widget, XmNactivateCallback);
824 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
825 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
826 XtAddCallback (widget, XmNvalueChangedCallback,
827 xm_internal_update_other_instances, instance);
831 /* update a motif widget */
833 void
834 xm_update_one_widget (widget_instance* instance,
835 Widget widget,
836 widget_value* val,
837 Boolean deep_p)
839 WidgetClass class;
841 /* Mark as not edited */
842 val->edited = False;
844 /* Common to all widget types */
845 XtSetSensitive (widget, val->enabled);
846 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
848 /* Common to all label like widgets */
849 if (XtIsSubclass (widget, xmLabelWidgetClass))
850 xm_update_label (instance, widget, val);
852 class = XtClass (widget);
853 /* Class specific things */
854 if (class == xmPushButtonWidgetClass ||
855 class == xmArrowButtonWidgetClass)
857 xm_update_pushbutton (instance, widget, val);
859 else if (class == xmCascadeButtonWidgetClass)
861 xm_update_cascadebutton (instance, widget, val);
863 else if (class == xmToggleButtonWidgetClass
864 || class == xmToggleButtonGadgetClass)
866 xm_update_toggle (instance, widget, val);
868 else if (class == xmRowColumnWidgetClass)
870 Boolean radiobox = 0;
871 int ac = 0;
872 Arg al [1];
874 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
875 XtGetValues (widget, al, ac);
877 if (radiobox)
878 xm_update_radiobox (instance, widget, val);
879 else
880 xm_update_menu (instance, widget, val, deep_p);
882 else if (class == xmTextWidgetClass)
884 xm_update_text (instance, widget, val);
886 else if (class == xmTextFieldWidgetClass)
888 xm_update_text_field (instance, widget, val);
890 else if (class == xmListWidgetClass)
892 xm_update_list (instance, widget, val);
896 \f/* getting the value back */
897 void
898 xm_update_one_value (widget_instance* instance,
899 Widget widget,
900 widget_value* val)
902 WidgetClass class = XtClass (widget);
903 widget_value *old_wv;
905 /* copy the call_data slot into the "return" widget_value */
906 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
907 if (!strcmp (val->name, old_wv->name))
909 val->call_data = old_wv->call_data;
910 break;
913 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
915 XtVaGetValues (widget, XmNset, &val->selected, NULL);
916 val->edited = True;
918 else if (class == xmTextWidgetClass)
920 xfree (val->value);
921 val->value = XmTextGetString (widget);
922 val->edited = True;
924 else if (class == xmTextFieldWidgetClass)
926 xfree (val->value);
927 val->value = XmTextFieldGetString (widget);
928 val->edited = True;
930 else if (class == xmRowColumnWidgetClass)
932 Boolean radiobox = 0;
933 int ac = 0;
934 Arg al [1];
936 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
937 XtGetValues (widget, al, ac);
939 if (radiobox)
941 CompositeWidget radio = (CompositeWidget)widget;
942 int i;
943 for (i = 0; i < radio->composite.num_children; i++)
945 int set = False;
946 Widget toggle = radio->composite.children [i];
948 XtVaGetValues (toggle, XmNset, &set, NULL);
949 if (set)
950 dupstring (&val->value, XtName (toggle));
952 val->edited = True;
955 else if (class == xmListWidgetClass)
957 int pos_cnt;
958 int* pos_list;
959 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
961 int i;
962 widget_value* cur;
963 for (cur = val->contents, i = 0; cur; cur = cur->next)
964 if (cur->value)
966 int j;
967 cur->selected = False;
968 i += 1;
969 for (j = 0; j < pos_cnt; j++)
970 if (pos_list [j] == i)
972 cur->selected = True;
973 val->value = xstrdup (cur->name);
976 val->edited = 1;
977 XtFree ((char *) pos_list);
983 /* This function is for activating a button from a program. It's wrong because
984 we pass a NULL argument in the call_data which is not Motif compatible.
985 This is used from the XmNdefaultAction callback of the List widgets to
986 have a double-click put down a dialog box like the button would do.
987 I could not find a way to do that with accelerators.
989 static void
990 activate_button (Widget widget,
991 XtPointer closure,
992 XtPointer call_data)
994 Widget button = (Widget)closure;
995 XtCallCallbacks (button, XmNactivateCallback, NULL);
998 /* creation functions */
1000 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1001 static void
1002 dialog_key_cb (Widget widget,
1003 XtPointer closure,
1004 XEvent *event,
1005 Boolean *continue_to_dispatch)
1007 KeySym sym = 0;
1008 Modifiers modif_ret;
1010 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1011 &modif_ret, &sym);
1013 if (sym == osfXK_Cancel)
1015 Widget w = *((Widget *) closure);
1017 while (w && ! XtIsShell (w))
1018 w = XtParent (w);
1020 if (XtIsShell (w)) XtPopdown (w);
1023 *continue_to_dispatch = TRUE;
1026 /* dialogs */
1027 static Widget
1028 make_dialog (char* name,
1029 Widget parent,
1030 Boolean pop_up_p,
1031 char* shell_title,
1032 char* icon_name,
1033 Boolean text_input_slot,
1034 Boolean radio_box,
1035 Boolean list,
1036 int left_buttons,
1037 int right_buttons)
1039 Widget result;
1040 Widget form;
1041 Widget row;
1042 Widget icon;
1043 Widget icon_separator;
1044 Widget message_label;
1045 Widget value = 0;
1046 Widget separator;
1047 Widget button = 0;
1048 Widget children [16]; /* for the final XtManageChildren */
1049 int n_children;
1050 Arg al[64]; /* Arg List */
1051 int ac; /* Arg Count */
1052 int i;
1054 if (pop_up_p)
1056 ac = 0;
1057 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1058 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1059 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1060 result = XmCreateDialogShell (parent, "dialog", al, ac);
1061 ac = 0;
1062 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1063 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1064 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1065 form = XmCreateForm (result, shell_title, al, ac);
1067 else
1069 ac = 0;
1070 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1071 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1072 form = XmCreateForm (parent, shell_title, al, ac);
1073 result = form;
1076 n_children = left_buttons + right_buttons + 1;
1077 ac = 0;
1078 XtSetArg(al[ac], XmNpacking, n_children == 3?
1079 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1080 XtSetArg(al[ac], XmNorientation, n_children == 3?
1081 XmVERTICAL: XmHORIZONTAL); ac++;
1082 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1083 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1084 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1085 XtSetArg(al[ac], XmNspacing, 13); ac++;
1086 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1087 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1088 XtSetArg(al[ac], XmNisAligned, True); ac++;
1089 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1090 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1091 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1092 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1093 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1094 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1095 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1096 row = XmCreateRowColumn (form, "row", al, ac);
1098 n_children = 0;
1099 for (i = 0; i < left_buttons; i++)
1101 char button_name [16];
1102 sprintf (button_name, "button%d", i + 1);
1103 ac = 0;
1104 if (i == 0)
1106 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1107 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1109 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1110 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1111 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1112 XtAddEventHandler (children [n_children],
1113 KeyPressMask, False, dialog_key_cb, result);
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 XtAddEventHandler (children [n_children],
1141 KeyPressMask, False, dialog_key_cb, result);
1143 if (! button) button = children [n_children];
1144 n_children++;
1147 XtManageChildren (children, n_children);
1149 ac = 0;
1150 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1151 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1152 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1153 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1154 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1155 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1156 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1157 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1158 separator = XmCreateSeparator (form, "", al, ac);
1160 ac = 0;
1161 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1162 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1163 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1164 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1165 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1166 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1167 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1168 icon = XmCreateLabel (form, icon_name, al, ac);
1170 ac = 0;
1171 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1172 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1173 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1174 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1175 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1176 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1177 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1178 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1179 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1180 icon_separator = XmCreateLabel (form, "", al, ac);
1182 if (text_input_slot)
1184 ac = 0;
1185 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1186 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1187 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1188 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1189 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1190 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1191 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1192 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1193 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1194 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1195 value = XmCreateTextField (form, "value", al, ac);
1197 else if (radio_box)
1199 Widget radio_butt;
1200 ac = 0;
1201 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1202 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1203 XtSetArg(al[ac], XmNspacing, 13); ac++;
1204 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1205 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1206 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1207 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1208 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1209 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1210 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1211 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1212 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1213 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1214 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1215 ac = 0;
1216 i = 0;
1217 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1218 children [i++] = radio_butt;
1219 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1220 children [i++] = radio_butt;
1221 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1222 children [i++] = radio_butt;
1223 XtManageChildren (children, i);
1225 else if (list)
1227 ac = 0;
1228 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1229 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1230 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1231 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1232 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1233 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1234 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1235 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1236 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1237 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1238 value = XmCreateScrolledList (form, "list", al, ac);
1240 /* this is the easiest way I found to have the dble click in the
1241 list activate the default button */
1242 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1245 ac = 0;
1246 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1247 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1248 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1249 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1250 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1251 XtSetArg(al[ac], XmNbottomWidget,
1252 text_input_slot || radio_box || list ? value : separator); ac++;
1253 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1254 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1255 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1256 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1257 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1258 message_label = XmCreateLabel (form, "message", al, ac);
1260 if (list)
1261 XtManageChild (value);
1263 i = 0;
1264 children [i] = row; i++;
1265 children [i] = separator; i++;
1266 if (text_input_slot || radio_box)
1268 children [i] = value; i++;
1270 children [i] = message_label; i++;
1271 children [i] = icon; i++;
1272 children [i] = icon_separator; i++;
1273 XtManageChildren (children, i);
1275 if (text_input_slot || list)
1277 XtInstallAccelerators (value, button);
1278 XtSetKeyboardFocus (result, value);
1280 else
1282 XtInstallAccelerators (form, button);
1283 XtSetKeyboardFocus (result, button);
1286 return result;
1289 static destroyed_instance*
1290 find_matching_instance (widget_instance* instance)
1292 destroyed_instance* cur;
1293 destroyed_instance* prev;
1294 char* type = instance->info->type;
1295 char* name = instance->info->name;
1297 for (prev = NULL, cur = all_destroyed_instances;
1298 cur;
1299 prev = cur, cur = cur->next)
1301 if (!strcmp (cur->name, name)
1302 && !strcmp (cur->type, type)
1303 && cur->parent == instance->parent
1304 && cur->pop_up_p == instance->pop_up_p)
1306 if (prev)
1307 prev->next = cur->next;
1308 else
1309 all_destroyed_instances = cur->next;
1310 return cur;
1312 /* do some cleanup */
1313 else if (!cur->widget)
1315 if (prev)
1316 prev->next = cur->next;
1317 else
1318 all_destroyed_instances = cur->next;
1319 free_destroyed_instance (cur);
1320 cur = prev ? prev : all_destroyed_instances;
1323 return NULL;
1326 static void
1327 mark_dead_instance_destroyed (Widget widget,
1328 XtPointer closure,
1329 XtPointer call_data)
1331 destroyed_instance* instance = (destroyed_instance*)closure;
1332 instance->widget = NULL;
1335 static void
1336 recenter_widget (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 (destroyed_instance* instance)
1374 Widget widget = instance->widget;
1376 /* widget is NULL if the parent was destroyed. */
1377 if (widget)
1379 Widget focus;
1380 Widget separator;
1382 /* Remove the destroy callback as the instance is not in the list
1383 anymore */
1384 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1385 mark_dead_instance_destroyed,
1386 (XtPointer)instance);
1388 /* Give the focus to the initial item */
1389 focus = XtNameToWidget (widget, "*value");
1390 if (!focus)
1391 focus = XtNameToWidget (widget, "*button1");
1392 if (focus)
1393 XtSetKeyboardFocus (widget, focus);
1395 /* shrink the separator label back to their original size */
1396 separator = XtNameToWidget (widget, "*separator_button");
1397 if (separator)
1398 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1400 /* Center the dialog in its parent */
1401 recenter_widget (widget);
1403 free_destroyed_instance (instance);
1404 return widget;
1407 Widget
1408 xm_create_dialog (widget_instance* instance)
1410 char* name = instance->info->type;
1411 Widget parent = instance->parent;
1412 Widget widget;
1413 Boolean pop_up_p = instance->pop_up_p;
1414 char* shell_name = 0;
1415 char* icon_name = 0;
1416 Boolean text_input_slot = False;
1417 Boolean radio_box = False;
1418 Boolean list = False;
1419 int total_buttons;
1420 int left_buttons = 0;
1421 int right_buttons = 1;
1422 destroyed_instance* dead_one;
1424 /* try to find a widget to recycle */
1425 dead_one = find_matching_instance (instance);
1426 if (dead_one)
1428 Widget recycled_widget = recycle_instance (dead_one);
1429 if (recycled_widget)
1430 return recycled_widget;
1433 switch (name [0]){
1434 case 'E': case 'e':
1435 icon_name = "dbox-error";
1436 shell_name = "Error";
1437 break;
1439 case 'I': case 'i':
1440 icon_name = "dbox-info";
1441 shell_name = "Information";
1442 break;
1444 case 'L': case 'l':
1445 list = True;
1446 icon_name = "dbox-question";
1447 shell_name = "Prompt";
1448 break;
1450 case 'P': case 'p':
1451 text_input_slot = True;
1452 icon_name = "dbox-question";
1453 shell_name = "Prompt";
1454 break;
1456 case 'Q': case 'q':
1457 icon_name = "dbox-question";
1458 shell_name = "Question";
1459 break;
1462 total_buttons = name [1] - '0';
1464 if (name [3] == 'T' || name [3] == 't')
1466 text_input_slot = False;
1467 radio_box = True;
1469 else if (name [3])
1470 right_buttons = name [4] - '0';
1472 left_buttons = total_buttons - right_buttons;
1474 widget = make_dialog (name, parent, pop_up_p,
1475 shell_name, icon_name, text_input_slot, radio_box,
1476 list, left_buttons, right_buttons);
1478 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1479 (XtPointer) instance);
1481 return widget;
1484 /* Create a menu bar. We turn off the f10 key
1485 because we have not yet managed to make it work right in Motif. */
1487 static Widget
1488 make_menubar (widget_instance* instance)
1490 Arg al[3];
1491 int ac;
1493 ac = 0;
1494 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1495 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1498 static void
1499 remove_grabs (Widget shell,
1500 XtPointer closure,
1501 XtPointer call_data)
1503 Widget menu = (Widget) closure;
1504 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1507 static Widget
1508 make_popup_menu (widget_instance* instance)
1510 Widget parent = instance->parent;
1511 Window parent_window = parent->core.window;
1512 Widget result;
1514 /* sets the parent window to 0 to fool Motif into not generating a grab */
1515 parent->core.window = 0;
1516 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1517 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1518 (XtPointer)result);
1519 parent->core.window = parent_window;
1520 return result;
1523 static Widget
1524 make_main (widget_instance* instance)
1526 Widget parent = instance->parent;
1527 Widget result;
1528 Arg al[2];
1529 int ac;
1531 ac = 0;
1532 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1533 XtSetArg (al[ac], XmNspacing, 0); ac++;
1534 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1535 return result;
1538 \f/* Table of functions to create widgets */
1540 #ifdef ENERGIZE
1542 /* interface with the XDesigner generated functions */
1543 typedef Widget (*widget_maker) (Widget);
1544 extern Widget create_project_p_sheet (Widget parent);
1545 extern Widget create_debugger_p_sheet (Widget parent);
1546 extern Widget create_breaklist_p_sheet (Widget parent);
1547 extern Widget create_le_browser_p_sheet (Widget parent);
1548 extern Widget create_class_browser_p_sheet (Widget parent);
1549 extern Widget create_call_browser_p_sheet (Widget parent);
1550 extern Widget create_build_dialog (Widget parent);
1551 extern Widget create_editmode_dialog (Widget parent);
1552 extern Widget create_search_dialog (Widget parent);
1553 extern Widget create_project_display_dialog (Widget parent);
1555 static Widget
1556 make_one (widget_instance* instance, widget_maker fn)
1558 Widget result;
1559 Arg al [64];
1560 int ac = 0;
1562 if (instance->pop_up_p)
1564 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1565 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1566 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1567 (XtPointer) instance);
1568 (*fn) (result);
1570 else
1572 result = (*fn) (instance->parent);
1573 XtRealizeWidget (result);
1575 return result;
1578 static Widget
1579 make_project_p_sheet (widget_instance* instance)
1581 return make_one (instance, create_project_p_sheet);
1584 static Widget
1585 make_debugger_p_sheet (widget_instance* instance)
1587 return make_one (instance, create_debugger_p_sheet);
1590 static Widget
1591 make_breaklist_p_sheet (widget_instance* instance)
1593 return make_one (instance, create_breaklist_p_sheet);
1596 static Widget
1597 make_le_browser_p_sheet (widget_instance* instance)
1599 return make_one (instance, create_le_browser_p_sheet);
1602 static Widget
1603 make_class_browser_p_sheet (widget_instance* instance)
1605 return make_one (instance, create_class_browser_p_sheet);
1608 static Widget
1609 make_call_browser_p_sheet (widget_instance* instance)
1611 return make_one (instance, create_call_browser_p_sheet);
1614 static Widget
1615 make_build_dialog (widget_instance* instance)
1617 return make_one (instance, create_build_dialog);
1620 static Widget
1621 make_editmode_dialog (widget_instance* instance)
1623 return make_one (instance, create_editmode_dialog);
1626 static Widget
1627 make_search_dialog (widget_instance* instance)
1629 return make_one (instance, create_search_dialog);
1632 static Widget
1633 make_project_display_dialog (widget_instance* instance)
1635 return make_one (instance, create_project_display_dialog);
1638 #endif /* ENERGIZE */
1640 widget_creation_entry
1641 xm_creation_table [] =
1643 {"menubar", make_menubar},
1644 {"popup", make_popup_menu},
1645 {"main", make_main},
1646 #ifdef ENERGIZE
1647 {"project_p_sheet", make_project_p_sheet},
1648 {"debugger_p_sheet", make_debugger_p_sheet},
1649 {"breaklist_psheet", make_breaklist_p_sheet},
1650 {"leb_psheet", make_le_browser_p_sheet},
1651 {"class_browser_psheet", make_class_browser_p_sheet},
1652 {"ctree_browser_psheet", make_call_browser_p_sheet},
1653 {"build", make_build_dialog},
1654 {"editmode", make_editmode_dialog},
1655 {"search", make_search_dialog},
1656 {"project_display", make_project_display_dialog},
1657 #endif /* ENERGIZE */
1658 {NULL, NULL}
1661 \f/* Destruction of instances */
1662 void
1663 xm_destroy_instance ( widget_instance* instance)
1665 Widget widget = instance->widget;
1666 /* recycle the dialog boxes */
1667 /* Disable the recycling until we can find a way to have the dialog box
1668 get reasonable layout after we modify its contents. */
1669 if (0
1670 && XtClass (widget) == xmDialogShellWidgetClass)
1672 destroyed_instance* dead_instance =
1673 make_destroyed_instance (instance->info->name,
1674 instance->info->type,
1675 instance->widget,
1676 instance->parent,
1677 instance->pop_up_p);
1678 dead_instance->next = all_destroyed_instances;
1679 all_destroyed_instances = dead_instance;
1680 XtUnmanageChild (first_child (instance->widget));
1681 XFlush (XtDisplay (instance->widget));
1682 XtAddCallback (instance->parent, XtNdestroyCallback,
1683 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1685 else
1687 /* This might not be necessary now that the nosel is attached to
1688 popdown instead of destroy, but it can't hurt. */
1689 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1690 xm_nosel_callback, (XtPointer)instance);
1691 XtDestroyWidget (instance->widget);
1695 \f/* popup utility */
1696 void
1697 xm_popup_menu (Widget widget, XEvent *event)
1699 XButtonPressedEvent dummy;
1701 if (event == 0)
1703 dummy.type = ButtonPress;
1704 dummy.serial = 0;
1705 dummy.send_event = 0;
1706 dummy.display = XtDisplay (widget);
1707 dummy.window = XtWindow (XtParent (widget));
1708 dummy.time = 0;
1709 dummy.button = 0;
1710 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1711 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1712 &dummy.x, &dummy.y, &dummy.state);
1713 event = (XEvent *) &dummy;
1716 if (event->type == ButtonPress || event->type == ButtonRelease)
1718 /* Setting the menuPost resource only required by Motif 1.1 and
1719 LessTif 0.84 and earlier. With later versions of LessTif,
1720 setting menuPost is unnecessary and may cause problems, so
1721 don't do it. */
1722 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1724 /* This is so totally ridiculous: there's NO WAY to tell Motif
1725 that *any* button can select a menu item. Only one button
1726 can have that honor. */
1728 char *trans = 0;
1729 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1730 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1731 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1732 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1733 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1734 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1736 #endif
1738 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1741 XtManageChild (widget);
1744 static void
1745 set_min_dialog_size (Widget w)
1747 short width;
1748 short height;
1749 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1750 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1753 void
1754 xm_pop_instance (widget_instance* instance, Boolean up)
1756 Widget widget = instance->widget;
1758 if (XtClass (widget) == xmDialogShellWidgetClass)
1760 Widget widget_to_manage = first_child (widget);
1761 if (up)
1763 XtManageChild (widget_to_manage);
1764 set_min_dialog_size (widget);
1765 XtSetKeyboardFocus (instance->parent, widget);
1767 else
1768 XtUnmanageChild (widget_to_manage);
1770 else
1772 if (up)
1773 XtManageChild (widget);
1774 else
1775 XtUnmanageChild (widget);
1780 /* motif callback */
1782 static void
1783 do_call (Widget widget,
1784 XtPointer closure,
1785 enum do_call_type type)
1787 Arg al [256];
1788 int ac;
1789 XtPointer user_data;
1790 widget_instance* instance = (widget_instance*)closure;
1791 Widget instance_widget;
1792 LWLIB_ID id;
1794 if (!instance)
1795 return;
1796 if (widget->core.being_destroyed)
1797 return;
1799 instance_widget = instance->widget;
1800 if (!instance_widget)
1801 return;
1803 id = instance->info->id;
1804 ac = 0;
1805 user_data = NULL;
1806 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1807 XtGetValues (widget, al, ac);
1809 switch (type)
1811 case pre_activate:
1812 if (instance->info->pre_activate_cb)
1813 instance->info->pre_activate_cb (widget, id, user_data);
1814 break;
1816 case selection:
1817 if (instance->info->selection_cb)
1818 instance->info->selection_cb (widget, id, user_data);
1819 break;
1821 case no_selection:
1822 if (instance->info->selection_cb)
1823 instance->info->selection_cb (widget, id, (XtPointer) -1);
1824 break;
1826 case post_activate:
1827 if (instance->info->post_activate_cb)
1828 instance->info->post_activate_cb (widget, id, user_data);
1829 break;
1831 default:
1832 abort ();
1836 /* Like lw_internal_update_other_instances except that it does not do
1837 anything if its shell parent is not managed. This is to protect
1838 lw_internal_update_other_instances to dereference freed memory
1839 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1840 list */
1841 static void
1842 xm_internal_update_other_instances (Widget widget,
1843 XtPointer closure,
1844 XtPointer call_data)
1846 Widget parent;
1847 for (parent = widget; parent; parent = XtParent (parent))
1848 if (XtIsShell (parent))
1849 break;
1850 else if (!XtIsManaged (parent))
1851 return;
1852 lw_internal_update_other_instances (widget, closure, call_data);
1855 static void
1856 xm_generic_callback (Widget widget,
1857 XtPointer closure,
1858 XtPointer call_data)
1860 lw_internal_update_other_instances (widget, closure, call_data);
1861 do_call (widget, closure, selection);
1864 static void
1865 xm_nosel_callback (Widget widget,
1866 XtPointer closure,
1867 XtPointer call_data)
1869 /* This callback is only called when a dialog box is dismissed with
1870 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1871 box to be destroyed in that case, not just unmapped, so that it
1872 releases its keyboard grabs. But there are problems with running
1873 our callbacks while the widget is in the process of being
1874 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1875 XmDESTROY and then destroy it ourself after having run the
1876 callback. */
1877 do_call (widget, closure, no_selection);
1878 XtDestroyWidget (widget);
1881 static void
1882 xm_pull_down_callback (Widget widget,
1883 XtPointer closure,
1884 XtPointer call_data)
1886 Widget parent = XtParent (widget);
1888 if (XmIsRowColumn (parent))
1890 unsigned char type = 0xff;
1891 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1892 if (type == XmMENU_BAR)
1893 do_call (widget, closure, pre_activate);
1898 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1899 CLOSURE is a pointer to the widget_instance of the shell,
1901 Note that this callback is called for each cascade button in a
1902 menu, whether or not its submenu is visible. */
1904 static void
1905 xm_pop_down_callback (Widget widget,
1906 XtPointer closure,
1907 XtPointer call_data)
1909 widget_instance *instance = (widget_instance *) closure;
1911 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1912 || XtParent (widget) == instance->parent)
1913 do_call (widget, closure, post_activate);
1917 /* set the keyboard focus */
1918 void
1919 xm_set_keyboard_focus (Widget parent, Widget w)
1921 XmProcessTraversal (w, 0);
1922 XtSetKeyboardFocus (parent, w);
1925 /* Motif hack to set the main window areas. */
1926 void
1927 xm_set_main_areas (Widget parent,
1928 Widget menubar,
1929 Widget work_area)
1931 XmMainWindowSetAreas (parent,
1932 menubar, /* menubar (maybe 0) */
1933 0, /* command area (psheets) */
1934 0, /* horizontal scroll */
1935 0, /* vertical scroll */
1936 work_area); /* work area */
1939 /* Motif hack to control resizing on the menubar. */
1940 void
1941 xm_manage_resizing (Widget w, Boolean flag)
1943 XtVaSetValues (w, XtNallowShellResize, flag, NULL);