Auto-commit of loaddefs files.
[emacs.git] / lwlib / lwlib-Xm.c
blobeccb4db23a6adf99ff042a5355d2f9e5765cbf27
1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2012 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; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
23 #include <config.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <setjmp.h>
29 #include <X11/StringDefs.h>
30 #include <X11/IntrinsicP.h>
31 #include <X11/ObjectP.h>
32 #include <X11/CoreP.h>
33 #include <X11/CompositeP.h>
35 #include <lisp.h>
37 #include "lwlib-Xm.h"
38 #include "lwlib-utils.h"
40 #include <Xm/BulletinB.h>
41 #include <Xm/CascadeB.h>
42 #include <Xm/CascadeBG.h>
43 #include <Xm/DrawingA.h>
44 #include <Xm/FileSB.h>
45 #include <Xm/Label.h>
46 #include <Xm/List.h>
47 #include <Xm/MainW.h>
48 #include <Xm/MenuShell.h>
49 #include <Xm/MessageB.h>
50 #include <Xm/PanedW.h>
51 #include <Xm/PushB.h>
52 #include <Xm/PushBG.h>
53 #include <Xm/ArrowB.h>
54 #include <Xm/SelectioB.h>
55 #include <Xm/Text.h>
56 #include <Xm/TextF.h>
57 #include <Xm/ToggleB.h>
58 #include <Xm/ToggleBG.h>
59 #include <Xm/RowColumn.h>
60 #include <Xm/ScrolledW.h>
61 #include <Xm/Separator.h>
62 #include <Xm/DialogS.h>
63 #include <Xm/Form.h>
65 enum do_call_type { pre_activate, selection, no_selection, post_activate };
68 \f/* Structures to keep destroyed instances */
69 typedef struct _destroyed_instance
71 char* name;
72 char* type;
73 Widget widget;
74 Widget parent;
75 Boolean pop_up_p;
76 struct _destroyed_instance* next;
77 } destroyed_instance;
79 static destroyed_instance *make_destroyed_instance (char *, char *,
80 Widget, Widget,
81 Boolean);
82 static void free_destroyed_instance (destroyed_instance*);
83 Widget first_child (Widget);
84 Boolean lw_motif_widget_p (Widget);
85 static XmString resource_motif_string (Widget, char *);
86 static void destroy_all_children (Widget, int);
87 static void xm_update_label (widget_instance *, Widget, widget_value *);
88 static void xm_update_list (widget_instance *, Widget, widget_value *);
89 static void xm_update_pushbutton (widget_instance *, Widget,
90 widget_value *);
91 static void xm_update_cascadebutton (widget_instance *, Widget,
92 widget_value *);
93 static void xm_update_toggle (widget_instance *, Widget, widget_value *);
94 static void xm_update_radiobox (widget_instance *, Widget, widget_value *);
95 static void make_menu_in_widget (widget_instance *, Widget,
96 widget_value *, int);
97 static void update_one_menu_entry (widget_instance *, Widget,
98 widget_value *, Boolean);
99 static void xm_update_menu (widget_instance *, Widget, widget_value *,
100 Boolean);
101 static void xm_update_text (widget_instance *, Widget, widget_value *);
102 static void xm_update_text_field (widget_instance *, Widget,
103 widget_value *);
104 void xm_update_one_value (widget_instance *, Widget, widget_value *);
105 static void activate_button (Widget, XtPointer, XtPointer);
106 static Widget make_dialog (char *, Widget, Boolean, char *, char *,
107 Boolean, Boolean, Boolean, int, int);
108 static destroyed_instance* find_matching_instance (widget_instance*);
109 static void mark_dead_instance_destroyed (Widget, XtPointer, XtPointer);
110 static void recenter_widget (Widget);
111 static Widget recycle_instance (destroyed_instance*);
112 Widget xm_create_dialog (widget_instance*);
113 static Widget make_menubar (widget_instance*);
114 static void remove_grabs (Widget, XtPointer, XtPointer);
115 static Widget make_popup_menu (widget_instance*);
116 static Widget make_main (widget_instance*);
117 void xm_destroy_instance (widget_instance*);
118 void xm_popup_menu (Widget, XEvent *);
119 static void set_min_dialog_size (Widget);
120 static void do_call (Widget, XtPointer, enum do_call_type);
121 static void xm_generic_callback (Widget, XtPointer, XtPointer);
122 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
123 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
124 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
125 void xm_set_keyboard_focus (Widget, Widget);
126 void xm_set_main_areas (Widget, Widget, Widget);
127 static void xm_internal_update_other_instances (Widget, XtPointer,
128 XtPointer);
129 static void xm_arm_callback (Widget, XtPointer, XtPointer);
131 #if 0
132 void xm_update_one_widget (widget_instance *, Widget, widget_value *,
133 Boolean);
134 void xm_pop_instance (widget_instance*, Boolean);
135 void xm_manage_resizing (Widget, Boolean);
136 #endif
139 #if 0
141 /* Print the complete X resource name of widget WIDGET to stderr.
142 This is sometimes handy to have available. */
144 void
145 x_print_complete_resource_name (Widget widget)
147 int i;
148 String names[100];
150 for (i = 0; i < 100 && widget != NULL; ++i)
152 names[i] = XtName (widget);
153 widget = XtParent (widget);
156 for (--i; i >= 1; --i)
157 fprintf (stderr, "%s.", names[i]);
158 fprintf (stderr, "%s\n", names[0]);
161 #endif /* 0 */
164 static destroyed_instance *all_destroyed_instances = NULL;
166 static destroyed_instance*
167 make_destroyed_instance (char* name,
168 char* type,
169 Widget widget,
170 Widget parent,
171 Boolean pop_up_p)
173 destroyed_instance* instance =
174 (destroyed_instance*) xmalloc (sizeof (destroyed_instance));
175 instance->name = safe_strdup (name);
176 instance->type = safe_strdup (type);
177 instance->widget = widget;
178 instance->parent = parent;
179 instance->pop_up_p = pop_up_p;
180 instance->next = NULL;
181 return instance;
184 static void
185 free_destroyed_instance (destroyed_instance* instance)
187 xfree (instance->name);
188 xfree (instance->type);
189 xfree (instance);
192 \f/* motif utility functions */
193 Widget
194 first_child (Widget widget)
196 return ((CompositeWidget)widget)->composite.children [0];
199 Boolean
200 lw_motif_widget_p (Widget widget)
202 return
203 XtClass (widget) == xmDialogShellWidgetClass
204 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
207 static XmString
208 resource_motif_string (Widget widget,
209 char* name)
211 XtResource resource;
212 XmString result = 0;
214 resource.resource_name = name;
215 resource.resource_class = XmCXmString;
216 resource.resource_type = XmRXmString;
217 resource.resource_size = sizeof (XmString);
218 resource.resource_offset = 0;
219 resource.default_type = XtRImmediate;
220 resource.default_addr = 0;
222 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
223 "DialogString", &resource, 1, NULL, 0);
224 return result;
227 /* Destroy all of the children of WIDGET
228 starting with number FIRST_CHILD_TO_DESTROY. */
230 static void
231 destroy_all_children (Widget widget,
232 int first_child_to_destroy)
234 Widget* children;
235 unsigned int number;
236 int i;
238 children = XtCompositeChildren (widget, &number);
239 if (children)
241 XtUnmanageChildren (children + first_child_to_destroy,
242 number - first_child_to_destroy);
244 /* Unmanage all children and destroy them. They will only be
245 really destroyed when we get out of DispatchEvent. */
246 for (i = first_child_to_destroy; i < number; i++)
248 Arg al[2];
249 Widget submenu = 0;
250 /* Cascade buttons have submenus,and these submenus
251 need to be freed. But they are not included in
252 XtCompositeChildren. So get it out of the cascade button
253 and free it. If this child is not a cascade button,
254 then submenu should remain unchanged. */
255 XtSetArg (al[0], XmNsubMenuId, &submenu);
256 XtGetValues (children[i], al, 1);
257 if (submenu)
259 destroy_all_children (submenu, 0);
260 XtDestroyWidget (submenu);
262 XtDestroyWidget (children[i]);
265 XtFree ((char *) children);
271 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
272 menu. CLIENT_DATA contains a pointer to the widget_value
273 corresponding to widget W. CALL_DATA contains a
274 XmPushButtonCallbackStruct containing the reason why the callback
275 is called. */
277 static void
278 xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
280 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
281 widget_value *wv = (widget_value *) client_data;
282 widget_instance *instance;
284 /* Get the id of the menu bar or popup menu this widget is in. */
285 while (w != NULL)
287 if (XmIsRowColumn (w))
289 unsigned char type = 0xff;
291 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
292 if (type == XmMENU_BAR || type == XmMENU_POPUP)
293 break;
296 w = XtParent (w);
299 if (w != NULL)
301 instance = lw_get_widget_instance (w);
302 if (instance && instance->info->highlight_cb)
304 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
305 instance->info->highlight_cb (w, instance->info->id, call_data);
312 /* Update the label of widget WIDGET. WIDGET must be a Label widget
313 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
314 the value to update.
316 Menus:
318 Emacs fills VAL->name with the text to display in the menu, and
319 sets VAL->value to null. Function make_menu_in_widget creates
320 widgets with VAL->name as resource name. This works because the
321 Label widget uses its resource name for display if no
322 XmNlabelString is set.
324 Dialogs:
326 VAL->name is again set to the resource name, but VAL->value is
327 not null, and contains the label string to display. */
329 static void
330 xm_update_label (widget_instance* instance,
331 Widget widget,
332 widget_value* val)
334 XmString res_string = 0;
335 XmString built_string = 0;
336 XmString key_string = 0;
337 Arg al [256];
338 int ac;
340 ac = 0;
342 if (val->value)
344 /* A label string is specified, i.e. we are in a dialog. First
345 see if it is overridden by something from the resource file. */
346 res_string = resource_motif_string (widget, val->value);
348 if (res_string)
350 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
352 else
354 built_string =
355 XmStringCreateLocalized (val->value);
356 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
359 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
362 if (val->key)
364 key_string = XmStringCreateLocalized (val->key);
365 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
368 if (ac)
369 XtSetValues (widget, al, ac);
371 if (built_string)
372 XmStringFree (built_string);
374 if (key_string)
375 XmStringFree (key_string);
378 \f/* update of list */
379 static void
380 xm_update_list (widget_instance* instance,
381 Widget widget,
382 widget_value* val)
384 widget_value* cur;
385 int i;
386 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
387 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
388 instance);
389 for (cur = val->contents, i = 0; cur; cur = cur->next)
390 if (cur->value)
392 XmString xmstr = XmStringCreateLocalized (cur->value);
393 i += 1;
394 XmListAddItem (widget, xmstr, 0);
395 if (cur->selected)
396 XmListSelectPos (widget, i, False);
397 XmStringFree (xmstr);
401 \f/* update of buttons */
402 static void
403 xm_update_pushbutton (widget_instance* instance,
404 Widget widget,
405 widget_value* val)
407 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
408 XtRemoveAllCallbacks (widget, XmNactivateCallback);
409 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
412 static void
413 xm_update_cascadebutton (widget_instance* instance,
414 Widget widget,
415 widget_value* val)
417 /* Should also rebuild the menu by calling ...update_menu... */
418 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
419 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
420 instance);
423 \f/* update toggle and radiobox */
424 static void
425 xm_update_toggle (widget_instance* instance,
426 Widget widget,
427 widget_value* val)
429 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
430 XtAddCallback (widget, XmNvalueChangedCallback,
431 xm_generic_callback, instance);
432 XtVaSetValues (widget, XmNset, val->selected,
433 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
436 static void
437 xm_update_radiobox (widget_instance* instance,
438 Widget widget,
439 widget_value* val)
442 Widget toggle;
443 widget_value* cur;
445 /* update the callback */
446 XtRemoveAllCallbacks (widget, XmNentryCallback);
447 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
449 /* first update all the toggles */
450 /* Energize kernel interface is currently bad. It sets the selected widget
451 with the selected flag but returns it by its name. So we currently
452 have to support both setting the selection with the selected slot
453 of val contents and setting it with the "value" slot of val. The latter
454 has a higher priority. This to be removed when the kernel is fixed. */
455 for (cur = val->contents; cur; cur = cur->next)
457 toggle = XtNameToWidget (widget, cur->value);
458 if (toggle)
460 XtSetSensitive (toggle, cur->enabled);
461 if (!val->value && cur->selected)
462 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
463 if (val->value && strcmp (val->value, cur->value))
464 XtVaSetValues (toggle, XmNset, False, NULL);
468 /* The selected was specified by the value slot */
469 if (val->value)
471 toggle = XtNameToWidget (widget, val->value);
472 if (toggle)
473 XtVaSetValues (toggle, XmNset, True, NULL);
478 /* update a popup menu, pulldown menu or a menubar */
480 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
482 static void
483 make_menu_in_widget (widget_instance* instance,
484 Widget widget,
485 widget_value* val,
486 int keep_first_children)
488 Widget* children = 0;
489 int num_children;
490 int child_index;
491 widget_value* cur;
492 Widget button = 0;
493 Widget menu;
494 Arg al [256];
495 int ac;
496 Boolean menubar_p;
497 unsigned char type;
499 Widget* old_children;
500 unsigned int old_num_children;
502 /* Disable drag and drop for labels in menu bar. */
503 static char overrideTrans[] = "<Btn2Down>: Noop()";
504 XtTranslations override = XtParseTranslationTable (overrideTrans);
506 old_children = XtCompositeChildren (widget, &old_num_children);
508 /* Allocate the children array */
509 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
511 children = (Widget*)(void*)XtMalloc (num_children * sizeof (Widget));
513 /* WIDGET should be a RowColumn. */
514 if (!XmIsRowColumn (widget))
515 abort ();
517 /* Determine whether WIDGET is a menu bar. */
518 type = -1;
519 XtSetArg (al[0], XmNrowColumnType, &type);
520 XtGetValues (widget, al, 1);
521 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
522 abort ();
523 menubar_p = type == XmMENU_BAR;
525 /* Add a callback to popups and pulldowns that is called when
526 it is made invisible again. */
527 if (!menubar_p)
528 XtAddCallback (XtParent (widget), XmNpopdownCallback,
529 xm_pop_down_callback, (XtPointer)instance);
531 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
532 for (child_index = 0, cur = val; child_index < keep_first_children;
533 child_index++, cur = cur->next)
534 children[child_index] = old_children[child_index];
536 /* Check that those are all we have
537 (the caller should have deleted the rest). */
538 if (old_num_children != keep_first_children)
539 abort ();
541 /* Create the rest. */
542 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
544 enum menu_separator separator;
546 ac = 0;
547 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
548 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
549 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
551 if (instance->pop_up_p && !cur->contents && !cur->call_data
552 && !lw_separator_p (cur->name, &separator, 1))
554 ac = 0;
555 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
556 button = XmCreateLabel (widget, cur->name, al, ac);
558 else if (lw_separator_p (cur->name, &separator, 1))
560 ac = 0;
561 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
562 button = XmCreateSeparator (widget, cur->name, al, ac);
564 else if (!cur->contents)
566 if (menubar_p)
567 button = XmCreateCascadeButton (widget, cur->name, al, ac);
568 else if (!cur->call_data)
569 button = XmCreateLabel (widget, cur->name, al, ac);
570 else if (cur->button_type == BUTTON_TYPE_TOGGLE
571 || cur->button_type == BUTTON_TYPE_RADIO)
573 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
574 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
575 XtSetArg (al[ac], XmNindicatorType,
576 (cur->button_type == BUTTON_TYPE_TOGGLE
577 ? XmN_OF_MANY : XmONE_OF_MANY));
578 ++ac;
579 button = XmCreateToggleButton (widget, cur->name, al, ac);
580 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
581 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
583 else
585 button = XmCreatePushButton (widget, cur->name, al, ac);
586 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
587 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
590 xm_update_label (instance, button, cur);
592 /* Add a callback that is called when the button is
593 selected. Toggle buttons don't support
594 XmNactivateCallback, we use XmNvalueChangedCallback in
595 that case. Don't add a callback to a simple label. */
596 if (cur->button_type)
597 xm_update_toggle (instance, button, cur);
598 else if (cur->call_data)
599 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
600 (XtPointer)instance);
602 else
604 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
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);
614 XtOverrideTranslations (button, override);
618 children[child_index] = button;
621 /* Last entry is the help button. The original comment read "Has to
622 be done after managing the buttons otherwise the menubar is only
623 4 pixels high." This is no longer true, and to make
624 XmNmenuHelpWidget work, we need to set it before managing the
625 children.. --gerd. */
626 if (button)
627 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
629 if (num_children)
630 XtManageChildren (children, num_children);
632 XtFree ((char *) children);
633 if (old_children)
634 XtFree ((char *) old_children);
637 static void
638 update_one_menu_entry (widget_instance* instance,
639 Widget widget,
640 widget_value* val,
641 Boolean deep_p)
643 Arg al [256];
644 int ac;
645 Widget menu;
646 widget_value* contents;
648 if (val->this_one_change == NO_CHANGE)
649 return;
651 /* update the sensitivity and userdata */
652 /* Common to all widget types */
653 XtSetSensitive (widget, val->enabled);
654 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
656 /* update the menu button as a label. */
657 if (val->this_one_change >= VISIBLE_CHANGE)
659 xm_update_label (instance, widget, val);
660 if (val->button_type)
661 xm_update_toggle (instance, widget, val);
664 /* update the pulldown/pullaside as needed */
665 ac = 0;
666 menu = NULL;
667 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
668 XtGetValues (widget, al, ac);
670 contents = val->contents;
672 if (!menu)
674 if (contents)
676 unsigned int old_num_children, i;
677 Widget parent;
678 Widget *widget_list;
680 parent = XtParent (widget);
681 widget_list = XtCompositeChildren (parent, &old_num_children);
683 /* Find the widget position within the parent's widget list. */
684 for (i = 0; i < old_num_children; i++)
685 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
686 break;
687 if (i == old_num_children)
688 abort ();
689 if (XmIsCascadeButton (widget_list[i]))
691 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
692 make_menu_in_widget (instance, menu, contents, 0);
693 ac = 0;
694 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
695 XtSetValues (widget, al, ac);
697 else
699 Widget button;
701 /* The current menuitem is a XmPushButtonGadget, it
702 needs to be replaced by a CascadeButtonGadget */
703 XtDestroyWidget (widget_list[i]);
704 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
705 make_menu_in_widget (instance, menu, contents, 0);
706 ac = 0;
707 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
708 /* Non-zero values don't work reliably in
709 conjunction with Emacs' event loop */
710 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
711 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
712 /* Tell Motif to put it in the right place */
713 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
714 #endif
715 button = XmCreateCascadeButton (parent, val->name, al, ac);
716 xm_update_label (instance, button, val);
718 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
719 (XtPointer)instance);
720 XtManageChild (button);
723 if (widget_list)
724 XtFree ((char*) widget_list);
727 else if (!contents)
729 ac = 0;
730 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
731 XtSetValues (widget, al, ac);
732 XtDestroyWidget (menu);
734 else if (deep_p && contents->change != NO_CHANGE)
735 xm_update_menu (instance, menu, val, 1);
738 static void
739 xm_update_menu (widget_instance* instance,
740 Widget widget,
741 widget_value* val,
742 Boolean deep_p)
744 Widget* children;
745 unsigned int num_children;
746 int num_children_to_keep = 0;
747 int i;
748 widget_value* cur;
750 children = XtCompositeChildren (widget, &num_children);
752 /* Widget is a RowColumn widget whose contents have to be updated
753 * to reflect the list of items in val->contents */
755 /* See how many buttons we can keep, and how many we
756 must completely replace. */
757 if (val->contents == 0)
758 num_children_to_keep = 0;
759 else if (val->contents->change == STRUCTURAL_CHANGE)
761 if (children)
763 for (i = 0, cur = val->contents;
764 (i < num_children
765 && cur); /* how else to ditch unwanted children ?? - mgd */
766 i++, cur = cur->next)
768 if (cur->this_one_change == STRUCTURAL_CHANGE)
769 break;
772 num_children_to_keep = i;
775 else
776 num_children_to_keep = num_children;
778 /* Update all the buttons of the RowColumn, in order,
779 except for those we are going to replace entirely. */
780 if (children)
782 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
784 if (!cur)
786 num_children_to_keep = i;
787 break;
789 if (children [i]->core.being_destroyed
790 || strcmp (XtName (children [i]), cur->name))
791 continue;
792 update_one_menu_entry (instance, children [i], cur, deep_p);
793 cur = cur->next;
797 /* Now replace from scratch all the buttons after the last
798 place that the top-level structure changed. */
799 if (val->contents && val->contents->change == STRUCTURAL_CHANGE)
801 destroy_all_children (widget, num_children_to_keep);
802 make_menu_in_widget (instance, widget, val->contents,
803 num_children_to_keep);
806 XtFree ((char *) children);
810 /* update text widgets */
812 static void
813 xm_update_text (widget_instance* instance,
814 Widget widget,
815 widget_value* val)
817 XmTextSetString (widget, val->value ? val->value : "");
818 XtRemoveAllCallbacks (widget, XmNactivateCallback);
819 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
820 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
821 XtAddCallback (widget, XmNvalueChangedCallback,
822 xm_internal_update_other_instances, instance);
825 static void
826 xm_update_text_field (widget_instance* instance,
827 Widget widget,
828 widget_value* val)
830 XmTextFieldSetString (widget, val->value ? val->value : "");
831 XtRemoveAllCallbacks (widget, XmNactivateCallback);
832 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
833 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
834 XtAddCallback (widget, XmNvalueChangedCallback,
835 xm_internal_update_other_instances, instance);
839 /* update a motif widget */
841 void
842 xm_update_one_widget (widget_instance* instance,
843 Widget widget,
844 widget_value* val,
845 Boolean deep_p)
847 WidgetClass class;
849 /* Mark as not edited */
850 val->edited = False;
852 /* Common to all widget types */
853 XtSetSensitive (widget, val->enabled);
854 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
856 /* Common to all label like widgets */
857 if (XtIsSubclass (widget, xmLabelWidgetClass))
858 xm_update_label (instance, widget, val);
860 class = XtClass (widget);
861 /* Class specific things */
862 if (class == xmPushButtonWidgetClass ||
863 class == xmArrowButtonWidgetClass)
865 xm_update_pushbutton (instance, widget, val);
867 else if (class == xmCascadeButtonWidgetClass)
869 xm_update_cascadebutton (instance, widget, val);
871 else if (class == xmToggleButtonWidgetClass
872 || class == xmToggleButtonGadgetClass)
874 xm_update_toggle (instance, widget, val);
876 else if (class == xmRowColumnWidgetClass)
878 Boolean radiobox = 0;
879 int ac = 0;
880 Arg al [1];
882 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
883 XtGetValues (widget, al, ac);
885 if (radiobox)
886 xm_update_radiobox (instance, widget, val);
887 else
888 xm_update_menu (instance, widget, val, deep_p);
890 else if (class == xmTextWidgetClass)
892 xm_update_text (instance, widget, val);
894 else if (class == xmTextFieldWidgetClass)
896 xm_update_text_field (instance, widget, val);
898 else if (class == xmListWidgetClass)
900 xm_update_list (instance, widget, val);
904 \f/* getting the value back */
905 void
906 xm_update_one_value (widget_instance* instance,
907 Widget widget,
908 widget_value* val)
910 WidgetClass class = XtClass (widget);
911 widget_value *old_wv;
913 /* copy the call_data slot into the "return" widget_value */
914 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
915 if (!strcmp (val->name, old_wv->name))
917 val->call_data = old_wv->call_data;
918 break;
921 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
923 XtVaGetValues (widget, XmNset, &val->selected, NULL);
924 val->edited = True;
926 else if (class == xmTextWidgetClass)
928 xfree (val->value);
929 val->value = XmTextGetString (widget);
930 val->edited = True;
932 else if (class == xmTextFieldWidgetClass)
934 xfree (val->value);
935 val->value = XmTextFieldGetString (widget);
936 val->edited = True;
938 else if (class == xmRowColumnWidgetClass)
940 Boolean radiobox = 0;
941 int ac = 0;
942 Arg al [1];
944 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
945 XtGetValues (widget, al, ac);
947 if (radiobox)
949 CompositeWidget radio = (CompositeWidget)widget;
950 int i;
951 for (i = 0; i < radio->composite.num_children; i++)
953 int set = False;
954 Widget toggle = radio->composite.children [i];
956 XtVaGetValues (toggle, XmNset, &set, NULL);
957 if (set)
959 xfree (val->value);
960 val->value = safe_strdup (XtName (toggle));
963 val->edited = True;
966 else if (class == xmListWidgetClass)
968 int pos_cnt;
969 int* pos_list;
970 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
972 int i;
973 widget_value* cur;
974 for (cur = val->contents, i = 0; cur; cur = cur->next)
975 if (cur->value)
977 int j;
978 cur->selected = False;
979 i += 1;
980 for (j = 0; j < pos_cnt; j++)
981 if (pos_list [j] == i)
983 cur->selected = True;
984 val->value = safe_strdup (cur->name);
987 val->edited = 1;
988 XtFree ((char *) pos_list);
994 /* This function is for activating a button from a program. It's wrong because
995 we pass a NULL argument in the call_data which is not Motif compatible.
996 This is used from the XmNdefaultAction callback of the List widgets to
997 have a double-click put down a dialog box like the button would do.
998 I could not find a way to do that with accelerators.
1000 static void
1001 activate_button (Widget widget,
1002 XtPointer closure,
1003 XtPointer call_data)
1005 Widget button = (Widget)closure;
1006 XtCallCallbacks (button, XmNactivateCallback, NULL);
1009 /* creation functions */
1011 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1012 static void
1013 dialog_key_cb (Widget widget,
1014 XtPointer closure,
1015 XEvent *event,
1016 Boolean *continue_to_dispatch)
1018 KeySym sym = 0;
1019 Modifiers modif_ret;
1021 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1022 &modif_ret, &sym);
1024 if (sym == osfXK_Cancel)
1026 Widget w = *((Widget *) closure);
1028 while (w && ! XtIsShell (w))
1029 w = XtParent (w);
1031 if (XtIsShell (w)) XtPopdown (w);
1034 *continue_to_dispatch = TRUE;
1037 /* dialogs */
1038 static Widget
1039 make_dialog (char* name,
1040 Widget parent,
1041 Boolean pop_up_p,
1042 char* shell_title,
1043 char* icon_name,
1044 Boolean text_input_slot,
1045 Boolean radio_box,
1046 Boolean list,
1047 int left_buttons,
1048 int right_buttons)
1050 Widget result;
1051 Widget form;
1052 Widget row;
1053 Widget icon;
1054 Widget icon_separator;
1055 Widget message_label;
1056 Widget value = 0;
1057 Widget separator;
1058 Widget button = 0;
1059 Widget children [16]; /* for the final XtManageChildren */
1060 int n_children;
1061 Arg al[64]; /* Arg List */
1062 int ac; /* Arg Count */
1063 int i;
1065 if (pop_up_p)
1067 ac = 0;
1068 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1069 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1070 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1071 result = XmCreateDialogShell (parent, "dialog", al, ac);
1072 ac = 0;
1073 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1074 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1075 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1076 form = XmCreateForm (result, shell_title, al, ac);
1078 else
1080 ac = 0;
1081 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1082 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1083 form = XmCreateForm (parent, shell_title, al, ac);
1084 result = form;
1087 n_children = left_buttons + right_buttons + 1;
1088 ac = 0;
1089 XtSetArg(al[ac], XmNpacking, n_children == 3?
1090 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1091 XtSetArg(al[ac], XmNorientation, n_children == 3?
1092 XmVERTICAL: XmHORIZONTAL); ac++;
1093 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1094 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1095 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1096 XtSetArg(al[ac], XmNspacing, 13); ac++;
1097 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1098 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1099 XtSetArg(al[ac], XmNisAligned, True); ac++;
1100 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1101 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1102 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1103 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1104 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1105 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1106 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1107 row = XmCreateRowColumn (form, "row", al, ac);
1109 n_children = 0;
1110 for (i = 0; i < left_buttons; i++)
1112 char button_name [16];
1113 sprintf (button_name, "button%d", i + 1);
1114 ac = 0;
1115 if (i == 0)
1117 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1118 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1120 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1121 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1122 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1123 XtAddEventHandler (children [n_children],
1124 KeyPressMask, False, dialog_key_cb, result);
1126 if (i == 0)
1128 button = children [n_children];
1129 ac = 0;
1130 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1131 XtSetValues (row, al, ac);
1134 n_children++;
1137 /* invisible separator button */
1138 ac = 0;
1139 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1140 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1141 n_children++;
1143 for (i = 0; i < right_buttons; i++)
1145 char button_name [16];
1146 sprintf (button_name, "button%d", left_buttons + i + 1);
1147 ac = 0;
1148 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1149 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1150 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1151 XtAddEventHandler (children [n_children],
1152 KeyPressMask, False, dialog_key_cb, result);
1154 if (! button) button = children [n_children];
1155 n_children++;
1158 XtManageChildren (children, n_children);
1160 ac = 0;
1161 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1162 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1163 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1164 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1165 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1166 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1167 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1168 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1169 separator = XmCreateSeparator (form, "", al, ac);
1171 ac = 0;
1172 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1173 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1174 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1175 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1176 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1177 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1178 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1179 icon = XmCreateLabel (form, icon_name, al, ac);
1181 ac = 0;
1182 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1183 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1184 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1185 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1186 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1187 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1188 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1189 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1190 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1191 icon_separator = XmCreateLabel (form, "", al, ac);
1193 if (text_input_slot)
1195 ac = 0;
1196 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1197 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1198 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1199 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1200 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1201 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1202 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1203 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1204 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1205 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1206 value = XmCreateTextField (form, "value", al, ac);
1208 else if (radio_box)
1210 Widget radio_butt;
1211 ac = 0;
1212 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1213 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1214 XtSetArg(al[ac], XmNspacing, 13); ac++;
1215 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1216 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1217 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1218 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1219 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1220 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1221 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1222 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1223 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1224 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1225 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1226 ac = 0;
1227 i = 0;
1228 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1229 children [i++] = radio_butt;
1230 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1231 children [i++] = radio_butt;
1232 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1233 children [i++] = radio_butt;
1234 XtManageChildren (children, i);
1236 else if (list)
1238 ac = 0;
1239 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1240 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1241 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1242 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1243 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1244 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1245 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1246 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1247 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1248 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1249 value = XmCreateScrolledList (form, "list", al, ac);
1251 /* this is the easiest way I found to have the dble click in the
1252 list activate the default button */
1253 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1256 ac = 0;
1257 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1258 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1259 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1260 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1261 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1262 XtSetArg(al[ac], XmNbottomWidget,
1263 text_input_slot || radio_box || list ? value : separator); ac++;
1264 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1265 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1266 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1267 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1268 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1269 message_label = XmCreateLabel (form, "message", al, ac);
1271 if (list)
1272 XtManageChild (value);
1274 i = 0;
1275 children [i] = row; i++;
1276 children [i] = separator; i++;
1277 if (text_input_slot || radio_box)
1279 children [i] = value; i++;
1281 children [i] = message_label; i++;
1282 children [i] = icon; i++;
1283 children [i] = icon_separator; i++;
1284 XtManageChildren (children, i);
1286 if (text_input_slot || list)
1288 XtInstallAccelerators (value, button);
1289 XtSetKeyboardFocus (result, value);
1291 else
1293 XtInstallAccelerators (form, button);
1294 XtSetKeyboardFocus (result, button);
1297 return result;
1300 static destroyed_instance*
1301 find_matching_instance (widget_instance* instance)
1303 destroyed_instance* cur;
1304 destroyed_instance* prev;
1305 char* type = instance->info->type;
1306 char* name = instance->info->name;
1308 for (prev = NULL, cur = all_destroyed_instances;
1309 cur;
1310 prev = cur, cur = cur->next)
1312 if (!strcmp (cur->name, name)
1313 && !strcmp (cur->type, type)
1314 && cur->parent == instance->parent
1315 && cur->pop_up_p == instance->pop_up_p)
1317 if (prev)
1318 prev->next = cur->next;
1319 else
1320 all_destroyed_instances = cur->next;
1321 return cur;
1323 /* do some cleanup */
1324 else if (!cur->widget)
1326 if (prev)
1327 prev->next = cur->next;
1328 else
1329 all_destroyed_instances = cur->next;
1330 free_destroyed_instance (cur);
1331 cur = prev ? prev : all_destroyed_instances;
1334 return NULL;
1337 static void
1338 mark_dead_instance_destroyed (Widget widget,
1339 XtPointer closure,
1340 XtPointer call_data)
1342 destroyed_instance* instance = (destroyed_instance*)closure;
1343 instance->widget = NULL;
1346 static void
1347 recenter_widget (Widget widget)
1349 Widget parent = XtParent (widget);
1350 Screen* screen = XtScreen (widget);
1351 Dimension screen_width = WidthOfScreen (screen);
1352 Dimension screen_height = HeightOfScreen (screen);
1353 Dimension parent_width = 0;
1354 Dimension parent_height = 0;
1355 Dimension child_width = 0;
1356 Dimension child_height = 0;
1357 Position x;
1358 Position y;
1360 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1361 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1362 NULL);
1364 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1365 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1367 XtTranslateCoords (parent, x, y, &x, &y);
1369 if (x + child_width > screen_width)
1370 x = screen_width - child_width;
1371 if (x < 0)
1372 x = 0;
1374 if (y + child_height > screen_height)
1375 y = screen_height - child_height;
1376 if (y < 0)
1377 y = 0;
1379 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1382 static Widget
1383 recycle_instance (destroyed_instance* instance)
1385 Widget widget = instance->widget;
1387 /* widget is NULL if the parent was destroyed. */
1388 if (widget)
1390 Widget focus;
1391 Widget separator;
1393 /* Remove the destroy callback as the instance is not in the list
1394 anymore */
1395 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1396 mark_dead_instance_destroyed,
1397 (XtPointer)instance);
1399 /* Give the focus to the initial item */
1400 focus = XtNameToWidget (widget, "*value");
1401 if (!focus)
1402 focus = XtNameToWidget (widget, "*button1");
1403 if (focus)
1404 XtSetKeyboardFocus (widget, focus);
1406 /* shrink the separator label back to their original size */
1407 separator = XtNameToWidget (widget, "*separator_button");
1408 if (separator)
1409 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1411 /* Center the dialog in its parent */
1412 recenter_widget (widget);
1414 free_destroyed_instance (instance);
1415 return widget;
1418 Widget
1419 xm_create_dialog (widget_instance* instance)
1421 char* name = instance->info->type;
1422 Widget parent = instance->parent;
1423 Widget widget;
1424 Boolean pop_up_p = instance->pop_up_p;
1425 char* shell_name = 0;
1426 char* icon_name = 0;
1427 Boolean text_input_slot = False;
1428 Boolean radio_box = False;
1429 Boolean list = False;
1430 int total_buttons;
1431 int left_buttons = 0;
1432 int right_buttons = 1;
1433 destroyed_instance* dead_one;
1435 /* try to find a widget to recycle */
1436 dead_one = find_matching_instance (instance);
1437 if (dead_one)
1439 Widget recycled_widget = recycle_instance (dead_one);
1440 if (recycled_widget)
1441 return recycled_widget;
1444 switch (name [0]){
1445 case 'E': case 'e':
1446 icon_name = "dbox-error";
1447 shell_name = "Error";
1448 break;
1450 case 'I': case 'i':
1451 icon_name = "dbox-info";
1452 shell_name = "Information";
1453 break;
1455 case 'L': case 'l':
1456 list = True;
1457 icon_name = "dbox-question";
1458 shell_name = "Prompt";
1459 break;
1461 case 'P': case 'p':
1462 text_input_slot = True;
1463 icon_name = "dbox-question";
1464 shell_name = "Prompt";
1465 break;
1467 case 'Q': case 'q':
1468 icon_name = "dbox-question";
1469 shell_name = "Question";
1470 break;
1473 total_buttons = name [1] - '0';
1475 if (name [3] == 'T' || name [3] == 't')
1477 text_input_slot = False;
1478 radio_box = True;
1480 else if (name [3])
1481 right_buttons = name [4] - '0';
1483 left_buttons = total_buttons - right_buttons;
1485 widget = make_dialog (name, parent, pop_up_p,
1486 shell_name, icon_name, text_input_slot, radio_box,
1487 list, left_buttons, right_buttons);
1489 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1490 (XtPointer) instance);
1492 return widget;
1495 /* Create a menu bar. We turn off the f10 key
1496 because we have not yet managed to make it work right in Motif. */
1498 static Widget
1499 make_menubar (widget_instance* instance)
1501 Arg al[3];
1502 int ac;
1504 ac = 0;
1505 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1506 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1509 static void
1510 remove_grabs (Widget shell,
1511 XtPointer closure,
1512 XtPointer call_data)
1514 Widget menu = (Widget) closure;
1515 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1518 static Widget
1519 make_popup_menu (widget_instance* instance)
1521 Widget parent = instance->parent;
1522 Window parent_window = parent->core.window;
1523 Widget result;
1525 /* sets the parent window to 0 to fool Motif into not generating a grab */
1526 parent->core.window = 0;
1527 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1528 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1529 (XtPointer)result);
1530 parent->core.window = parent_window;
1531 return result;
1534 static Widget
1535 make_main (widget_instance* instance)
1537 Widget parent = instance->parent;
1538 Widget result;
1539 Arg al[2];
1540 int ac;
1542 ac = 0;
1543 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1544 XtSetArg (al[ac], XmNspacing, 0); ac++;
1545 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1546 return result;
1549 \f/* Table of functions to create widgets */
1551 #ifdef ENERGIZE
1553 /* interface with the XDesigner generated functions */
1554 typedef Widget (*widget_maker) (Widget);
1555 extern Widget create_project_p_sheet (Widget parent);
1556 extern Widget create_debugger_p_sheet (Widget parent);
1557 extern Widget create_breaklist_p_sheet (Widget parent);
1558 extern Widget create_le_browser_p_sheet (Widget parent);
1559 extern Widget create_class_browser_p_sheet (Widget parent);
1560 extern Widget create_call_browser_p_sheet (Widget parent);
1561 extern Widget create_build_dialog (Widget parent);
1562 extern Widget create_editmode_dialog (Widget parent);
1563 extern Widget create_search_dialog (Widget parent);
1564 extern Widget create_project_display_dialog (Widget parent);
1566 static Widget
1567 make_one (widget_instance* instance, widget_maker fn)
1569 Widget result;
1570 Arg al [64];
1571 int ac = 0;
1573 if (instance->pop_up_p)
1575 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1576 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1577 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1578 (XtPointer) instance);
1579 (*fn) (result);
1581 else
1583 result = (*fn) (instance->parent);
1584 XtRealizeWidget (result);
1586 return result;
1589 static Widget
1590 make_project_p_sheet (widget_instance* instance)
1592 return make_one (instance, create_project_p_sheet);
1595 static Widget
1596 make_debugger_p_sheet (widget_instance* instance)
1598 return make_one (instance, create_debugger_p_sheet);
1601 static Widget
1602 make_breaklist_p_sheet (widget_instance* instance)
1604 return make_one (instance, create_breaklist_p_sheet);
1607 static Widget
1608 make_le_browser_p_sheet (widget_instance* instance)
1610 return make_one (instance, create_le_browser_p_sheet);
1613 static Widget
1614 make_class_browser_p_sheet (widget_instance* instance)
1616 return make_one (instance, create_class_browser_p_sheet);
1619 static Widget
1620 make_call_browser_p_sheet (widget_instance* instance)
1622 return make_one (instance, create_call_browser_p_sheet);
1625 static Widget
1626 make_build_dialog (widget_instance* instance)
1628 return make_one (instance, create_build_dialog);
1631 static Widget
1632 make_editmode_dialog (widget_instance* instance)
1634 return make_one (instance, create_editmode_dialog);
1637 static Widget
1638 make_search_dialog (widget_instance* instance)
1640 return make_one (instance, create_search_dialog);
1643 static Widget
1644 make_project_display_dialog (widget_instance* instance)
1646 return make_one (instance, create_project_display_dialog);
1649 #endif /* ENERGIZE */
1651 widget_creation_entry
1652 xm_creation_table [] =
1654 {"menubar", make_menubar},
1655 {"popup", make_popup_menu},
1656 {"main", make_main},
1657 #ifdef ENERGIZE
1658 {"project_p_sheet", make_project_p_sheet},
1659 {"debugger_p_sheet", make_debugger_p_sheet},
1660 {"breaklist_psheet", make_breaklist_p_sheet},
1661 {"leb_psheet", make_le_browser_p_sheet},
1662 {"class_browser_psheet", make_class_browser_p_sheet},
1663 {"ctree_browser_psheet", make_call_browser_p_sheet},
1664 {"build", make_build_dialog},
1665 {"editmode", make_editmode_dialog},
1666 {"search", make_search_dialog},
1667 {"project_display", make_project_display_dialog},
1668 #endif /* ENERGIZE */
1669 {NULL, NULL}
1672 \f/* Destruction of instances */
1673 void
1674 xm_destroy_instance ( widget_instance* instance)
1676 Widget widget = instance->widget;
1677 /* recycle the dialog boxes */
1678 /* Disable the recycling until we can find a way to have the dialog box
1679 get reasonable layout after we modify its contents. */
1680 if (0
1681 && XtClass (widget) == xmDialogShellWidgetClass)
1683 destroyed_instance* dead_instance =
1684 make_destroyed_instance (instance->info->name,
1685 instance->info->type,
1686 instance->widget,
1687 instance->parent,
1688 instance->pop_up_p);
1689 dead_instance->next = all_destroyed_instances;
1690 all_destroyed_instances = dead_instance;
1691 XtUnmanageChild (first_child (instance->widget));
1692 XFlush (XtDisplay (instance->widget));
1693 XtAddCallback (instance->parent, XtNdestroyCallback,
1694 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1696 else
1698 /* This might not be necessary now that the nosel is attached to
1699 popdown instead of destroy, but it can't hurt. */
1700 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1701 xm_nosel_callback, (XtPointer)instance);
1702 XtDestroyWidget (instance->widget);
1706 \f/* popup utility */
1707 void
1708 xm_popup_menu (Widget widget, XEvent *event)
1710 XButtonPressedEvent dummy;
1712 if (event == 0)
1714 dummy.type = ButtonPress;
1715 dummy.serial = 0;
1716 dummy.send_event = 0;
1717 dummy.display = XtDisplay (widget);
1718 dummy.window = XtWindow (XtParent (widget));
1719 dummy.time = 0;
1720 dummy.button = 0;
1721 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1722 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1723 &dummy.x, &dummy.y, &dummy.state);
1724 event = (XEvent *) &dummy;
1727 if (event->type == ButtonPress || event->type == ButtonRelease)
1729 /* Setting the menuPost resource only required by Motif 1.1 and
1730 LessTif 0.84 and earlier. With later versions of LessTif,
1731 setting menuPost is unnecessary and may cause problems, so
1732 don't do it. */
1733 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
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);
1747 #endif
1749 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1752 XtManageChild (widget);
1755 static void
1756 set_min_dialog_size (Widget w)
1758 short width;
1759 short height;
1760 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1761 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1764 void
1765 xm_pop_instance (widget_instance* instance, Boolean up)
1767 Widget widget = instance->widget;
1769 if (XtClass (widget) == xmDialogShellWidgetClass)
1771 Widget widget_to_manage = first_child (widget);
1772 if (up)
1774 XtManageChild (widget_to_manage);
1775 set_min_dialog_size (widget);
1776 XtSetKeyboardFocus (instance->parent, widget);
1778 else
1779 XtUnmanageChild (widget_to_manage);
1781 else
1783 if (up)
1784 XtManageChild (widget);
1785 else
1786 XtUnmanageChild (widget);
1791 /* motif callback */
1793 static void
1794 do_call (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);
1820 switch (type)
1822 case pre_activate:
1823 if (instance->info->pre_activate_cb)
1824 instance->info->pre_activate_cb (widget, id, user_data);
1825 break;
1827 case selection:
1828 if (instance->info->selection_cb)
1829 instance->info->selection_cb (widget, id, user_data);
1830 break;
1832 case no_selection:
1833 if (instance->info->selection_cb)
1834 instance->info->selection_cb (widget, id, (XtPointer) -1);
1835 break;
1837 case post_activate:
1838 if (instance->info->post_activate_cb)
1839 instance->info->post_activate_cb (widget, id, user_data);
1840 break;
1842 default:
1843 abort ();
1847 /* Like lw_internal_update_other_instances except that it does not do
1848 anything if its shell parent is not managed. This is to protect
1849 lw_internal_update_other_instances to dereference freed memory
1850 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1851 list */
1852 static void
1853 xm_internal_update_other_instances (Widget widget,
1854 XtPointer closure,
1855 XtPointer call_data)
1857 Widget parent;
1858 for (parent = widget; parent; parent = XtParent (parent))
1859 if (XtIsShell (parent))
1860 break;
1861 else if (!XtIsManaged (parent))
1862 return;
1863 lw_internal_update_other_instances (widget, closure, call_data);
1866 static void
1867 xm_generic_callback (Widget widget,
1868 XtPointer closure,
1869 XtPointer call_data)
1871 lw_internal_update_other_instances (widget, closure, call_data);
1872 do_call (widget, closure, selection);
1875 static void
1876 xm_nosel_callback (Widget widget,
1877 XtPointer closure,
1878 XtPointer call_data)
1880 /* This callback is only called when a dialog box is dismissed with
1881 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1882 box to be destroyed in that case, not just unmapped, so that it
1883 releases its keyboard grabs. But there are problems with running
1884 our callbacks while the widget is in the process of being
1885 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1886 XmDESTROY and then destroy it ourself after having run the
1887 callback. */
1888 do_call (widget, closure, no_selection);
1889 XtDestroyWidget (widget);
1892 static void
1893 xm_pull_down_callback (Widget widget,
1894 XtPointer closure,
1895 XtPointer call_data)
1897 Widget parent = XtParent (widget);
1899 if (XmIsRowColumn (parent))
1901 unsigned char type = 0xff;
1902 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1903 if (type == XmMENU_BAR)
1904 do_call (widget, closure, pre_activate);
1909 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1910 CLOSURE is a pointer to the widget_instance of the shell,
1912 Note that this callback is called for each cascade button in a
1913 menu, whether or not its submenu is visible. */
1915 static void
1916 xm_pop_down_callback (Widget widget,
1917 XtPointer closure,
1918 XtPointer call_data)
1920 widget_instance *instance = (widget_instance *) closure;
1922 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1923 || XtParent (widget) == instance->parent)
1924 do_call (widget, closure, post_activate);
1928 /* set the keyboard focus */
1929 void
1930 xm_set_keyboard_focus (Widget parent, Widget w)
1932 XmProcessTraversal (w, 0);
1933 XtSetKeyboardFocus (parent, w);
1936 /* Motif hack to set the main window areas. */
1937 void
1938 xm_set_main_areas (Widget parent,
1939 Widget menubar,
1940 Widget work_area)
1942 XmMainWindowSetAreas (parent,
1943 menubar, /* menubar (maybe 0) */
1944 0, /* command area (psheets) */
1945 0, /* horizontal scroll */
1946 0, /* vertical scroll */
1947 work_area); /* work area */
1950 /* Motif hack to control resizing on the menubar. */
1951 void
1952 xm_manage_resizing (Widget w, Boolean flag)
1954 XtVaSetValues (w, XtNallowShellResize, flag, NULL);