*** empty log message ***
[emacs.git] / lwlib / lwlib-Xm.c
blob26aa9536c4067c117848bade0250a451fc010705
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
34 #include "../src/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 #if defined __STDC__ || defined PROTOTYPES
65 #define P_(X) X
66 #else
67 #define P_(X) ()
68 #endif
70 enum do_call_type { pre_activate, selection, no_selection, post_activate };
73 \f/* Structures to keep destroyed instances */
74 typedef struct _destroyed_instance
76 char* name;
77 char* type;
78 Widget widget;
79 Widget parent;
80 Boolean pop_up_p;
81 struct _destroyed_instance* next;
82 } destroyed_instance;
84 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
85 Widget, Widget,
86 Boolean));
87 static void free_destroyed_instance P_ ((destroyed_instance*));
88 Widget first_child P_ ((Widget));
89 Boolean lw_motif_widget_p P_ ((Widget));
90 static XmString resource_motif_string P_ ((Widget, char *));
91 static void destroy_all_children P_ ((Widget, int));
92 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
93 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
94 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
95 widget_value *));
96 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
97 widget_value *));
98 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
99 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
100 static void make_menu_in_widget P_ ((widget_instance *, Widget,
101 widget_value *, int));
102 static void update_one_menu_entry P_ ((widget_instance *, Widget,
103 widget_value *, Boolean));
104 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
105 Boolean));
106 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
107 static void xm_update_text_field P_ ((widget_instance *, Widget,
108 widget_value *));
109 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
110 static void activate_button P_ ((Widget, XtPointer, XtPointer));
111 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
112 Boolean, Boolean, Boolean, int, int));
113 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
114 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
115 static void recenter_widget P_ ((Widget));
116 static Widget recycle_instance P_ ((destroyed_instance*));
117 Widget xm_create_dialog P_ ((widget_instance*));
118 static Widget make_menubar P_ ((widget_instance*));
119 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
120 static Widget make_popup_menu P_ ((widget_instance*));
121 static Widget make_main P_ ((widget_instance*));
122 void xm_destroy_instance P_ ((widget_instance*));
123 void xm_popup_menu P_ ((Widget, XEvent *));
124 static void set_min_dialog_size P_ ((Widget));
125 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
126 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
129 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
130 void xm_set_keyboard_focus P_ ((Widget, Widget));
131 void xm_set_main_areas P_ ((Widget, Widget, Widget));
132 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
133 XtPointer));
134 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
136 #if 0
137 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
138 Boolean));
139 void xm_pop_instance P_ ((widget_instance*, Boolean));
140 void xm_manage_resizing P_ ((Widget, Boolean));
141 #endif
144 #if 0
146 /* Print the complete X resource name of widget WIDGET to stderr.
147 This is sometimes handy to have available. */
149 void
150 x_print_complete_resource_name (widget)
151 Widget widget;
153 int i;
154 String names[100];
156 for (i = 0; i < 100 && widget != NULL; ++i)
158 names[i] = XtName (widget);
159 widget = XtParent (widget);
162 for (--i; i >= 1; --i)
163 fprintf (stderr, "%s.", names[i]);
164 fprintf (stderr, "%s\n", names[0]);
167 #endif /* 0 */
170 static destroyed_instance *all_destroyed_instances = NULL;
172 static destroyed_instance*
173 make_destroyed_instance (name, type, widget, parent, pop_up_p)
174 char* name;
175 char* type;
176 Widget widget;
177 Widget parent;
178 Boolean pop_up_p;
180 destroyed_instance* instance =
181 (destroyed_instance*)malloc (sizeof (destroyed_instance));
182 instance->name = safe_strdup (name);
183 instance->type = safe_strdup (type);
184 instance->widget = widget;
185 instance->parent = parent;
186 instance->pop_up_p = pop_up_p;
187 instance->next = NULL;
188 return instance;
191 static void
192 free_destroyed_instance (instance)
193 destroyed_instance* instance;
195 free (instance->name);
196 free (instance->type);
197 free (instance);
200 \f/* motif utility functions */
201 Widget
202 first_child (widget)
203 Widget widget;
205 return ((CompositeWidget)widget)->composite.children [0];
208 Boolean
209 lw_motif_widget_p (widget)
210 Widget widget;
212 return
213 XtClass (widget) == xmDialogShellWidgetClass
214 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
217 static XmString
218 resource_motif_string (widget, name)
219 Widget widget;
220 char* name;
222 XtResource resource;
223 XmString result = 0;
225 resource.resource_name = name;
226 resource.resource_class = XmCXmString;
227 resource.resource_type = XmRXmString;
228 resource.resource_size = sizeof (XmString);
229 resource.resource_offset = 0;
230 resource.default_type = XtRImmediate;
231 resource.default_addr = 0;
233 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
234 "DialogString", &resource, 1, NULL, 0);
235 return result;
238 /* Destroy all of the children of WIDGET
239 starting with number FIRST_CHILD_TO_DESTROY. */
241 static void
242 destroy_all_children (widget, first_child_to_destroy)
243 Widget widget;
244 int first_child_to_destroy;
246 Widget* children;
247 unsigned int number;
248 int i;
250 children = XtCompositeChildren (widget, &number);
251 if (children)
253 XtUnmanageChildren (children + first_child_to_destroy,
254 number - first_child_to_destroy);
256 /* Unmanage all children and destroy them. They will only be
257 really destroyed when we get out of DispatchEvent. */
258 for (i = first_child_to_destroy; i < number; i++)
260 Arg al[2];
261 Widget submenu = 0;
262 /* Cascade buttons have submenus,and these submenus
263 need to be freed. But they are not included in
264 XtCompositeChildren. So get it out of the cascade button
265 and free it. If this child is not a cascade button,
266 then submenu should remain unchanged. */
267 XtSetArg (al[0], XmNsubMenuId, &submenu);
268 XtGetValues (children[i], al, 1);
269 if (submenu)
270 XtDestroyWidget (submenu);
271 XtDestroyWidget (children[i]);
274 XtFree ((char *) children);
280 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
281 menu. CLIENT_DATA contains a pointer to the widget_value
282 corresponding to widget W. CALL_DATA contains a
283 XmPushButtonCallbackStruct containing the reason why the callback
284 is called. */
286 static void
287 xm_arm_callback (w, client_data, call_data)
288 Widget w;
289 XtPointer client_data, call_data;
291 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
292 widget_value *wv = (widget_value *) client_data;
293 widget_instance *instance;
295 /* Get the id of the menu bar or popup menu this widget is in. */
296 while (w != NULL)
298 if (XmIsRowColumn (w))
300 unsigned char type = 0xff;
302 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
303 if (type == XmMENU_BAR || type == XmMENU_POPUP)
304 break;
307 w = XtParent (w);
310 if (w != NULL)
312 instance = lw_get_widget_instance (w);
313 if (instance && instance->info->highlight_cb)
315 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
316 instance->info->highlight_cb (w, instance->info->id, call_data);
323 /* Update the label of widget WIDGET. WIDGET must be a Label widget
324 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
325 the value to update.
327 Menus:
329 Emacs fills VAL->name with the text to display in the menu, and
330 sets VAL->value to null. Function make_menu_in_widget creates
331 widgets with VAL->name as resource name. This works because the
332 Label widget uses its resource name for display if no
333 XmNlabelString is set.
335 Dialogs:
337 VAL->name is again set to the resource name, but VAL->value is
338 not null, and contains the label string to display. */
340 static void
341 xm_update_label (instance, widget, val)
342 widget_instance* instance;
343 Widget widget;
344 widget_value* val;
346 XmString res_string = 0;
347 XmString built_string = 0;
348 XmString key_string = 0;
349 Arg al [256];
350 int ac;
352 ac = 0;
354 if (val->value)
356 /* A label string is specified, i.e. we are in a dialog. First
357 see if it is overridden by something from the resource file. */
358 res_string = resource_motif_string (widget, val->value);
360 if (res_string)
362 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
364 else
366 built_string =
367 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
368 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
371 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
374 if (val->key)
376 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
377 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
380 if (ac)
381 XtSetValues (widget, al, ac);
383 if (built_string)
384 XmStringFree (built_string);
386 if (key_string)
387 XmStringFree (key_string);
390 \f/* update of list */
391 static void
392 xm_update_list (instance, widget, val)
393 widget_instance* instance;
394 Widget widget;
395 widget_value* val;
397 widget_value* cur;
398 int i;
399 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
400 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
401 instance);
402 for (cur = val->contents, i = 0; cur; cur = cur->next)
403 if (cur->value)
405 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
406 i += 1;
407 XmListAddItem (widget, xmstr, 0);
408 if (cur->selected)
409 XmListSelectPos (widget, i, False);
410 XmStringFree (xmstr);
414 \f/* update of buttons */
415 static void
416 xm_update_pushbutton (instance, widget, val)
417 widget_instance* instance;
418 Widget widget;
419 widget_value* val;
421 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
422 XtRemoveAllCallbacks (widget, XmNactivateCallback);
423 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
426 static void
427 xm_update_cascadebutton (instance, widget, val)
428 widget_instance* instance;
429 Widget widget;
430 widget_value* val;
432 /* Should also rebuild the menu by calling ...update_menu... */
433 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
434 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
435 instance);
438 \f/* update toggle and radiobox */
439 static void
440 xm_update_toggle (instance, widget, val)
441 widget_instance* instance;
442 Widget widget;
443 widget_value* val;
445 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
446 XtAddCallback (widget, XmNvalueChangedCallback,
447 xm_generic_callback, instance);
448 XtVaSetValues (widget, XmNset, val->selected,
449 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
452 static void
453 xm_update_radiobox (instance, widget, val)
454 widget_instance* instance;
455 Widget widget;
456 widget_value* val;
459 Widget toggle;
460 widget_value* cur;
462 /* update the callback */
463 XtRemoveAllCallbacks (widget, XmNentryCallback);
464 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
466 /* first update all the toggles */
467 /* Energize kernel interface is currently bad. It sets the selected widget
468 with the selected flag but returns it by its name. So we currently
469 have to support both setting the selection with the selected slot
470 of val contents and setting it with the "value" slot of val. The latter
471 has a higher priority. This to be removed when the kernel is fixed. */
472 for (cur = val->contents; cur; cur = cur->next)
474 toggle = XtNameToWidget (widget, cur->value);
475 if (toggle)
477 XtSetSensitive (toggle, cur->enabled);
478 if (!val->value && cur->selected)
479 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
480 if (val->value && strcmp (val->value, cur->value))
481 XtVaSetValues (toggle, XmNset, False, NULL);
485 /* The selected was specified by the value slot */
486 if (val->value)
488 toggle = XtNameToWidget (widget, val->value);
489 if (toggle)
490 XtVaSetValues (toggle, XmNset, True, NULL);
495 /* update a popup menu, pulldown menu or a menubar */
497 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
499 static void
500 make_menu_in_widget (instance, widget, val, keep_first_children)
501 widget_instance* instance;
502 Widget widget;
503 widget_value* val;
504 int keep_first_children;
506 Widget* children = 0;
507 int num_children;
508 int child_index;
509 widget_value* cur;
510 Widget button = 0;
511 Widget title = 0;
512 Widget menu;
513 Arg al [256];
514 int ac;
515 Boolean menubar_p;
516 unsigned char type;
518 Widget* old_children;
519 unsigned int old_num_children;
521 old_children = XtCompositeChildren (widget, &old_num_children);
523 /* Allocate the children array */
524 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
526 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
528 /* WIDGET should be a RowColumn. */
529 if (!XmIsRowColumn (widget))
530 abort ();
532 /* Determine whether WIDGET is a menu bar. */
533 type = -1;
534 XtSetArg (al[0], XmNrowColumnType, &type);
535 XtGetValues (widget, al, 1);
536 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
537 abort ();
538 menubar_p = type == XmMENU_BAR;
540 /* Add a callback to popups and pulldowns that is called when
541 it is made invisible again. */
542 if (!menubar_p)
543 XtAddCallback (XtParent (widget), XmNpopdownCallback,
544 xm_pop_down_callback, (XtPointer)instance);
546 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
547 for (child_index = 0, cur = val; child_index < keep_first_children;
548 child_index++, cur = cur->next)
549 children[child_index] = old_children[child_index];
551 /* Check that those are all we have
552 (the caller should have deleted the rest). */
553 if (old_num_children != keep_first_children)
554 abort ();
556 /* Create the rest. */
557 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
559 enum menu_separator separator;
561 ac = 0;
562 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
563 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
564 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
566 if (instance->pop_up_p && !cur->contents && !cur->call_data
567 && !lw_separator_p (cur->name, &separator, 1))
569 ac = 0;
570 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
571 title = button = XmCreateLabel (widget, cur->name, al, ac);
573 else if (lw_separator_p (cur->name, &separator, 1))
575 ac = 0;
576 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
577 button = XmCreateSeparator (widget, cur->name, al, ac);
579 else if (!cur->contents)
581 if (menubar_p)
582 button = XmCreateCascadeButton (widget, cur->name, al, ac);
583 else if (!cur->call_data)
584 button = XmCreateLabel (widget, cur->name, al, ac);
585 else if (cur->button_type == BUTTON_TYPE_TOGGLE
586 || cur->button_type == BUTTON_TYPE_RADIO)
588 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
589 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
590 XtSetArg (al[ac], XmNindicatorType,
591 (cur->button_type == BUTTON_TYPE_TOGGLE
592 ? XmN_OF_MANY : XmONE_OF_MANY));
593 ++ac;
594 button = XmCreateToggleButton (widget, cur->name, al, ac);
595 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
596 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
598 else
600 button = XmCreatePushButton (widget, cur->name, al, ac);
601 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
602 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
605 xm_update_label (instance, button, cur);
607 /* Add a callback that is called when the button is
608 selected. Toggle buttons don't support
609 XmNactivateCallback, we use XmNvalueChangedCallback in
610 that case. Don't add a callback to a simple label. */
611 if (cur->button_type)
612 xm_update_toggle (instance, button, cur);
613 else if (cur->call_data)
614 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
615 (XtPointer)instance);
617 else
619 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
621 make_menu_in_widget (instance, menu, cur->contents, 0);
622 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
623 button = XmCreateCascadeButton (widget, cur->name, al, ac);
625 xm_update_label (instance, button, cur);
627 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
628 (XtPointer)instance);
631 children[child_index] = button;
634 /* Last entry is the help button. The original comment read "Has to
635 be done after managing the buttons otherwise the menubar is only
636 4 pixels high." This is no longer true, and to make
637 XmNmenuHelpWidget work, we need to set it before managing the
638 children.. --gerd. */
639 if (button)
640 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
642 if (num_children)
643 XtManageChildren (children, num_children);
645 XtFree ((char *) children);
646 if (old_children)
647 XtFree ((char *) old_children);
650 static void
651 update_one_menu_entry (instance, widget, val, deep_p)
652 widget_instance* instance;
653 Widget widget;
654 widget_value* val;
655 Boolean deep_p;
657 Arg al [256];
658 int ac;
659 Widget menu;
660 widget_value* contents;
662 if (val->this_one_change == NO_CHANGE)
663 return;
665 /* update the sensitivity and userdata */
666 /* Common to all widget types */
667 XtSetSensitive (widget, val->enabled);
668 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
670 /* update the menu button as a label. */
671 if (val->this_one_change >= VISIBLE_CHANGE)
673 xm_update_label (instance, widget, val);
674 if (val->button_type)
675 xm_update_toggle (instance, widget, val);
678 /* update the pulldown/pullaside as needed */
679 ac = 0;
680 menu = NULL;
681 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
682 XtGetValues (widget, al, ac);
684 contents = val->contents;
686 if (!menu)
688 if (contents)
690 unsigned int old_num_children, i;
691 Widget parent;
692 Widget *widget_list;
694 parent = XtParent (widget);
695 widget_list = XtCompositeChildren (parent, &old_num_children);
697 /* Find the widget position within the parent's widget list. */
698 for (i = 0; i < old_num_children; i++)
699 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
700 break;
701 if (i == old_num_children)
702 abort ();
703 if (XmIsCascadeButton (widget_list[i]))
705 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
706 make_menu_in_widget (instance, menu, contents, 0);
707 ac = 0;
708 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
709 XtSetValues (widget, al, ac);
711 else
713 Widget button;
715 /* The current menuitem is a XmPushButtonGadget, it
716 needs to be replaced by a CascadeButtonGadget */
717 XtDestroyWidget (widget_list[i]);
718 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
719 make_menu_in_widget (instance, menu, contents, 0);
720 ac = 0;
721 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
722 /* Non-zero values don't work reliably in
723 conjunction with Emacs' event loop */
724 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
725 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
726 /* Tell Motif to put it in the right place */
727 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
728 #endif
729 button = XmCreateCascadeButton (parent, val->name, al, ac);
730 xm_update_label (instance, button, val);
732 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
733 (XtPointer)instance);
734 XtManageChild (button);
738 else if (!contents)
740 ac = 0;
741 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
742 XtSetValues (widget, al, ac);
743 XtDestroyWidget (menu);
745 else if (deep_p && contents->change != NO_CHANGE)
746 xm_update_menu (instance, menu, val, 1);
749 static void
750 xm_update_menu (instance, widget, val, deep_p)
751 widget_instance* instance;
752 Widget widget;
753 widget_value* val;
754 Boolean deep_p;
756 Widget* children;
757 unsigned int num_children;
758 int num_children_to_keep = 0;
759 int i;
760 widget_value* cur;
762 children = XtCompositeChildren (widget, &num_children);
764 /* Widget is a RowColumn widget whose contents have to be updated
765 * to reflect the list of items in val->contents */
767 /* See how many buttons we can keep, and how many we
768 must completely replace. */
769 if (val->contents == 0)
770 num_children_to_keep = 0;
771 else if (val->contents->change == STRUCTURAL_CHANGE)
773 if (children)
775 for (i = 0, cur = val->contents;
776 (i < num_children
777 && cur); /* how else to ditch unwanted children ?? - mgd */
778 i++, cur = cur->next)
780 if (cur->this_one_change == STRUCTURAL_CHANGE)
781 break;
784 num_children_to_keep = i;
787 else
788 num_children_to_keep = num_children;
790 /* Update all the buttons of the RowColumn, in order,
791 except for those we are going to replace entirely. */
792 if (children)
794 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
796 if (!cur)
798 num_children_to_keep = i;
799 break;
801 if (children [i]->core.being_destroyed
802 || strcmp (XtName (children [i]), cur->name))
803 continue;
804 update_one_menu_entry (instance, children [i], cur, deep_p);
805 cur = cur->next;
809 /* Now replace from scratch all the buttons after the last
810 place that the top-level structure changed. */
811 if (val->contents->change == STRUCTURAL_CHANGE)
813 destroy_all_children (widget, num_children_to_keep);
814 make_menu_in_widget (instance, widget, val->contents,
815 num_children_to_keep);
818 XtFree ((char *) children);
822 /* update text widgets */
824 static void
825 xm_update_text (instance, widget, val)
826 widget_instance* instance;
827 Widget widget;
828 widget_value* val;
830 XmTextSetString (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);
838 static void
839 xm_update_text_field (instance, widget, val)
840 widget_instance* instance;
841 Widget widget;
842 widget_value* val;
844 XmTextFieldSetString (widget, val->value ? val->value : "");
845 XtRemoveAllCallbacks (widget, XmNactivateCallback);
846 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
847 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
848 XtAddCallback (widget, XmNvalueChangedCallback,
849 xm_internal_update_other_instances, instance);
853 /* update a motif widget */
855 void
856 xm_update_one_widget (instance, widget, val, deep_p)
857 widget_instance* instance;
858 Widget widget;
859 widget_value* val;
860 Boolean deep_p;
862 WidgetClass class;
864 /* Mark as not edited */
865 val->edited = False;
867 /* Common to all widget types */
868 XtSetSensitive (widget, val->enabled);
869 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
871 /* Common to all label like widgets */
872 if (XtIsSubclass (widget, xmLabelWidgetClass))
873 xm_update_label (instance, widget, val);
875 class = XtClass (widget);
876 /* Class specific things */
877 if (class == xmPushButtonWidgetClass ||
878 class == xmArrowButtonWidgetClass)
880 xm_update_pushbutton (instance, widget, val);
882 else if (class == xmCascadeButtonWidgetClass)
884 xm_update_cascadebutton (instance, widget, val);
886 else if (class == xmToggleButtonWidgetClass
887 || class == xmToggleButtonGadgetClass)
889 xm_update_toggle (instance, widget, val);
891 else if (class == xmRowColumnWidgetClass)
893 Boolean radiobox = 0;
894 int ac = 0;
895 Arg al [1];
897 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
898 XtGetValues (widget, al, ac);
900 if (radiobox)
901 xm_update_radiobox (instance, widget, val);
902 else
903 xm_update_menu (instance, widget, val, deep_p);
905 else if (class == xmTextWidgetClass)
907 xm_update_text (instance, widget, val);
909 else if (class == xmTextFieldWidgetClass)
911 xm_update_text_field (instance, widget, val);
913 else if (class == xmListWidgetClass)
915 xm_update_list (instance, widget, val);
919 \f/* getting the value back */
920 void
921 xm_update_one_value (instance, widget, val)
922 widget_instance* instance;
923 Widget widget;
924 widget_value* val;
926 WidgetClass class = XtClass (widget);
927 widget_value *old_wv;
929 /* copy the call_data slot into the "return" widget_value */
930 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
931 if (!strcmp (val->name, old_wv->name))
933 val->call_data = old_wv->call_data;
934 break;
937 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
939 XtVaGetValues (widget, XmNset, &val->selected, NULL);
940 val->edited = True;
942 else if (class == xmTextWidgetClass)
944 if (val->value)
945 free (val->value);
946 val->value = XmTextGetString (widget);
947 val->edited = True;
949 else if (class == xmTextFieldWidgetClass)
951 if (val->value)
952 free (val->value);
953 val->value = XmTextFieldGetString (widget);
954 val->edited = True;
956 else if (class == xmRowColumnWidgetClass)
958 Boolean radiobox = 0;
959 int ac = 0;
960 Arg al [1];
962 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
963 XtGetValues (widget, al, ac);
965 if (radiobox)
967 CompositeWidget radio = (CompositeWidget)widget;
968 int i;
969 for (i = 0; i < radio->composite.num_children; i++)
971 int set = False;
972 Widget toggle = radio->composite.children [i];
974 XtVaGetValues (toggle, XmNset, &set, NULL);
975 if (set)
977 if (val->value)
978 free (val->value);
979 val->value = safe_strdup (XtName (toggle));
982 val->edited = True;
985 else if (class == xmListWidgetClass)
987 int pos_cnt;
988 int* pos_list;
989 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
991 int i;
992 widget_value* cur;
993 for (cur = val->contents, i = 0; cur; cur = cur->next)
994 if (cur->value)
996 int j;
997 cur->selected = False;
998 i += 1;
999 for (j = 0; j < pos_cnt; j++)
1000 if (pos_list [j] == i)
1002 cur->selected = True;
1003 val->value = safe_strdup (cur->name);
1006 val->edited = 1;
1007 XtFree ((char *) pos_list);
1013 /* This function is for activating a button from a program. It's wrong because
1014 we pass a NULL argument in the call_data which is not Motif compatible.
1015 This is used from the XmNdefaultAction callback of the List widgets to
1016 have a double-click put down a dialog box like the button would do.
1017 I could not find a way to do that with accelerators.
1019 static void
1020 activate_button (widget, closure, call_data)
1021 Widget widget;
1022 XtPointer closure;
1023 XtPointer call_data;
1025 Widget button = (Widget)closure;
1026 XtCallCallbacks (button, XmNactivateCallback, NULL);
1029 /* creation functions */
1031 /* dialogs */
1032 static Widget
1033 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1034 radio_box, list, left_buttons, right_buttons)
1035 char* name;
1036 Widget parent;
1037 Boolean pop_up_p;
1038 char* shell_title;
1039 char* icon_name;
1040 Boolean text_input_slot;
1041 Boolean radio_box;
1042 Boolean list;
1043 int left_buttons;
1044 int right_buttons;
1046 Widget result;
1047 Widget form;
1048 Widget row;
1049 Widget icon;
1050 Widget icon_separator;
1051 Widget message;
1052 Widget value = 0;
1053 Widget separator;
1054 Widget button = 0;
1055 Widget children [16]; /* for the final XtManageChildren */
1056 int n_children;
1057 Arg al[64]; /* Arg List */
1058 int ac; /* Arg Count */
1059 int i;
1061 if (pop_up_p)
1063 ac = 0;
1064 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1065 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1066 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1067 result = XmCreateDialogShell (parent, "dialog", al, ac);
1068 ac = 0;
1069 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1070 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1071 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1072 form = XmCreateForm (result, shell_title, al, ac);
1074 else
1076 ac = 0;
1077 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1078 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1079 form = XmCreateForm (parent, shell_title, al, ac);
1080 result = form;
1083 n_children = left_buttons + right_buttons + 1;
1084 ac = 0;
1085 XtSetArg(al[ac], XmNpacking, n_children == 3?
1086 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1087 XtSetArg(al[ac], XmNorientation, n_children == 3?
1088 XmVERTICAL: XmHORIZONTAL); ac++;
1089 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1090 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1091 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1092 XtSetArg(al[ac], XmNspacing, 13); ac++;
1093 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1094 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1095 XtSetArg(al[ac], XmNisAligned, True); ac++;
1096 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1097 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1098 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1099 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1100 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1101 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1102 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1103 row = XmCreateRowColumn (form, "row", al, ac);
1105 n_children = 0;
1106 for (i = 0; i < left_buttons; i++)
1108 char button_name [16];
1109 sprintf (button_name, "button%d", i + 1);
1110 ac = 0;
1111 if (i == 0)
1113 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1114 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1116 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1117 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1118 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1120 if (i == 0)
1122 button = children [n_children];
1123 ac = 0;
1124 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1125 XtSetValues (row, al, ac);
1128 n_children++;
1131 /* invisible separator button */
1132 ac = 0;
1133 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1134 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1135 n_children++;
1137 for (i = 0; i < right_buttons; i++)
1139 char button_name [16];
1140 sprintf (button_name, "button%d", left_buttons + i + 1);
1141 ac = 0;
1142 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1143 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1144 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1145 if (! button) button = children [n_children];
1146 n_children++;
1149 XtManageChildren (children, n_children);
1151 ac = 0;
1152 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1153 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1154 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1155 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1156 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1157 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1158 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1159 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1160 separator = XmCreateSeparator (form, "", al, ac);
1162 ac = 0;
1163 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1164 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1165 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1166 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1167 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1168 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1169 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1170 icon = XmCreateLabel (form, icon_name, al, ac);
1172 ac = 0;
1173 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1174 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1175 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1176 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1177 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1178 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1179 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1180 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1181 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1182 icon_separator = XmCreateLabel (form, "", al, ac);
1184 if (text_input_slot)
1186 ac = 0;
1187 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1188 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1189 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1190 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1191 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1192 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1193 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1194 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1195 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1196 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1197 value = XmCreateTextField (form, "value", al, ac);
1199 else if (radio_box)
1201 Widget radio_butt;
1202 ac = 0;
1203 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1204 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1205 XtSetArg(al[ac], XmNspacing, 13); ac++;
1206 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1207 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1208 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1209 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1210 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1211 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1212 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1213 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1214 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1215 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1216 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1217 ac = 0;
1218 i = 0;
1219 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1220 children [i++] = radio_butt;
1221 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1222 children [i++] = radio_butt;
1223 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1224 children [i++] = radio_butt;
1225 XtManageChildren (children, i);
1227 else if (list)
1229 ac = 0;
1230 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1231 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1232 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1233 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1234 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1235 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1236 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1237 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1238 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1239 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1240 value = XmCreateScrolledList (form, "list", al, ac);
1242 /* this is the easiest way I found to have the dble click in the
1243 list activate the default button */
1244 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1247 ac = 0;
1248 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1249 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1250 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1251 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1252 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1253 XtSetArg(al[ac], XmNbottomWidget,
1254 text_input_slot || radio_box || list ? value : separator); ac++;
1255 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1256 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1257 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1258 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1259 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1260 message = XmCreateLabel (form, "message", al, ac);
1262 if (list)
1263 XtManageChild (value);
1265 i = 0;
1266 children [i] = row; i++;
1267 children [i] = separator; i++;
1268 if (text_input_slot || radio_box)
1270 children [i] = value; i++;
1272 children [i] = message; i++;
1273 children [i] = icon; i++;
1274 children [i] = icon_separator; i++;
1275 XtManageChildren (children, i);
1277 if (text_input_slot || list)
1279 XtInstallAccelerators (value, button);
1280 XtSetKeyboardFocus (result, value);
1282 else
1284 XtInstallAccelerators (form, button);
1285 XtSetKeyboardFocus (result, button);
1288 return result;
1291 static destroyed_instance*
1292 find_matching_instance (instance)
1293 widget_instance* instance;
1295 destroyed_instance* cur;
1296 destroyed_instance* prev;
1297 char* type = instance->info->type;
1298 char* name = instance->info->name;
1300 for (prev = NULL, cur = all_destroyed_instances;
1301 cur;
1302 prev = cur, cur = cur->next)
1304 if (!strcmp (cur->name, name)
1305 && !strcmp (cur->type, type)
1306 && cur->parent == instance->parent
1307 && cur->pop_up_p == instance->pop_up_p)
1309 if (prev)
1310 prev->next = cur->next;
1311 else
1312 all_destroyed_instances = cur->next;
1313 return cur;
1315 /* do some cleanup */
1316 else if (!cur->widget)
1318 if (prev)
1319 prev->next = cur->next;
1320 else
1321 all_destroyed_instances = cur->next;
1322 free_destroyed_instance (cur);
1323 cur = prev ? prev : all_destroyed_instances;
1326 return NULL;
1329 static void
1330 mark_dead_instance_destroyed (widget, closure, call_data)
1331 Widget widget;
1332 XtPointer closure;
1333 XtPointer call_data;
1335 destroyed_instance* instance = (destroyed_instance*)closure;
1336 instance->widget = NULL;
1339 static void
1340 recenter_widget (widget)
1341 Widget widget;
1343 Widget parent = XtParent (widget);
1344 Screen* screen = XtScreen (widget);
1345 Dimension screen_width = WidthOfScreen (screen);
1346 Dimension screen_height = HeightOfScreen (screen);
1347 Dimension parent_width = 0;
1348 Dimension parent_height = 0;
1349 Dimension child_width = 0;
1350 Dimension child_height = 0;
1351 Position x;
1352 Position y;
1354 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1355 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1356 NULL);
1358 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1359 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1361 XtTranslateCoords (parent, x, y, &x, &y);
1363 if (x + child_width > screen_width)
1364 x = screen_width - child_width;
1365 if (x < 0)
1366 x = 0;
1368 if (y + child_height > screen_height)
1369 y = screen_height - child_height;
1370 if (y < 0)
1371 y = 0;
1373 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1376 static Widget
1377 recycle_instance (instance)
1378 destroyed_instance* instance;
1380 Widget widget = instance->widget;
1382 /* widget is NULL if the parent was destroyed. */
1383 if (widget)
1385 Widget focus;
1386 Widget separator;
1388 /* Remove the destroy callback as the instance is not in the list
1389 anymore */
1390 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1391 mark_dead_instance_destroyed,
1392 (XtPointer)instance);
1394 /* Give the focus to the initial item */
1395 focus = XtNameToWidget (widget, "*value");
1396 if (!focus)
1397 focus = XtNameToWidget (widget, "*button1");
1398 if (focus)
1399 XtSetKeyboardFocus (widget, focus);
1401 /* shrink the separator label back to their original size */
1402 separator = XtNameToWidget (widget, "*separator_button");
1403 if (separator)
1404 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1406 /* Center the dialog in its parent */
1407 recenter_widget (widget);
1409 free_destroyed_instance (instance);
1410 return widget;
1413 Widget
1414 xm_create_dialog (instance)
1415 widget_instance* instance;
1417 char* name = instance->info->type;
1418 Widget parent = instance->parent;
1419 Widget widget;
1420 Boolean pop_up_p = instance->pop_up_p;
1421 char* shell_name = 0;
1422 char* icon_name = 0;
1423 Boolean text_input_slot = False;
1424 Boolean radio_box = False;
1425 Boolean list = False;
1426 int total_buttons;
1427 int left_buttons = 0;
1428 int right_buttons = 1;
1429 destroyed_instance* dead_one;
1431 /* try to find a widget to recycle */
1432 dead_one = find_matching_instance (instance);
1433 if (dead_one)
1435 Widget recycled_widget = recycle_instance (dead_one);
1436 if (recycled_widget)
1437 return recycled_widget;
1440 switch (name [0]){
1441 case 'E': case 'e':
1442 icon_name = "dbox-error";
1443 shell_name = "Error";
1444 break;
1446 case 'I': case 'i':
1447 icon_name = "dbox-info";
1448 shell_name = "Information";
1449 break;
1451 case 'L': case 'l':
1452 list = True;
1453 icon_name = "dbox-question";
1454 shell_name = "Prompt";
1455 break;
1457 case 'P': case 'p':
1458 text_input_slot = True;
1459 icon_name = "dbox-question";
1460 shell_name = "Prompt";
1461 break;
1463 case 'Q': case 'q':
1464 icon_name = "dbox-question";
1465 shell_name = "Question";
1466 break;
1469 total_buttons = name [1] - '0';
1471 if (name [3] == 'T' || name [3] == 't')
1473 text_input_slot = False;
1474 radio_box = True;
1476 else if (name [3])
1477 right_buttons = name [4] - '0';
1479 left_buttons = total_buttons - right_buttons;
1481 widget = make_dialog (name, parent, pop_up_p,
1482 shell_name, icon_name, text_input_slot, radio_box,
1483 list, left_buttons, right_buttons);
1485 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1486 (XtPointer) instance);
1487 return widget;
1490 /* Create a menu bar. We turn off the f10 key
1491 because we have not yet managed to make it work right in Motif. */
1493 static Widget
1494 make_menubar (instance)
1495 widget_instance* instance;
1497 Arg al[3];
1498 int ac;
1500 ac = 0;
1501 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1502 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1505 static void
1506 remove_grabs (shell, closure, call_data)
1507 Widget shell;
1508 XtPointer closure;
1509 XtPointer call_data;
1511 Widget menu = (Widget) closure;
1512 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1515 static Widget
1516 make_popup_menu (instance)
1517 widget_instance* instance;
1519 Widget parent = instance->parent;
1520 Window parent_window = parent->core.window;
1521 Widget result;
1523 /* sets the parent window to 0 to fool Motif into not generating a grab */
1524 parent->core.window = 0;
1525 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1526 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1527 (XtPointer)result);
1528 parent->core.window = parent_window;
1529 return result;
1532 static Widget
1533 make_main (instance)
1534 widget_instance* instance;
1536 Widget parent = instance->parent;
1537 Widget result;
1538 Arg al[2];
1539 int ac;
1541 ac = 0;
1542 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1543 XtSetArg (al[ac], XmNspacing, 0); ac++;
1544 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1545 return result;
1548 \f/* Table of functions to create widgets */
1550 #ifdef ENERGIZE
1552 /* interface with the XDesigner generated functions */
1553 typedef Widget (*widget_maker) (Widget);
1554 extern Widget create_project_p_sheet (Widget parent);
1555 extern Widget create_debugger_p_sheet (Widget parent);
1556 extern Widget create_breaklist_p_sheet (Widget parent);
1557 extern Widget create_le_browser_p_sheet (Widget parent);
1558 extern Widget create_class_browser_p_sheet (Widget parent);
1559 extern Widget create_call_browser_p_sheet (Widget parent);
1560 extern Widget create_build_dialog (Widget parent);
1561 extern Widget create_editmode_dialog (Widget parent);
1562 extern Widget create_search_dialog (Widget parent);
1563 extern Widget create_project_display_dialog (Widget parent);
1565 static Widget
1566 make_one (widget_instance* instance, widget_maker fn)
1568 Widget result;
1569 Arg al [64];
1570 int ac = 0;
1572 if (instance->pop_up_p)
1574 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1575 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1576 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1577 (XtPointer) instance);
1578 (*fn) (result);
1580 else
1582 result = (*fn) (instance->parent);
1583 XtRealizeWidget (result);
1585 return result;
1588 static Widget
1589 make_project_p_sheet (widget_instance* instance)
1591 return make_one (instance, create_project_p_sheet);
1594 static Widget
1595 make_debugger_p_sheet (widget_instance* instance)
1597 return make_one (instance, create_debugger_p_sheet);
1600 static Widget
1601 make_breaklist_p_sheet (widget_instance* instance)
1603 return make_one (instance, create_breaklist_p_sheet);
1606 static Widget
1607 make_le_browser_p_sheet (widget_instance* instance)
1609 return make_one (instance, create_le_browser_p_sheet);
1612 static Widget
1613 make_class_browser_p_sheet (widget_instance* instance)
1615 return make_one (instance, create_class_browser_p_sheet);
1618 static Widget
1619 make_call_browser_p_sheet (widget_instance* instance)
1621 return make_one (instance, create_call_browser_p_sheet);
1624 static Widget
1625 make_build_dialog (widget_instance* instance)
1627 return make_one (instance, create_build_dialog);
1630 static Widget
1631 make_editmode_dialog (widget_instance* instance)
1633 return make_one (instance, create_editmode_dialog);
1636 static Widget
1637 make_search_dialog (widget_instance* instance)
1639 return make_one (instance, create_search_dialog);
1642 static Widget
1643 make_project_display_dialog (widget_instance* instance)
1645 return make_one (instance, create_project_display_dialog);
1648 #endif /* ENERGIZE */
1650 widget_creation_entry
1651 xm_creation_table [] =
1653 {"menubar", make_menubar},
1654 {"popup", make_popup_menu},
1655 {"main", make_main},
1656 #ifdef ENERGIZE
1657 {"project_p_sheet", make_project_p_sheet},
1658 {"debugger_p_sheet", make_debugger_p_sheet},
1659 {"breaklist_psheet", make_breaklist_p_sheet},
1660 {"leb_psheet", make_le_browser_p_sheet},
1661 {"class_browser_psheet", make_class_browser_p_sheet},
1662 {"ctree_browser_psheet", make_call_browser_p_sheet},
1663 {"build", make_build_dialog},
1664 {"editmode", make_editmode_dialog},
1665 {"search", make_search_dialog},
1666 {"project_display", make_project_display_dialog},
1667 #endif /* ENERGIZE */
1668 {NULL, NULL}
1671 \f/* Destruction of instances */
1672 void
1673 xm_destroy_instance (instance)
1674 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, event)
1709 Widget widget;
1710 XEvent *event;
1712 XButtonPressedEvent dummy;
1714 if (event == 0)
1716 dummy.type = ButtonPress;
1717 dummy.serial = 0;
1718 dummy.send_event = 0;
1719 dummy.display = XtDisplay (widget);
1720 dummy.window = XtWindow (XtParent (widget));
1721 dummy.time = 0;
1722 dummy.button = 0;
1723 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1724 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1725 &dummy.x, &dummy.y, &dummy.state);
1726 event = (XEvent *) &dummy;
1729 if (event->type == ButtonPress || event->type == ButtonRelease)
1731 /* Setting the menuPost resource only required by Motif 1.1 and
1732 LessTif 0.84 and earlier. With later versions of LessTif,
1733 setting menuPost is unnecessary and may cause problems, so
1734 don't do it. */
1735 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1737 /* This is so totally ridiculous: there's NO WAY to tell Motif
1738 that *any* button can select a menu item. Only one button
1739 can have that honor. */
1741 char *trans = 0;
1742 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1743 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1744 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1745 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1746 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1747 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1749 #endif
1751 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1754 XtManageChild (widget);
1757 static void
1758 set_min_dialog_size (w)
1759 Widget w;
1761 short width;
1762 short height;
1763 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1764 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1767 void
1768 xm_pop_instance (instance, up)
1769 widget_instance* instance;
1770 Boolean up;
1772 Widget widget = instance->widget;
1774 if (XtClass (widget) == xmDialogShellWidgetClass)
1776 Widget widget_to_manage = first_child (widget);
1777 if (up)
1779 XtManageChild (widget_to_manage);
1780 set_min_dialog_size (widget);
1781 XtSetKeyboardFocus (instance->parent, widget);
1783 else
1784 XtUnmanageChild (widget_to_manage);
1786 else
1788 if (up)
1789 XtManageChild (widget);
1790 else
1791 XtUnmanageChild (widget);
1796 /* motif callback */
1798 static void
1799 do_call (widget, closure, type)
1800 Widget widget;
1801 XtPointer closure;
1802 enum do_call_type type;
1804 Arg al [256];
1805 int ac;
1806 XtPointer user_data;
1807 widget_instance* instance = (widget_instance*)closure;
1808 Widget instance_widget;
1809 LWLIB_ID id;
1811 if (!instance)
1812 return;
1813 if (widget->core.being_destroyed)
1814 return;
1816 instance_widget = instance->widget;
1817 if (!instance_widget)
1818 return;
1820 id = instance->info->id;
1821 ac = 0;
1822 user_data = NULL;
1823 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1824 XtGetValues (widget, al, ac);
1826 switch (type)
1828 case pre_activate:
1829 if (instance->info->pre_activate_cb)
1830 instance->info->pre_activate_cb (widget, id, user_data);
1831 break;
1833 case selection:
1834 if (instance->info->selection_cb)
1835 instance->info->selection_cb (widget, id, user_data);
1836 break;
1838 case no_selection:
1839 if (instance->info->selection_cb)
1840 instance->info->selection_cb (widget, id, (XtPointer) -1);
1841 break;
1843 case post_activate:
1844 if (instance->info->post_activate_cb)
1845 instance->info->post_activate_cb (widget, id, user_data);
1846 break;
1848 default:
1849 abort ();
1853 /* Like lw_internal_update_other_instances except that it does not do
1854 anything if its shell parent is not managed. This is to protect
1855 lw_internal_update_other_instances to dereference freed memory
1856 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1857 list */
1858 static void
1859 xm_internal_update_other_instances (widget, closure, call_data)
1860 Widget widget;
1861 XtPointer closure;
1862 XtPointer call_data;
1864 Widget parent;
1865 for (parent = widget; parent; parent = XtParent (parent))
1866 if (XtIsShell (parent))
1867 break;
1868 else if (!XtIsManaged (parent))
1869 return;
1870 lw_internal_update_other_instances (widget, closure, call_data);
1873 static void
1874 xm_generic_callback (widget, closure, call_data)
1875 Widget widget;
1876 XtPointer closure;
1877 XtPointer call_data;
1879 lw_internal_update_other_instances (widget, closure, call_data);
1880 do_call (widget, closure, selection);
1883 static void
1884 xm_nosel_callback (widget, closure, call_data)
1885 Widget widget;
1886 XtPointer closure;
1887 XtPointer call_data;
1889 /* This callback is only called when a dialog box is dismissed with
1890 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1891 box to be destroyed in that case, not just unmapped, so that it
1892 releases its keyboard grabs. But there are problems with running
1893 our callbacks while the widget is in the process of being
1894 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1895 XmDESTROY and then destroy it ourself after having run the
1896 callback. */
1897 do_call (widget, closure, no_selection);
1898 XtDestroyWidget (widget);
1901 static void
1902 xm_pull_down_callback (widget, closure, call_data)
1903 Widget widget;
1904 XtPointer closure;
1905 XtPointer call_data;
1907 Widget parent = XtParent (widget);
1909 if (XmIsRowColumn (parent))
1911 unsigned char type = 0xff;
1912 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1913 if (type == XmMENU_BAR)
1914 do_call (widget, closure, pre_activate);
1919 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1920 CLOSURE is a pointer to the widget_instance of the shell,
1922 Note that this callback is called for each cascade button in a
1923 menu, whether or not its submenu is visible. */
1925 static void
1926 xm_pop_down_callback (widget, closure, call_data)
1927 Widget widget;
1928 XtPointer closure;
1929 XtPointer call_data;
1931 widget_instance *instance = (widget_instance *) closure;
1933 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1934 || XtParent (widget) == instance->parent)
1935 do_call (widget, closure, post_activate);
1939 /* set the keyboard focus */
1940 void
1941 xm_set_keyboard_focus (parent, w)
1942 Widget parent;
1943 Widget w;
1945 XmProcessTraversal (w, 0);
1946 XtSetKeyboardFocus (parent, w);
1949 /* Motif hack to set the main window areas. */
1950 void
1951 xm_set_main_areas (parent, menubar, work_area)
1952 Widget parent;
1953 Widget menubar;
1954 Widget work_area;
1956 XmMainWindowSetAreas (parent,
1957 menubar, /* menubar (maybe 0) */
1958 0, /* command area (psheets) */
1959 0, /* horizontal scroll */
1960 0, /* vertical scroll */
1961 work_area); /* work area */
1964 /* Motif hack to control resizing on the menubar. */
1965 void
1966 xm_manage_resizing (w, flag)
1967 Widget w;
1968 Boolean flag;
1970 XtVaSetValues (w, XtNallowShellResize, flag, NULL);