Require tex-mode when compiling.
[emacs.git] / lwlib / lwlib-Xm.c
blob4a3f097a867ec8b86119abc31ceb620a657e5cf6
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
34 #include "lwlib-Xm.h"
35 #include "lwlib-utils.h"
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Label.h>
43 #include <Xm/List.h>
44 #include <Xm/MainW.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
48 #include <Xm/PushB.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
52 #include <Xm/Text.h>
53 #include <Xm/TextF.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
60 #include <Xm/Form.h>
62 #if defined __STDC__ || defined PROTOTYPES
63 #define P_(X) X
64 #else
65 #define P_(X) ()
66 #endif
68 enum do_call_type { pre_activate, selection, no_selection, post_activate };
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
83 Widget, Widget,
84 Boolean));
85 static void free_destroyed_instance P_ ((destroyed_instance*));
86 Widget first_child P_ ((Widget));
87 Boolean lw_motif_widget_p P_ ((Widget));
88 static XmString resource_motif_string P_ ((Widget, char *));
89 static void destroy_all_children P_ ((Widget, int));
90 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
91 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
92 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
93 widget_value *));
94 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
95 widget_value *));
96 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
98 static void make_menu_in_widget P_ ((widget_instance *, Widget,
99 widget_value *, int));
100 static void update_one_menu_entry P_ ((widget_instance *, Widget,
101 widget_value *, Boolean));
102 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
103 Boolean));
104 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
105 static void xm_update_text_field P_ ((widget_instance *, Widget,
106 widget_value *));
107 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
108 static void activate_button P_ ((Widget, XtPointer, XtPointer));
109 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
110 Boolean, Boolean, Boolean, int, int));
111 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
112 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
113 static void recenter_widget P_ ((Widget));
114 static Widget recycle_instance P_ ((destroyed_instance*));
115 Widget xm_create_dialog P_ ((widget_instance*));
116 static Widget make_menubar P_ ((widget_instance*));
117 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
118 static Widget make_popup_menu P_ ((widget_instance*));
119 static Widget make_main P_ ((widget_instance*));
120 void xm_destroy_instance P_ ((widget_instance*));
121 void xm_popup_menu P_ ((Widget, XEvent *));
122 static void set_min_dialog_size P_ ((Widget));
123 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
124 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
125 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
126 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_unmap_callback P_ ((Widget, XtPointer, XtPointer));
129 void xm_set_keyboard_focus P_ ((Widget, Widget));
130 void xm_set_main_areas P_ ((Widget, Widget, Widget));
131 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
132 XtPointer));
133 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
135 #if 0
136 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
137 Boolean));
138 void xm_pop_instance P_ ((widget_instance*, Boolean));
139 void xm_manage_resizing P_ ((Widget, Boolean));
140 #endif
143 static destroyed_instance *all_destroyed_instances = NULL;
145 static destroyed_instance*
146 make_destroyed_instance (name, type, widget, parent, pop_up_p)
147 char* name;
148 char* type;
149 Widget widget;
150 Widget parent;
151 Boolean pop_up_p;
153 destroyed_instance* instance =
154 (destroyed_instance*)malloc (sizeof (destroyed_instance));
155 instance->name = safe_strdup (name);
156 instance->type = safe_strdup (type);
157 instance->widget = widget;
158 instance->parent = parent;
159 instance->pop_up_p = pop_up_p;
160 instance->next = NULL;
161 return instance;
164 static void
165 free_destroyed_instance (instance)
166 destroyed_instance* instance;
168 free (instance->name);
169 free (instance->type);
170 free (instance);
173 \f/* motif utility functions */
174 Widget
175 first_child (widget)
176 Widget widget;
178 return ((CompositeWidget)widget)->composite.children [0];
181 Boolean
182 lw_motif_widget_p (widget)
183 Widget widget;
185 return
186 XtClass (widget) == xmDialogShellWidgetClass
187 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
190 static XmString
191 resource_motif_string (widget, name)
192 Widget widget;
193 char* name;
195 XtResource resource;
196 XmString result = 0;
198 resource.resource_name = name;
199 resource.resource_class = XmCXmString;
200 resource.resource_type = XmRXmString;
201 resource.resource_size = sizeof (XmString);
202 resource.resource_offset = 0;
203 resource.default_type = XtRImmediate;
204 resource.default_addr = 0;
206 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
207 "DialogString", &resource, 1, NULL, 0);
208 return result;
211 /* Destroy all of the children of WIDGET
212 starting with number FIRST_CHILD_TO_DESTROY. */
214 static void
215 destroy_all_children (widget, first_child_to_destroy)
216 Widget widget;
217 int first_child_to_destroy;
219 Widget* children;
220 unsigned int number;
221 int i;
223 children = XtCompositeChildren (widget, &number);
224 if (children)
226 XtUnmanageChildren (children + first_child_to_destroy,
227 number - first_child_to_destroy);
229 /* Unmanage all children and destroy them. They will only be
230 really destroyed when we get out of DispatchEvent. */
231 for (i = first_child_to_destroy; i < number; i++)
233 Arg al[2];
234 Widget submenu = 0;
235 /* Cascade buttons have submenus,and these submenus
236 need to be freed. But they are not included in
237 XtCompositeChildren. So get it out of the cascade button
238 and free it. If this child is not a cascade button,
239 then submenu should remain unchanged. */
240 XtSetArg (al[0], XmNsubMenuId, &submenu);
241 XtGetValues (children[i], al, 1);
242 if (submenu)
243 XtDestroyWidget (submenu);
244 XtDestroyWidget (children[i]);
247 XtFree ((char *) children);
253 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
254 menu. CLIENT_DATA contains a pointer to the widget_value
255 corresponding to widget W. CALL_DATA contains a
256 XmPushButtonCallbackStruct containing the reason why the callback
257 is called. */
259 static void
260 xm_arm_callback (w, client_data, call_data)
261 Widget w;
262 XtPointer client_data, call_data;
264 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
265 widget_value *wv = (widget_value *) client_data;
266 widget_instance *instance;
268 /* During the pretest of 21.1, there was a case where this callback
269 was called with a null widget on hpux 10.2. I think that's
270 likely a bug in the Motif lib there. */
271 if (w != None)
273 /* Get the id of the menu bar or popup menu this widget is in. */
274 while (1)
276 if (XmIsRowColumn (w))
278 unsigned char type = 0xff;
280 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
281 if (type == XmMENU_BAR || type == XmMENU_POPUP)
282 break;
285 w = XtParent (w);
288 instance = lw_get_widget_instance (w);
289 if (instance && instance->info->highlight_cb)
291 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
292 instance->info->highlight_cb (w, instance->info->id, call_data);
299 /* Update the label of widget WIDGET. WIDGET must be a Label widget
300 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
301 the value to update.
303 Menus:
305 Emacs fills VAL->name with the text to display in the menu, and
306 sets VAL->value to null. Function make_menu_in_widget creates
307 widgets with VAL->name as resource name. This works because the
308 Label widget uses its resource name for display if no
309 XmNlabelString is set.
311 Dialogs:
313 VAL->name is again set to the resource name, but VAL->value is
314 not null, and contains the label string to display. */
316 static void
317 xm_update_label (instance, widget, val)
318 widget_instance* instance;
319 Widget widget;
320 widget_value* val;
322 XmString res_string = 0;
323 XmString built_string = 0;
324 XmString key_string = 0;
325 Arg al [256];
326 int ac;
328 ac = 0;
330 if (val->value)
332 /* A label string is specified, i.e. we are in a dialog. First
333 see if it is overridden by something from the resource file. */
334 res_string = resource_motif_string (widget, val->value);
336 if (res_string)
338 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
340 else
342 built_string =
343 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
344 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
347 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
350 if (val->key)
352 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
353 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
356 if (ac)
357 XtSetValues (widget, al, ac);
359 if (built_string)
360 XmStringFree (built_string);
362 if (key_string)
363 XmStringFree (key_string);
366 \f/* update of list */
367 static void
368 xm_update_list (instance, widget, val)
369 widget_instance* instance;
370 Widget widget;
371 widget_value* val;
373 widget_value* cur;
374 int i;
375 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
376 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
377 instance);
378 for (cur = val->contents, i = 0; cur; cur = cur->next)
379 if (cur->value)
381 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
382 i += 1;
383 XmListAddItem (widget, xmstr, 0);
384 if (cur->selected)
385 XmListSelectPos (widget, i, False);
386 XmStringFree (xmstr);
390 \f/* update of buttons */
391 static void
392 xm_update_pushbutton (instance, widget, val)
393 widget_instance* instance;
394 Widget widget;
395 widget_value* val;
397 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
398 XtRemoveAllCallbacks (widget, XmNactivateCallback);
399 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
402 static void
403 xm_update_cascadebutton (instance, widget, val)
404 widget_instance* instance;
405 Widget widget;
406 widget_value* val;
408 /* Should also rebuild the menu by calling ...update_menu... */
409 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
410 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
411 instance);
414 \f/* update toggle and radiobox */
415 static void
416 xm_update_toggle (instance, widget, val)
417 widget_instance* instance;
418 Widget widget;
419 widget_value* val;
421 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
422 XtAddCallback (widget, XmNvalueChangedCallback,
423 xm_generic_callback, instance);
424 XtVaSetValues (widget, XmNset, val->selected,
425 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
428 static void
429 xm_update_radiobox (instance, widget, val)
430 widget_instance* instance;
431 Widget widget;
432 widget_value* val;
435 Widget toggle;
436 widget_value* cur;
438 /* update the callback */
439 XtRemoveAllCallbacks (widget, XmNentryCallback);
440 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
442 /* first update all the toggles */
443 /* Energize kernel interface is currently bad. It sets the selected widget
444 with the selected flag but returns it by its name. So we currently
445 have to support both setting the selection with the selected slot
446 of val contents and setting it with the "value" slot of val. The latter
447 has a higher priority. This to be removed when the kernel is fixed. */
448 for (cur = val->contents; cur; cur = cur->next)
450 toggle = XtNameToWidget (widget, cur->value);
451 if (toggle)
453 XtVaSetValues (toggle, XmNsensitive, cur->enabled, NULL);
454 if (!val->value && cur->selected)
455 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
456 if (val->value && strcmp (val->value, cur->value))
457 XtVaSetValues (toggle, XmNset, False, NULL);
461 /* The selected was specified by the value slot */
462 if (val->value)
464 toggle = XtNameToWidget (widget, val->value);
465 if (toggle)
466 XtVaSetValues (toggle, XmNset, True, NULL);
471 /* update a popup menu, pulldown menu or a menubar */
473 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
475 static void
476 make_menu_in_widget (instance, widget, val, keep_first_children)
477 widget_instance* instance;
478 Widget widget;
479 widget_value* val;
480 int keep_first_children;
482 Widget* children = 0;
483 int num_children;
484 int child_index;
485 widget_value* cur;
486 Widget button = 0;
487 Widget title = 0;
488 Widget menu;
489 Arg al [256];
490 int ac;
491 Boolean menubar_p;
492 unsigned char type;
494 Widget* old_children;
495 unsigned int old_num_children;
497 old_children = XtCompositeChildren (widget, &old_num_children);
499 /* Allocate the children array */
500 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
501 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
503 /* WIDGET should be a RowColumn. */
504 if (!XmIsRowColumn (widget))
505 abort ();
507 /* Determine whether WIDGET is a menu bar. */
508 type = -1;
509 XtSetArg (al[0], XmNrowColumnType, &type);
510 XtGetValues (widget, al, 1);
511 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
512 abort ();
513 menubar_p = type == XmMENU_BAR;
515 #if 0 /* This can't be used in LessTif as of 2000-01-24 because it's
516 impossible to decide from this plus the cascading callback if a
517 popup is still posted or not. When selecting cascade button A,
518 then B, then clicking on the frame, the sequence of callbacks is
519 `cascading A', cascading B', `popdown for all cascade buttons in
520 the menu bar. */
521 /* Add a callback to popups and pulldowns that is called when
522 it is made invisible again. */
523 if (!menubar_p)
524 XtAddCallback (XtParent (widget), XmNpopdownCallback,
525 xm_pop_down_callback, (XtPointer)instance);
526 #endif
528 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
529 for (child_index = 0, cur = val; child_index < keep_first_children;
530 child_index++, cur = cur->next)
531 children[child_index] = old_children[child_index];
533 /* Check that those are all we have
534 (the caller should have deleted the rest). */
535 if (old_num_children != keep_first_children)
536 abort ();
538 /* Create the rest. */
539 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
541 enum menu_separator separator;
543 ac = 0;
544 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
545 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
546 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
548 if (instance->pop_up_p && !cur->contents && !cur->call_data
549 && !lw_separator_p (cur->name, &separator, 1))
551 ac = 0;
552 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
553 title = button = XmCreateLabel (widget, cur->name, al, ac);
555 else if (lw_separator_p (cur->name, &separator, 1))
557 ac = 0;
558 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
559 button = XmCreateSeparator (widget, cur->name, al, ac);
561 else if (!cur->contents)
563 if (menubar_p)
564 button = XmCreateCascadeButton (widget, cur->name, al, ac);
565 else if (!cur->call_data)
566 button = XmCreateLabel (widget, cur->name, al, ac);
567 else if (cur->button_type == BUTTON_TYPE_TOGGLE
568 || cur->button_type == BUTTON_TYPE_RADIO)
570 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
571 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
572 XtSetArg (al[ac], XmNindicatorType,
573 (cur->button_type == BUTTON_TYPE_TOGGLE
574 ? XmN_OF_MANY : XmONE_OF_MANY));
575 ++ac;
576 button = XmCreateToggleButton (widget, cur->name, al, ac);
577 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
578 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
580 else
582 button = XmCreatePushButton (widget, cur->name, al, ac);
583 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
584 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
587 xm_update_label (instance, button, cur);
589 /* Add a callback that is called when the button is
590 selected. Toggle buttons don't support
591 XmNactivateCallback, we use XmNvalueChangedCallback in
592 that case. Don't add a callback to a simple label. */
593 if (cur->button_type)
594 xm_update_toggle (instance, button, cur);
595 else if (cur->call_data)
596 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
597 (XtPointer)instance);
599 else
601 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
603 /* XmNpopdownCallback is working strangely under LessTif.
604 Using XmNunmapCallback is the only way to go there. */
605 if (menubar_p)
606 XtAddCallback (menu, XmNunmapCallback, xm_unmap_callback,
607 (XtPointer) instance);
609 make_menu_in_widget (instance, menu, cur->contents, 0);
610 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
611 button = XmCreateCascadeButton (widget, cur->name, al, ac);
613 xm_update_label (instance, button, cur);
615 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
616 (XtPointer)instance);
619 children[child_index] = button;
622 /* Last entry is the help button. The original comment read "Has to
623 be done after managing the buttons otherwise the menubar is only
624 4 pixels high." This is no longer true, and to make
625 XmNmenuHelpWidget work, we need to set it before managing the
626 children.. --gerd. */
627 if (button)
628 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
630 /* LessTif apparently doesn't recompute centered text when more
631 widgets are added. So, do it after all widgets have been
632 created. */
633 if (title)
634 XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, NULL);
636 if (num_children)
637 XtManageChildren (children, num_children);
639 XtFree ((char *) children);
640 if (old_children)
641 XtFree ((char *) old_children);
644 static void
645 update_one_menu_entry (instance, widget, val, deep_p)
646 widget_instance* instance;
647 Widget widget;
648 widget_value* val;
649 Boolean deep_p;
651 Arg al [256];
652 int ac;
653 Widget menu;
654 widget_value* contents;
656 if (val->this_one_change == NO_CHANGE)
657 return;
659 /* update the sensitivity and userdata */
660 /* Common to all widget types */
661 XtVaSetValues (widget,
662 XmNsensitive, val->enabled,
663 XmNuserData, val->call_data,
664 NULL);
666 /* update the menu button as a label. */
667 if (val->this_one_change >= VISIBLE_CHANGE)
669 xm_update_label (instance, widget, val);
670 if (val->button_type)
671 xm_update_toggle (instance, widget, val);
674 /* update the pulldown/pullaside as needed */
675 ac = 0;
676 menu = NULL;
677 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
678 XtGetValues (widget, al, ac);
680 contents = val->contents;
682 if (!menu)
684 if (contents)
686 unsigned int old_num_children, i;
687 Widget parent;
688 Widget *widget_list;
690 parent = XtParent (widget);
691 widget_list = XtCompositeChildren (parent, &old_num_children);
693 /* Find the widget position within the parent's widget list. */
694 for (i = 0; i < old_num_children; i++)
695 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
696 break;
697 if (i == old_num_children)
698 abort ();
699 if (XmIsCascadeButton (widget_list[i]))
701 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
702 make_menu_in_widget (instance, menu, contents, 0);
703 ac = 0;
704 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
705 XtSetValues (widget, al, ac);
707 else
709 Widget button;
711 /* The current menuitem is a XmPushButtonGadget, it
712 needs to be replaced by a CascadeButtonGadget */
713 XtDestroyWidget (widget_list[i]);
714 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
715 make_menu_in_widget (instance, menu, contents, 0);
716 ac = 0;
717 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
718 /* Non-zero values don't work reliably in
719 conjunction with Emacs' event loop */
720 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
721 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
722 /* Tell Motif to put it in the right place */
723 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
724 #endif
725 button = XmCreateCascadeButton (parent, val->name, al, ac);
726 xm_update_label (instance, button, val);
728 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
729 (XtPointer)instance);
730 XtManageChild (button);
734 else if (!contents)
736 ac = 0;
737 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
738 XtSetValues (widget, al, ac);
739 XtDestroyWidget (menu);
741 else if (deep_p && contents->change != NO_CHANGE)
742 xm_update_menu (instance, menu, val, 1);
745 static void
746 xm_update_menu (instance, widget, val, deep_p)
747 widget_instance* instance;
748 Widget widget;
749 widget_value* val;
750 Boolean deep_p;
752 Widget* children;
753 unsigned int num_children;
754 int num_children_to_keep = 0;
755 int i;
756 widget_value* cur;
758 children = XtCompositeChildren (widget, &num_children);
760 /* Widget is a RowColumn widget whose contents have to be updated
761 * to reflect the list of items in val->contents */
763 /* See how many buttons we can keep, and how many we
764 must completely replace. */
765 if (val->contents == 0)
766 num_children_to_keep = 0;
767 else if (val->contents->change == STRUCTURAL_CHANGE)
769 if (children)
771 for (i = 0, cur = val->contents;
772 (i < num_children
773 && cur); /* how else to ditch unwanted children ?? - mgd */
774 i++, cur = cur->next)
776 if (cur->this_one_change == STRUCTURAL_CHANGE)
777 break;
780 num_children_to_keep = i;
783 else
784 num_children_to_keep = num_children;
786 /* Update all the buttons of the RowColumn, in order,
787 except for those we are going to replace entirely. */
788 if (children)
790 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
792 if (!cur)
794 num_children_to_keep = i;
795 break;
797 if (children [i]->core.being_destroyed
798 || strcmp (XtName (children [i]), cur->name))
799 continue;
800 update_one_menu_entry (instance, children [i], cur, deep_p);
801 cur = cur->next;
805 /* Now replace from scratch all the buttons after the last
806 place that the top-level structure changed. */
807 if (val->contents->change == STRUCTURAL_CHANGE)
809 destroy_all_children (widget, num_children_to_keep);
810 make_menu_in_widget (instance, widget, val->contents,
811 num_children_to_keep);
814 XtFree ((char *) children);
818 /* update text widgets */
820 static void
821 xm_update_text (instance, widget, val)
822 widget_instance* instance;
823 Widget widget;
824 widget_value* val;
826 XmTextSetString (widget, val->value ? val->value : "");
827 XtRemoveAllCallbacks (widget, XmNactivateCallback);
828 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
829 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
830 XtAddCallback (widget, XmNvalueChangedCallback,
831 xm_internal_update_other_instances, instance);
834 static void
835 xm_update_text_field (instance, widget, val)
836 widget_instance* instance;
837 Widget widget;
838 widget_value* val;
840 XmTextFieldSetString (widget, val->value ? val->value : "");
841 XtRemoveAllCallbacks (widget, XmNactivateCallback);
842 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
843 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
844 XtAddCallback (widget, XmNvalueChangedCallback,
845 xm_internal_update_other_instances, instance);
849 /* update a motif widget */
851 void
852 xm_update_one_widget (instance, widget, val, deep_p)
853 widget_instance* instance;
854 Widget widget;
855 widget_value* val;
856 Boolean deep_p;
858 WidgetClass class;
860 /* Mark as not edited */
861 val->edited = False;
863 /* Common to all widget types */
864 XtVaSetValues (widget,
865 XmNsensitive, val->enabled,
866 XmNuserData, val->call_data,
867 NULL);
869 /* Common to all label like widgets */
870 if (XtIsSubclass (widget, xmLabelWidgetClass))
871 xm_update_label (instance, widget, val);
873 class = XtClass (widget);
874 /* Class specific things */
875 if (class == xmPushButtonWidgetClass ||
876 class == xmArrowButtonWidgetClass)
878 xm_update_pushbutton (instance, widget, val);
880 else if (class == xmCascadeButtonWidgetClass)
882 xm_update_cascadebutton (instance, widget, val);
884 else if (class == xmToggleButtonWidgetClass
885 || class == xmToggleButtonGadgetClass)
887 xm_update_toggle (instance, widget, val);
889 else if (class == xmRowColumnWidgetClass)
891 Boolean radiobox = 0;
892 int ac = 0;
893 Arg al [1];
895 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
896 XtGetValues (widget, al, ac);
898 if (radiobox)
899 xm_update_radiobox (instance, widget, val);
900 else
901 xm_update_menu (instance, widget, val, deep_p);
903 else if (class == xmTextWidgetClass)
905 xm_update_text (instance, widget, val);
907 else if (class == xmTextFieldWidgetClass)
909 xm_update_text_field (instance, widget, val);
911 else if (class == xmListWidgetClass)
913 xm_update_list (instance, widget, val);
917 \f/* getting the value back */
918 void
919 xm_update_one_value (instance, widget, val)
920 widget_instance* instance;
921 Widget widget;
922 widget_value* val;
924 WidgetClass class = XtClass (widget);
925 widget_value *old_wv;
927 /* copy the call_data slot into the "return" widget_value */
928 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
929 if (!strcmp (val->name, old_wv->name))
931 val->call_data = old_wv->call_data;
932 break;
935 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
937 XtVaGetValues (widget, XmNset, &val->selected, NULL);
938 val->edited = True;
940 else if (class == xmTextWidgetClass)
942 if (val->value)
943 free (val->value);
944 val->value = XmTextGetString (widget);
945 val->edited = True;
947 else if (class == xmTextFieldWidgetClass)
949 if (val->value)
950 free (val->value);
951 val->value = XmTextFieldGetString (widget);
952 val->edited = True;
954 else if (class == xmRowColumnWidgetClass)
956 Boolean radiobox = 0;
957 int ac = 0;
958 Arg al [1];
960 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
961 XtGetValues (widget, al, ac);
963 if (radiobox)
965 CompositeWidget radio = (CompositeWidget)widget;
966 int i;
967 for (i = 0; i < radio->composite.num_children; i++)
969 int set = False;
970 Widget toggle = radio->composite.children [i];
972 XtVaGetValues (toggle, XmNset, &set, NULL);
973 if (set)
975 if (val->value)
976 free (val->value);
977 val->value = safe_strdup (XtName (toggle));
980 val->edited = True;
983 else if (class == xmListWidgetClass)
985 int pos_cnt;
986 int* pos_list;
987 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
989 int i;
990 widget_value* cur;
991 for (cur = val->contents, i = 0; cur; cur = cur->next)
992 if (cur->value)
994 int j;
995 cur->selected = False;
996 i += 1;
997 for (j = 0; j < pos_cnt; j++)
998 if (pos_list [j] == i)
1000 cur->selected = True;
1001 val->value = safe_strdup (cur->name);
1004 val->edited = 1;
1005 XtFree ((char *) pos_list);
1011 /* This function is for activating a button from a program. It's wrong because
1012 we pass a NULL argument in the call_data which is not Motif compatible.
1013 This is used from the XmNdefaultAction callback of the List widgets to
1014 have a double-click put down a dialog box like the button would do.
1015 I could not find a way to do that with accelerators.
1017 static void
1018 activate_button (widget, closure, call_data)
1019 Widget widget;
1020 XtPointer closure;
1021 XtPointer call_data;
1023 Widget button = (Widget)closure;
1024 XtCallCallbacks (button, XmNactivateCallback, NULL);
1027 /* creation functions */
1029 /* dialogs */
1030 static Widget
1031 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1032 radio_box, list, left_buttons, right_buttons)
1033 char* name;
1034 Widget parent;
1035 Boolean pop_up_p;
1036 char* shell_title;
1037 char* icon_name;
1038 Boolean text_input_slot;
1039 Boolean radio_box;
1040 Boolean list;
1041 int left_buttons;
1042 int right_buttons;
1044 Widget result;
1045 Widget form;
1046 Widget row;
1047 Widget icon;
1048 Widget icon_separator;
1049 Widget message;
1050 Widget value = 0;
1051 Widget separator;
1052 Widget button = 0;
1053 Widget children [16]; /* for the final XtManageChildren */
1054 int n_children;
1055 Arg al[64]; /* Arg List */
1056 int ac; /* Arg Count */
1057 int i;
1059 if (pop_up_p)
1061 ac = 0;
1062 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1063 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1064 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1065 result = XmCreateDialogShell (parent, "dialog", al, ac);
1066 ac = 0;
1067 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1068 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1069 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1070 form = XmCreateForm (result, shell_title, al, ac);
1072 else
1074 ac = 0;
1075 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1076 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1077 form = XmCreateForm (parent, shell_title, al, ac);
1078 result = form;
1081 n_children = left_buttons + right_buttons + 1;
1082 ac = 0;
1083 XtSetArg(al[ac], XmNpacking, n_children == 3?
1084 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1085 XtSetArg(al[ac], XmNorientation, n_children == 3?
1086 XmVERTICAL: XmHORIZONTAL); ac++;
1087 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1088 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1089 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1090 XtSetArg(al[ac], XmNspacing, 13); ac++;
1091 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1092 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1093 XtSetArg(al[ac], XmNisAligned, True); ac++;
1094 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1095 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1096 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1097 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1098 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1099 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1100 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1101 row = XmCreateRowColumn (form, "row", al, ac);
1103 n_children = 0;
1104 for (i = 0; i < left_buttons; i++)
1106 char button_name [16];
1107 sprintf (button_name, "button%d", i + 1);
1108 ac = 0;
1109 if (i == 0)
1111 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1112 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1114 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1115 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1116 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1118 if (i == 0)
1120 button = children [n_children];
1121 ac = 0;
1122 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1123 XtSetValues (row, al, ac);
1126 n_children++;
1129 /* invisible separator button */
1130 ac = 0;
1131 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1132 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1133 n_children++;
1135 for (i = 0; i < right_buttons; i++)
1137 char button_name [16];
1138 sprintf (button_name, "button%d", left_buttons + i + 1);
1139 ac = 0;
1140 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1141 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1142 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1143 if (! button) button = children [n_children];
1144 n_children++;
1147 XtManageChildren (children, n_children);
1149 ac = 0;
1150 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1151 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1152 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1153 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1154 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1155 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1156 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1157 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1158 separator = XmCreateSeparator (form, "", al, ac);
1160 ac = 0;
1161 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1162 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1163 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1164 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1165 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1166 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1167 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1168 icon = XmCreateLabel (form, icon_name, al, ac);
1170 ac = 0;
1171 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1172 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1173 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1174 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1175 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1176 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1177 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1178 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1179 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1180 icon_separator = XmCreateLabel (form, "", al, ac);
1182 if (text_input_slot)
1184 ac = 0;
1185 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1186 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1187 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1188 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1189 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1190 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1191 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1192 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1193 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1194 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1195 value = XmCreateTextField (form, "value", al, ac);
1197 else if (radio_box)
1199 Widget radio_butt;
1200 ac = 0;
1201 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1202 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1203 XtSetArg(al[ac], XmNspacing, 13); ac++;
1204 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1205 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1206 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1207 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1208 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1209 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1210 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1211 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1212 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1213 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1214 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1215 ac = 0;
1216 i = 0;
1217 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1218 children [i++] = radio_butt;
1219 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1220 children [i++] = radio_butt;
1221 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1222 children [i++] = radio_butt;
1223 XtManageChildren (children, i);
1225 else if (list)
1227 ac = 0;
1228 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1229 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1230 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1231 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1232 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1233 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1234 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1235 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1236 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1237 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1238 value = XmCreateScrolledList (form, "list", al, ac);
1240 /* this is the easiest way I found to have the dble click in the
1241 list activate the default button */
1242 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1245 ac = 0;
1246 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1247 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1248 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1249 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1250 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1251 XtSetArg(al[ac], XmNbottomWidget,
1252 text_input_slot || radio_box || list ? value : separator); ac++;
1253 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1254 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1255 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1256 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1257 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1258 message = XmCreateLabel (form, "message", al, ac);
1260 if (list)
1261 XtManageChild (value);
1263 i = 0;
1264 children [i] = row; i++;
1265 children [i] = separator; i++;
1266 if (text_input_slot || radio_box)
1268 children [i] = value; i++;
1270 children [i] = message; i++;
1271 children [i] = icon; i++;
1272 children [i] = icon_separator; i++;
1273 XtManageChildren (children, i);
1275 if (text_input_slot || list)
1277 XtInstallAccelerators (value, button);
1278 XtSetKeyboardFocus (result, value);
1280 else
1282 XtInstallAccelerators (form, button);
1283 XtSetKeyboardFocus (result, button);
1286 return result;
1289 static destroyed_instance*
1290 find_matching_instance (instance)
1291 widget_instance* instance;
1293 destroyed_instance* cur;
1294 destroyed_instance* prev;
1295 char* type = instance->info->type;
1296 char* name = instance->info->name;
1298 for (prev = NULL, cur = all_destroyed_instances;
1299 cur;
1300 prev = cur, cur = cur->next)
1302 if (!strcmp (cur->name, name)
1303 && !strcmp (cur->type, type)
1304 && cur->parent == instance->parent
1305 && cur->pop_up_p == instance->pop_up_p)
1307 if (prev)
1308 prev->next = cur->next;
1309 else
1310 all_destroyed_instances = cur->next;
1311 return cur;
1313 /* do some cleanup */
1314 else if (!cur->widget)
1316 if (prev)
1317 prev->next = cur->next;
1318 else
1319 all_destroyed_instances = cur->next;
1320 free_destroyed_instance (cur);
1321 cur = prev ? prev : all_destroyed_instances;
1324 return NULL;
1327 static void
1328 mark_dead_instance_destroyed (widget, closure, call_data)
1329 Widget widget;
1330 XtPointer closure;
1331 XtPointer call_data;
1333 destroyed_instance* instance = (destroyed_instance*)closure;
1334 instance->widget = NULL;
1337 static void
1338 recenter_widget (widget)
1339 Widget widget;
1341 Widget parent = XtParent (widget);
1342 Screen* screen = XtScreen (widget);
1343 Dimension screen_width = WidthOfScreen (screen);
1344 Dimension screen_height = HeightOfScreen (screen);
1345 Dimension parent_width = 0;
1346 Dimension parent_height = 0;
1347 Dimension child_width = 0;
1348 Dimension child_height = 0;
1349 Position x;
1350 Position y;
1352 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1353 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1354 NULL);
1356 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1357 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1359 XtTranslateCoords (parent, x, y, &x, &y);
1361 if (x + child_width > screen_width)
1362 x = screen_width - child_width;
1363 if (x < 0)
1364 x = 0;
1366 if (y + child_height > screen_height)
1367 y = screen_height - child_height;
1368 if (y < 0)
1369 y = 0;
1371 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1374 static Widget
1375 recycle_instance (instance)
1376 destroyed_instance* instance;
1378 Widget widget = instance->widget;
1380 /* widget is NULL if the parent was destroyed. */
1381 if (widget)
1383 Widget focus;
1384 Widget separator;
1386 /* Remove the destroy callback as the instance is not in the list
1387 anymore */
1388 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1389 mark_dead_instance_destroyed,
1390 (XtPointer)instance);
1392 /* Give the focus to the initial item */
1393 focus = XtNameToWidget (widget, "*value");
1394 if (!focus)
1395 focus = XtNameToWidget (widget, "*button1");
1396 if (focus)
1397 XtSetKeyboardFocus (widget, focus);
1399 /* shrink the separator label back to their original size */
1400 separator = XtNameToWidget (widget, "*separator_button");
1401 if (separator)
1402 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1404 /* Center the dialog in its parent */
1405 recenter_widget (widget);
1407 free_destroyed_instance (instance);
1408 return widget;
1411 Widget
1412 xm_create_dialog (instance)
1413 widget_instance* instance;
1415 char* name = instance->info->type;
1416 Widget parent = instance->parent;
1417 Widget widget;
1418 Boolean pop_up_p = instance->pop_up_p;
1419 char* shell_name = 0;
1420 char* icon_name;
1421 Boolean text_input_slot = False;
1422 Boolean radio_box = False;
1423 Boolean list = False;
1424 int total_buttons;
1425 int left_buttons = 0;
1426 int right_buttons = 1;
1427 destroyed_instance* dead_one;
1429 /* try to find a widget to recycle */
1430 dead_one = find_matching_instance (instance);
1431 if (dead_one)
1433 Widget recycled_widget = recycle_instance (dead_one);
1434 if (recycled_widget)
1435 return recycled_widget;
1438 switch (name [0]){
1439 case 'E': case 'e':
1440 icon_name = "dbox-error";
1441 shell_name = "Error";
1442 break;
1444 case 'I': case 'i':
1445 icon_name = "dbox-info";
1446 shell_name = "Information";
1447 break;
1449 case 'L': case 'l':
1450 list = True;
1451 icon_name = "dbox-question";
1452 shell_name = "Prompt";
1453 break;
1455 case 'P': case 'p':
1456 text_input_slot = True;
1457 icon_name = "dbox-question";
1458 shell_name = "Prompt";
1459 break;
1461 case 'Q': case 'q':
1462 icon_name = "dbox-question";
1463 shell_name = "Question";
1464 break;
1467 total_buttons = name [1] - '0';
1469 if (name [3] == 'T' || name [3] == 't')
1471 text_input_slot = False;
1472 radio_box = True;
1474 else if (name [3])
1475 right_buttons = name [4] - '0';
1477 left_buttons = total_buttons - right_buttons;
1479 widget = make_dialog (name, parent, pop_up_p,
1480 shell_name, icon_name, text_input_slot, radio_box,
1481 list, left_buttons, right_buttons);
1483 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1484 (XtPointer) instance);
1485 return widget;
1488 /* Create a menu bar. We turn off the f10 key
1489 because we have not yet managed to make it work right in Motif. */
1491 static Widget
1492 make_menubar (instance)
1493 widget_instance* instance;
1495 Arg al[3];
1496 int ac;
1498 ac = 0;
1499 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1501 #if 0
1502 /* As of 2000-01-17, the LessTif menu bar resizes to height 0 when
1503 all its children are removed, causing an annoying flickering
1504 behavior. Prevent that by not allowing resizing. */
1505 XtSetArg(al[ac], XmNresizeHeight, False); ++ac;
1506 XtSetArg(al[ac], XmNresizeWidth, False); ++ac;
1507 #endif
1509 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1512 static void
1513 remove_grabs (shell, closure, call_data)
1514 Widget shell;
1515 XtPointer closure;
1516 XtPointer call_data;
1518 Widget menu = (Widget) closure;
1519 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1522 static Widget
1523 make_popup_menu (instance)
1524 widget_instance* instance;
1526 Widget parent = instance->parent;
1527 Window parent_window = parent->core.window;
1528 Widget result;
1530 /* sets the parent window to 0 to fool Motif into not generating a grab */
1531 parent->core.window = 0;
1532 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1533 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1534 (XtPointer)result);
1535 parent->core.window = parent_window;
1536 return result;
1539 static Widget
1540 make_main (instance)
1541 widget_instance* instance;
1543 Widget parent = instance->parent;
1544 Widget result;
1545 Arg al[2];
1546 int ac;
1548 ac = 0;
1549 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1550 XtSetArg (al[ac], XmNspacing, 0); ac++;
1551 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1552 return result;
1555 \f/* Table of functions to create widgets */
1557 #ifdef ENERGIZE
1559 /* interface with the XDesigner generated functions */
1560 typedef Widget (*widget_maker) (Widget);
1561 extern Widget create_project_p_sheet (Widget parent);
1562 extern Widget create_debugger_p_sheet (Widget parent);
1563 extern Widget create_breaklist_p_sheet (Widget parent);
1564 extern Widget create_le_browser_p_sheet (Widget parent);
1565 extern Widget create_class_browser_p_sheet (Widget parent);
1566 extern Widget create_call_browser_p_sheet (Widget parent);
1567 extern Widget create_build_dialog (Widget parent);
1568 extern Widget create_editmode_dialog (Widget parent);
1569 extern Widget create_search_dialog (Widget parent);
1570 extern Widget create_project_display_dialog (Widget parent);
1572 static Widget
1573 make_one (widget_instance* instance, widget_maker fn)
1575 Widget result;
1576 Arg al [64];
1577 int ac = 0;
1579 if (instance->pop_up_p)
1581 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1582 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1583 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1584 (XtPointer) instance);
1585 (*fn) (result);
1587 else
1589 result = (*fn) (instance->parent);
1590 XtRealizeWidget (result);
1592 return result;
1595 static Widget
1596 make_project_p_sheet (widget_instance* instance)
1598 return make_one (instance, create_project_p_sheet);
1601 static Widget
1602 make_debugger_p_sheet (widget_instance* instance)
1604 return make_one (instance, create_debugger_p_sheet);
1607 static Widget
1608 make_breaklist_p_sheet (widget_instance* instance)
1610 return make_one (instance, create_breaklist_p_sheet);
1613 static Widget
1614 make_le_browser_p_sheet (widget_instance* instance)
1616 return make_one (instance, create_le_browser_p_sheet);
1619 static Widget
1620 make_class_browser_p_sheet (widget_instance* instance)
1622 return make_one (instance, create_class_browser_p_sheet);
1625 static Widget
1626 make_call_browser_p_sheet (widget_instance* instance)
1628 return make_one (instance, create_call_browser_p_sheet);
1631 static Widget
1632 make_build_dialog (widget_instance* instance)
1634 return make_one (instance, create_build_dialog);
1637 static Widget
1638 make_editmode_dialog (widget_instance* instance)
1640 return make_one (instance, create_editmode_dialog);
1643 static Widget
1644 make_search_dialog (widget_instance* instance)
1646 return make_one (instance, create_search_dialog);
1649 static Widget
1650 make_project_display_dialog (widget_instance* instance)
1652 return make_one (instance, create_project_display_dialog);
1655 #endif /* ENERGIZE */
1657 widget_creation_entry
1658 xm_creation_table [] =
1660 {"menubar", make_menubar},
1661 {"popup", make_popup_menu},
1662 {"main", make_main},
1663 #ifdef ENERGIZE
1664 {"project_p_sheet", make_project_p_sheet},
1665 {"debugger_p_sheet", make_debugger_p_sheet},
1666 {"breaklist_psheet", make_breaklist_p_sheet},
1667 {"leb_psheet", make_le_browser_p_sheet},
1668 {"class_browser_psheet", make_class_browser_p_sheet},
1669 {"ctree_browser_psheet", make_call_browser_p_sheet},
1670 {"build", make_build_dialog},
1671 {"editmode", make_editmode_dialog},
1672 {"search", make_search_dialog},
1673 {"project_display", make_project_display_dialog},
1674 #endif /* ENERGIZE */
1675 {NULL, NULL}
1678 \f/* Destruction of instances */
1679 void
1680 xm_destroy_instance (instance)
1681 widget_instance* instance;
1683 Widget widget = instance->widget;
1684 /* recycle the dialog boxes */
1685 /* Disable the recycling until we can find a way to have the dialog box
1686 get reasonable layout after we modify its contents. */
1687 if (0
1688 && XtClass (widget) == xmDialogShellWidgetClass)
1690 destroyed_instance* dead_instance =
1691 make_destroyed_instance (instance->info->name,
1692 instance->info->type,
1693 instance->widget,
1694 instance->parent,
1695 instance->pop_up_p);
1696 dead_instance->next = all_destroyed_instances;
1697 all_destroyed_instances = dead_instance;
1698 XtUnmanageChild (first_child (instance->widget));
1699 XFlush (XtDisplay (instance->widget));
1700 XtAddCallback (instance->parent, XtNdestroyCallback,
1701 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1703 else
1705 /* This might not be necessary now that the nosel is attached to
1706 popdown instead of destroy, but it can't hurt. */
1707 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1708 xm_nosel_callback, (XtPointer)instance);
1709 XtDestroyWidget (instance->widget);
1713 \f/* popup utility */
1714 void
1715 xm_popup_menu (widget, event)
1716 Widget widget;
1717 XEvent *event;
1719 XButtonPressedEvent dummy;
1721 if (event == 0)
1723 dummy.type = ButtonPress;
1724 dummy.serial = 0;
1725 dummy.send_event = 0;
1726 dummy.display = XtDisplay (widget);
1727 dummy.window = XtWindow (XtParent (widget));
1728 dummy.time = 0;
1729 dummy.button = 0;
1730 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1731 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1732 &dummy.x, &dummy.y, &dummy.state);
1733 event = (XEvent *) &dummy;
1736 if (event->type == ButtonPress || event->type == ButtonRelease)
1738 /* This is so totally ridiculous: there's NO WAY to tell Motif
1739 that *any* button can select a menu item. Only one button
1740 can have that honor.
1742 char *trans = 0;
1743 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1744 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1745 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1746 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1747 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1748 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1749 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1751 XtManageChild (widget);
1754 static void
1755 set_min_dialog_size (w)
1756 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 (instance, up)
1766 widget_instance* instance;
1767 Boolean up;
1769 Widget widget = instance->widget;
1771 if (XtClass (widget) == xmDialogShellWidgetClass)
1773 Widget widget_to_manage = first_child (widget);
1774 if (up)
1776 XtManageChild (widget_to_manage);
1777 set_min_dialog_size (widget);
1778 XtSetKeyboardFocus (instance->parent, widget);
1780 else
1781 XtUnmanageChild (widget_to_manage);
1783 else
1785 if (up)
1786 XtManageChild (widget);
1787 else
1788 XtUnmanageChild (widget);
1793 /* motif callback */
1795 static void
1796 do_call (widget, closure, type)
1797 Widget widget;
1798 XtPointer closure;
1799 enum do_call_type type;
1801 Arg al [256];
1802 int ac;
1803 XtPointer user_data;
1804 widget_instance* instance = (widget_instance*)closure;
1805 Widget instance_widget;
1806 LWLIB_ID id;
1808 if (!instance)
1809 return;
1810 if (widget->core.being_destroyed)
1811 return;
1813 instance_widget = instance->widget;
1814 if (!instance_widget)
1815 return;
1817 id = instance->info->id;
1818 ac = 0;
1819 user_data = NULL;
1820 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1821 XtGetValues (widget, al, ac);
1822 switch (type)
1824 case pre_activate:
1825 if (instance->info->pre_activate_cb)
1826 instance->info->pre_activate_cb (widget, id, user_data);
1827 break;
1828 case selection:
1829 if (instance->info->selection_cb)
1830 instance->info->selection_cb (widget, id, user_data);
1831 break;
1832 case no_selection:
1833 if (instance->info->selection_cb)
1834 instance->info->selection_cb (widget, id, (XtPointer) -1);
1835 break;
1836 case post_activate:
1837 if (instance->info->post_activate_cb)
1838 instance->info->post_activate_cb (widget, id, user_data);
1839 break;
1840 default:
1841 abort ();
1845 /* Like lw_internal_update_other_instances except that it does not do
1846 anything if its shell parent is not managed. This is to protect
1847 lw_internal_update_other_instances to dereference freed memory
1848 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1849 list */
1850 static void
1851 xm_internal_update_other_instances (widget, closure, call_data)
1852 Widget widget;
1853 XtPointer closure;
1854 XtPointer call_data;
1856 Widget parent;
1857 for (parent = widget; parent; parent = XtParent (parent))
1858 if (XtIsShell (parent))
1859 break;
1860 else if (!XtIsManaged (parent))
1861 return;
1862 lw_internal_update_other_instances (widget, closure, call_data);
1865 static void
1866 xm_generic_callback (widget, closure, call_data)
1867 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, closure, call_data)
1877 Widget widget;
1878 XtPointer closure;
1879 XtPointer call_data;
1881 /* This callback is only called when a dialog box is dismissed with the wm's
1882 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1883 in that case, not just unmapped, so that it releases its keyboard grabs.
1884 But there are problems with running our callbacks while the widget is in
1885 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1886 instead of XmDESTROY and then destroy it ourself after having run the
1887 callback.
1889 do_call (widget, closure, no_selection);
1890 XtDestroyWidget (widget);
1893 static void
1894 xm_pull_down_callback (widget, closure, call_data)
1895 Widget widget;
1896 XtPointer closure;
1897 XtPointer call_data;
1899 Widget parent = XtParent (widget);
1901 if (XmIsRowColumn (parent))
1903 unsigned char type = 0xff;
1904 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1905 if (type == XmMENU_BAR)
1906 do_call (widget, closure, pre_activate);
1911 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1912 CLOSURE is a pointer to the widget_instance of the shell, CALL_DATA
1913 is always null under LessTif.
1915 2000-01-23: This callback is called for each cascade button in
1916 a menu, whether or not its submenu is visible. */
1918 static void
1919 xm_pop_down_callback (widget, closure, call_data)
1920 Widget widget;
1921 XtPointer closure;
1922 XtPointer call_data;
1924 widget_instance *instance = (widget_instance *) closure;
1926 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1927 || (XtParent (widget) == instance->parent))
1928 do_call (widget, closure, post_activate);
1931 static void
1932 xm_unmap_callback (widget, closure, call_data)
1933 Widget widget;
1934 XtPointer closure;
1935 XtPointer call_data;
1937 widget_instance *instance = (widget_instance *) closure;
1938 if (!instance->pop_up_p)
1939 do_call (widget, closure, post_activate);
1943 /* set the keyboard focus */
1944 void
1945 xm_set_keyboard_focus (parent, w)
1946 Widget parent;
1947 Widget w;
1949 XmProcessTraversal (w, 0);
1950 XtSetKeyboardFocus (parent, w);
1953 /* Motif hack to set the main window areas. */
1954 void
1955 xm_set_main_areas (parent, menubar, work_area)
1956 Widget parent;
1957 Widget menubar;
1958 Widget work_area;
1960 XmMainWindowSetAreas (parent,
1961 menubar, /* menubar (maybe 0) */
1962 0, /* command area (psheets) */
1963 0, /* horizontal scroll */
1964 0, /* vertical scroll */
1965 work_area); /* work area */
1968 /* Motif hack to control resizing on the menubar. */
1969 void
1970 xm_manage_resizing (w, flag)
1971 Widget w;
1972 Boolean flag;
1974 XtVaSetValues (w, XtNallowShellResize, flag, NULL);