Mention that Lisp files are normally read as multibyte.
[emacs.git] / lwlib / lwlib-Xm.c
blobb33a53e43fcaab824281a43ace4a9ffc0c80b8b3
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
34 #include "lwlib-Xm.h"
35 #include "lwlib-utils.h"
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Label.h>
43 #include <Xm/List.h>
44 #include <Xm/MainW.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
48 #include <Xm/PushB.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
52 #include <Xm/Text.h>
53 #include <Xm/TextF.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
60 #include <Xm/Form.h>
62 #if defined __STDC__ || defined PROTOTYPES
63 #define P_(X) X
64 #else
65 #define P_(X) ()
66 #endif
68 enum do_call_type { pre_activate, selection, no_selection, post_activate };
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
83 Widget, Widget,
84 Boolean));
85 static void free_destroyed_instance P_ ((destroyed_instance*));
86 Widget first_child P_ ((Widget));
87 Boolean lw_motif_widget_p P_ ((Widget));
88 static XmString resource_motif_string P_ ((Widget, char *));
89 static void destroy_all_children P_ ((Widget, int));
90 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
91 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
92 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
93 widget_value *));
94 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
95 widget_value *));
96 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
98 static void make_menu_in_widget P_ ((widget_instance *, Widget,
99 widget_value *, int));
100 static void update_one_menu_entry P_ ((widget_instance *, Widget,
101 widget_value *, Boolean));
102 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
103 Boolean));
104 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
105 static void xm_update_text_field P_ ((widget_instance *, Widget,
106 widget_value *));
107 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
108 static void activate_button P_ ((Widget, XtPointer, XtPointer));
109 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
110 Boolean, Boolean, Boolean, int, int));
111 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
112 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
113 static void recenter_widget P_ ((Widget));
114 static Widget recycle_instance P_ ((destroyed_instance*));
115 Widget xm_create_dialog P_ ((widget_instance*));
116 static Widget make_menubar P_ ((widget_instance*));
117 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
118 static Widget make_popup_menu P_ ((widget_instance*));
119 static Widget make_main P_ ((widget_instance*));
120 void xm_destroy_instance P_ ((widget_instance*));
121 void xm_popup_menu P_ ((Widget, XEvent *));
122 static void set_min_dialog_size P_ ((Widget));
123 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
124 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
125 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
126 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_unmap_callback P_ ((Widget, XtPointer, XtPointer));
129 void xm_set_keyboard_focus P_ ((Widget, Widget));
130 void xm_set_main_areas P_ ((Widget, Widget, Widget));
131 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
132 XtPointer));
133 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
135 #if 0
136 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
137 Boolean));
138 void xm_pop_instance P_ ((widget_instance*, Boolean));
139 void xm_manage_resizing P_ ((Widget, Boolean));
140 #endif
143 static destroyed_instance *all_destroyed_instances = NULL;
145 static destroyed_instance*
146 make_destroyed_instance (name, type, widget, parent, pop_up_p)
147 char* name;
148 char* type;
149 Widget widget;
150 Widget parent;
151 Boolean pop_up_p;
153 destroyed_instance* instance =
154 (destroyed_instance*)malloc (sizeof (destroyed_instance));
155 instance->name = safe_strdup (name);
156 instance->type = safe_strdup (type);
157 instance->widget = widget;
158 instance->parent = parent;
159 instance->pop_up_p = pop_up_p;
160 instance->next = NULL;
161 return instance;
164 static void
165 free_destroyed_instance (instance)
166 destroyed_instance* instance;
168 free (instance->name);
169 free (instance->type);
170 free (instance);
173 \f/* motif utility functions */
174 Widget
175 first_child (widget)
176 Widget widget;
178 return ((CompositeWidget)widget)->composite.children [0];
181 Boolean
182 lw_motif_widget_p (widget)
183 Widget widget;
185 return
186 XtClass (widget) == xmDialogShellWidgetClass
187 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
190 static XmString
191 resource_motif_string (widget, name)
192 Widget widget;
193 char* name;
195 XtResource resource;
196 XmString result = 0;
198 resource.resource_name = name;
199 resource.resource_class = XmCXmString;
200 resource.resource_type = XmRXmString;
201 resource.resource_size = sizeof (XmString);
202 resource.resource_offset = 0;
203 resource.default_type = XtRImmediate;
204 resource.default_addr = 0;
206 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
207 "DialogString", &resource, 1, NULL, 0);
208 return result;
211 /* Destroy all of the children of WIDGET
212 starting with number FIRST_CHILD_TO_DESTROY. */
214 static void
215 destroy_all_children (widget, first_child_to_destroy)
216 Widget widget;
217 int first_child_to_destroy;
219 Widget* children;
220 unsigned int number;
221 int i;
223 children = XtCompositeChildren (widget, &number);
224 if (children)
226 XtUnmanageChildren (children + first_child_to_destroy,
227 number - first_child_to_destroy);
229 /* Unmanage all children and destroy them. They will only be
230 really destroyed when we get out of DispatchEvent. */
231 for (i = first_child_to_destroy; i < number; i++)
233 Arg al[2];
234 Widget submenu = 0;
235 /* Cascade buttons have submenus,and these submenus
236 need to be freed. But they are not included in
237 XtCompositeChildren. So get it out of the cascade button
238 and free it. If this child is not a cascade button,
239 then submenu should remain unchanged. */
240 XtSetArg (al[0], XmNsubMenuId, &submenu);
241 XtGetValues (children[i], al, 1);
242 if (submenu)
243 XtDestroyWidget (submenu);
244 XtDestroyWidget (children[i]);
247 XtFree ((char *) children);
253 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
254 menu. CLIENT_DATA contains a pointer to the widget_value
255 corresponding to widget W. CALL_DATA contains a
256 XmPushButtonCallbackStruct containing the reason why the callback
257 is called. */
259 static void
260 xm_arm_callback (w, client_data, call_data)
261 Widget w;
262 XtPointer client_data, call_data;
264 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
265 widget_value *wv = (widget_value *) client_data;
266 widget_instance *instance;
268 /* Get the id of the menu bar or popup menu this widget is in. */
269 while (1)
271 if (XmIsRowColumn (w))
273 unsigned char type = 0xff;
275 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
276 if (type == XmMENU_BAR || type == XmMENU_POPUP)
277 break;
280 w = XtParent (w);
283 instance = lw_get_widget_instance (w);
284 if (instance && instance->info->highlight_cb)
286 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
287 instance->info->highlight_cb (w, instance->info->id, call_data);
293 /* Update the label of widget WIDGET. WIDGET must be a Label widget
294 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
295 the value to update.
297 Menus:
299 Emacs fills VAL->name with the text to display in the menu, and
300 sets VAL->value to null. Function make_menu_in_widget creates
301 widgets with VAL->name as resource name. This works because the
302 Label widget uses its resource name for display if no
303 XmNlabelString is set.
305 Dialogs:
307 VAL->name is again set to the resource name, but VAL->value is
308 not null, and contains the label string to display. */
310 static void
311 xm_update_label (instance, widget, val)
312 widget_instance* instance;
313 Widget widget;
314 widget_value* val;
316 XmString res_string = 0;
317 XmString built_string = 0;
318 XmString key_string = 0;
319 Arg al [256];
320 int ac;
322 ac = 0;
324 if (val->value)
326 /* A label string is specified, i.e. we are in a dialog. First
327 see if it is overridden by something from the resource file. */
328 res_string = resource_motif_string (widget, val->value);
330 if (res_string)
332 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
334 else
336 built_string =
337 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
338 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
341 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
344 if (val->key)
346 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
347 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
350 if (ac)
351 XtSetValues (widget, al, ac);
353 if (built_string)
354 XmStringFree (built_string);
356 if (key_string)
357 XmStringFree (key_string);
360 \f/* update of list */
361 static void
362 xm_update_list (instance, widget, val)
363 widget_instance* instance;
364 Widget widget;
365 widget_value* val;
367 widget_value* cur;
368 int i;
369 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
370 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
371 instance);
372 for (cur = val->contents, i = 0; cur; cur = cur->next)
373 if (cur->value)
375 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
376 i += 1;
377 XmListAddItem (widget, xmstr, 0);
378 if (cur->selected)
379 XmListSelectPos (widget, i, False);
380 XmStringFree (xmstr);
384 \f/* update of buttons */
385 static void
386 xm_update_pushbutton (instance, widget, val)
387 widget_instance* instance;
388 Widget widget;
389 widget_value* val;
391 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
392 XtRemoveAllCallbacks (widget, XmNactivateCallback);
393 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
396 static void
397 xm_update_cascadebutton (instance, widget, val)
398 widget_instance* instance;
399 Widget widget;
400 widget_value* val;
402 /* Should also rebuild the menu by calling ...update_menu... */
403 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
404 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
405 instance);
408 \f/* update toggle and radiobox */
409 static void
410 xm_update_toggle (instance, widget, val)
411 widget_instance* instance;
412 Widget widget;
413 widget_value* val;
415 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
416 XtAddCallback (widget, XmNvalueChangedCallback,
417 xm_generic_callback, instance);
418 XtVaSetValues (widget, XmNset, val->selected,
419 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
422 static void
423 xm_update_radiobox (instance, widget, val)
424 widget_instance* instance;
425 Widget widget;
426 widget_value* val;
429 Widget toggle;
430 widget_value* cur;
432 /* update the callback */
433 XtRemoveAllCallbacks (widget, XmNentryCallback);
434 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
436 /* first update all the toggles */
437 /* Energize kernel interface is currently bad. It sets the selected widget
438 with the selected flag but returns it by its name. So we currently
439 have to support both setting the selection with the selected slot
440 of val contents and setting it with the "value" slot of val. The latter
441 has a higher priority. This to be removed when the kernel is fixed. */
442 for (cur = val->contents; cur; cur = cur->next)
444 toggle = XtNameToWidget (widget, cur->value);
445 if (toggle)
447 XtVaSetValues (toggle, XmNsensitive, cur->enabled, NULL);
448 if (!val->value && cur->selected)
449 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
450 if (val->value && strcmp (val->value, cur->value))
451 XtVaSetValues (toggle, XmNset, False, NULL);
455 /* The selected was specified by the value slot */
456 if (val->value)
458 toggle = XtNameToWidget (widget, val->value);
459 if (toggle)
460 XtVaSetValues (toggle, XmNset, True, NULL);
465 /* update a popup menu, pulldown menu or a menubar */
467 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
469 static void
470 make_menu_in_widget (instance, widget, val, keep_first_children)
471 widget_instance* instance;
472 Widget widget;
473 widget_value* val;
474 int keep_first_children;
476 Widget* children = 0;
477 int num_children;
478 int child_index;
479 widget_value* cur;
480 Widget button = 0;
481 Widget title = 0;
482 Widget menu;
483 Arg al [256];
484 int ac;
485 Boolean menubar_p;
486 unsigned char type;
488 Widget* old_children;
489 unsigned int old_num_children;
491 old_children = XtCompositeChildren (widget, &old_num_children);
493 /* Allocate the children array */
494 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
495 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
497 /* WIDGET should be a RowColumn. */
498 if (!XmIsRowColumn (widget))
499 abort ();
501 /* Determine whether WIDGET is a menu bar. */
502 type = -1;
503 XtSetArg (al[0], XmNrowColumnType, &type);
504 XtGetValues (widget, al, 1);
505 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
506 abort ();
507 menubar_p = type == XmMENU_BAR;
509 #if 0 /* This can't be used in LessTif as of 2000-01-24 because it's
510 impossible to decide from this plus the cascading callback if a
511 popup is still posted or not. When selecting cascade button A,
512 then B, then clicking on the frame, the sequence of callbacks is
513 `cascading A', cascading B', `popdown for all cascade buttons in
514 the menu bar. */
515 /* Add a callback to popups and pulldowns that is called when
516 it is made invisible again. */
517 if (!menubar_p)
518 XtAddCallback (XtParent (widget), XmNpopdownCallback,
519 xm_pop_down_callback, (XtPointer)instance);
520 #endif
522 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
523 for (child_index = 0, cur = val; child_index < keep_first_children;
524 child_index++, cur = cur->next)
525 children[child_index] = old_children[child_index];
527 /* Check that those are all we have
528 (the caller should have deleted the rest). */
529 if (old_num_children != keep_first_children)
530 abort ();
532 /* Create the rest. */
533 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
535 enum menu_separator separator;
537 ac = 0;
538 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
539 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
540 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
542 if (instance->pop_up_p && !cur->contents && !cur->call_data
543 && !lw_separator_p (cur->name, &separator, 1))
545 ac = 0;
546 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
547 title = button = XmCreateLabel (widget, cur->name, al, ac);
549 else if (lw_separator_p (cur->name, &separator, 1))
551 ac = 0;
552 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
553 button = XmCreateSeparator (widget, cur->name, al, ac);
555 else if (!cur->contents)
557 if (menubar_p)
558 button = XmCreateCascadeButton (widget, cur->name, al, ac);
559 else if (!cur->call_data)
560 button = XmCreateLabel (widget, cur->name, al, ac);
561 else if (cur->button_type == BUTTON_TYPE_TOGGLE
562 || cur->button_type == BUTTON_TYPE_RADIO)
564 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
565 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
566 XtSetArg (al[ac], XmNindicatorType,
567 (cur->button_type == BUTTON_TYPE_TOGGLE
568 ? XmN_OF_MANY : XmONE_OF_MANY));
569 ++ac;
570 button = XmCreateToggleButton (widget, cur->name, al, ac);
571 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
572 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
574 else
576 button = XmCreatePushButton (widget, cur->name, al, ac);
577 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
578 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
581 xm_update_label (instance, button, cur);
583 /* Add a callback that is called when the button is
584 selected. Toggle buttons don't support
585 XmNactivateCallback, we use XmNvalueChangedCallback in
586 that case. Don't add a callback to a simple label. */
587 if (cur->button_type)
588 xm_update_toggle (instance, button, cur);
589 else if (cur->call_data)
590 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
591 (XtPointer)instance);
593 else
595 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
597 /* XmNpopdownCallback is working strangely under LessTif.
598 Using XmNunmapCallback is the only way to go there. */
599 if (menubar_p)
600 XtAddCallback (menu, XmNunmapCallback, xm_unmap_callback,
601 (XtPointer) instance);
603 make_menu_in_widget (instance, menu, cur->contents, 0);
604 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
605 button = XmCreateCascadeButton (widget, cur->name, al, ac);
607 xm_update_label (instance, button, cur);
609 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
610 (XtPointer)instance);
613 children[child_index] = button;
616 /* Last entry is the help button. The original comment read "Has to
617 be done after managing the buttons otherwise the menubar is only
618 4 pixels high." This is no longer true, and to make
619 XmNmenuHelpWidget work, we need to set it before managing the
620 children.. --gerd. */
621 if (button)
622 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
624 /* LessTif apparently doesn't recompute centered text when more
625 widgets are added. So, do it after all widgets have been
626 created. */
627 if (title)
628 XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, NULL);
630 if (num_children)
631 XtManageChildren (children, num_children);
633 XtFree ((char *) children);
634 if (old_children)
635 XtFree ((char *) old_children);
638 static void
639 update_one_menu_entry (instance, widget, val, deep_p)
640 widget_instance* instance;
641 Widget widget;
642 widget_value* val;
643 Boolean deep_p;
645 Arg al [256];
646 int ac;
647 Widget menu;
648 widget_value* contents;
650 if (val->this_one_change == NO_CHANGE)
651 return;
653 /* update the sensitivity and userdata */
654 /* Common to all widget types */
655 XtVaSetValues (widget,
656 XmNsensitive, val->enabled,
657 XmNuserData, val->call_data,
658 NULL);
660 /* update the menu button as a label. */
661 if (val->this_one_change >= VISIBLE_CHANGE)
663 xm_update_label (instance, widget, val);
664 if (val->button_type)
665 xm_update_toggle (instance, widget, val);
668 /* update the pulldown/pullaside as needed */
669 ac = 0;
670 menu = NULL;
671 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
672 XtGetValues (widget, al, ac);
674 contents = val->contents;
676 if (!menu)
678 if (contents)
680 unsigned int old_num_children, i;
681 Widget parent;
682 Widget *widget_list;
684 parent = XtParent (widget);
685 widget_list = XtCompositeChildren (parent, &old_num_children);
687 /* Find the widget position within the parent's widget list. */
688 for (i = 0; i < old_num_children; i++)
689 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
690 break;
691 if (i == old_num_children)
692 abort ();
693 if (XmIsCascadeButton (widget_list[i]))
695 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
696 make_menu_in_widget (instance, menu, contents, 0);
697 ac = 0;
698 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
699 XtSetValues (widget, al, ac);
701 else
703 Widget button;
705 /* The current menuitem is a XmPushButtonGadget, it
706 needs to be replaced by a CascadeButtonGadget */
707 XtDestroyWidget (widget_list[i]);
708 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
709 make_menu_in_widget (instance, menu, contents, 0);
710 ac = 0;
711 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
712 /* Non-zero values don't work reliably in
713 conjunction with Emacs' event loop */
714 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
715 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
716 /* Tell Motif to put it in the right place */
717 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
718 #endif
719 button = XmCreateCascadeButton (parent, val->name, al, ac);
720 xm_update_label (instance, button, val);
722 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
723 (XtPointer)instance);
724 XtManageChild (button);
728 else if (!contents)
730 ac = 0;
731 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
732 XtSetValues (widget, al, ac);
733 XtDestroyWidget (menu);
735 else if (deep_p && contents->change != NO_CHANGE)
736 xm_update_menu (instance, menu, val, 1);
739 static void
740 xm_update_menu (instance, widget, val, deep_p)
741 widget_instance* instance;
742 Widget widget;
743 widget_value* val;
744 Boolean deep_p;
746 Widget* children;
747 unsigned int num_children;
748 int num_children_to_keep = 0;
749 int i;
750 widget_value* cur;
752 children = XtCompositeChildren (widget, &num_children);
754 /* Widget is a RowColumn widget whose contents have to be updated
755 * to reflect the list of items in val->contents */
757 /* See how many buttons we can keep, and how many we
758 must completely replace. */
759 if (val->contents == 0)
760 num_children_to_keep = 0;
761 else if (val->contents->change == STRUCTURAL_CHANGE)
763 if (children)
765 for (i = 0, cur = val->contents;
766 (i < num_children
767 && cur); /* how else to ditch unwanted children ?? - mgd */
768 i++, cur = cur->next)
770 if (cur->this_one_change == STRUCTURAL_CHANGE)
771 break;
774 num_children_to_keep = i;
777 else
778 num_children_to_keep = num_children;
780 /* Update all the buttons of the RowColumn, in order,
781 except for those we are going to replace entirely. */
782 if (children)
784 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
786 if (!cur)
788 num_children_to_keep = i;
789 break;
791 if (children [i]->core.being_destroyed
792 || strcmp (XtName (children [i]), cur->name))
793 continue;
794 update_one_menu_entry (instance, children [i], cur, deep_p);
795 cur = cur->next;
799 /* Now replace from scratch all the buttons after the last
800 place that the top-level structure changed. */
801 if (val->contents->change == STRUCTURAL_CHANGE)
803 destroy_all_children (widget, num_children_to_keep);
804 make_menu_in_widget (instance, widget, val->contents,
805 num_children_to_keep);
808 XtFree ((char *) children);
812 /* update text widgets */
814 static void
815 xm_update_text (instance, widget, val)
816 widget_instance* instance;
817 Widget widget;
818 widget_value* val;
820 XmTextSetString (widget, val->value ? val->value : "");
821 XtRemoveAllCallbacks (widget, XmNactivateCallback);
822 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
823 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
824 XtAddCallback (widget, XmNvalueChangedCallback,
825 xm_internal_update_other_instances, instance);
828 static void
829 xm_update_text_field (instance, widget, val)
830 widget_instance* instance;
831 Widget widget;
832 widget_value* val;
834 XmTextFieldSetString (widget, val->value ? val->value : "");
835 XtRemoveAllCallbacks (widget, XmNactivateCallback);
836 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
837 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
838 XtAddCallback (widget, XmNvalueChangedCallback,
839 xm_internal_update_other_instances, instance);
843 /* update a motif widget */
845 void
846 xm_update_one_widget (instance, widget, val, deep_p)
847 widget_instance* instance;
848 Widget widget;
849 widget_value* val;
850 Boolean deep_p;
852 WidgetClass class;
854 /* Mark as not edited */
855 val->edited = False;
857 /* Common to all widget types */
858 XtVaSetValues (widget,
859 XmNsensitive, val->enabled,
860 XmNuserData, val->call_data,
861 NULL);
863 /* Common to all label like widgets */
864 if (XtIsSubclass (widget, xmLabelWidgetClass))
865 xm_update_label (instance, widget, val);
867 class = XtClass (widget);
868 /* Class specific things */
869 if (class == xmPushButtonWidgetClass ||
870 class == xmArrowButtonWidgetClass)
872 xm_update_pushbutton (instance, widget, val);
874 else if (class == xmCascadeButtonWidgetClass)
876 xm_update_cascadebutton (instance, widget, val);
878 else if (class == xmToggleButtonWidgetClass
879 || class == xmToggleButtonGadgetClass)
881 xm_update_toggle (instance, widget, val);
883 else if (class == xmRowColumnWidgetClass)
885 Boolean radiobox = 0;
886 int ac = 0;
887 Arg al [1];
889 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
890 XtGetValues (widget, al, ac);
892 if (radiobox)
893 xm_update_radiobox (instance, widget, val);
894 else
895 xm_update_menu (instance, widget, val, deep_p);
897 else if (class == xmTextWidgetClass)
899 xm_update_text (instance, widget, val);
901 else if (class == xmTextFieldWidgetClass)
903 xm_update_text_field (instance, widget, val);
905 else if (class == xmListWidgetClass)
907 xm_update_list (instance, widget, val);
911 \f/* getting the value back */
912 void
913 xm_update_one_value (instance, widget, val)
914 widget_instance* instance;
915 Widget widget;
916 widget_value* val;
918 WidgetClass class = XtClass (widget);
919 widget_value *old_wv;
921 /* copy the call_data slot into the "return" widget_value */
922 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
923 if (!strcmp (val->name, old_wv->name))
925 val->call_data = old_wv->call_data;
926 break;
929 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
931 XtVaGetValues (widget, XmNset, &val->selected, NULL);
932 val->edited = True;
934 else if (class == xmTextWidgetClass)
936 if (val->value)
937 free (val->value);
938 val->value = XmTextGetString (widget);
939 val->edited = True;
941 else if (class == xmTextFieldWidgetClass)
943 if (val->value)
944 free (val->value);
945 val->value = XmTextFieldGetString (widget);
946 val->edited = True;
948 else if (class == xmRowColumnWidgetClass)
950 Boolean radiobox = 0;
951 int ac = 0;
952 Arg al [1];
954 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
955 XtGetValues (widget, al, ac);
957 if (radiobox)
959 CompositeWidget radio = (CompositeWidget)widget;
960 int i;
961 for (i = 0; i < radio->composite.num_children; i++)
963 int set = False;
964 Widget toggle = radio->composite.children [i];
966 XtVaGetValues (toggle, XmNset, &set, NULL);
967 if (set)
969 if (val->value)
970 free (val->value);
971 val->value = safe_strdup (XtName (toggle));
974 val->edited = True;
977 else if (class == xmListWidgetClass)
979 int pos_cnt;
980 int* pos_list;
981 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
983 int i;
984 widget_value* cur;
985 for (cur = val->contents, i = 0; cur; cur = cur->next)
986 if (cur->value)
988 int j;
989 cur->selected = False;
990 i += 1;
991 for (j = 0; j < pos_cnt; j++)
992 if (pos_list [j] == i)
994 cur->selected = True;
995 val->value = safe_strdup (cur->name);
998 val->edited = 1;
999 XtFree ((char *) pos_list);
1005 /* This function is for activating a button from a program. It's wrong because
1006 we pass a NULL argument in the call_data which is not Motif compatible.
1007 This is used from the XmNdefaultAction callback of the List widgets to
1008 have a double-click put down a dialog box like the button would do.
1009 I could not find a way to do that with accelerators.
1011 static void
1012 activate_button (widget, closure, call_data)
1013 Widget widget;
1014 XtPointer closure;
1015 XtPointer call_data;
1017 Widget button = (Widget)closure;
1018 XtCallCallbacks (button, XmNactivateCallback, NULL);
1021 /* creation functions */
1023 /* dialogs */
1024 static Widget
1025 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1026 radio_box, list, left_buttons, right_buttons)
1027 char* name;
1028 Widget parent;
1029 Boolean pop_up_p;
1030 char* shell_title;
1031 char* icon_name;
1032 Boolean text_input_slot;
1033 Boolean radio_box;
1034 Boolean list;
1035 int left_buttons;
1036 int right_buttons;
1038 Widget result;
1039 Widget form;
1040 Widget row;
1041 Widget icon;
1042 Widget icon_separator;
1043 Widget message;
1044 Widget value = 0;
1045 Widget separator;
1046 Widget button = 0;
1047 Widget children [16]; /* for the final XtManageChildren */
1048 int n_children;
1049 Arg al[64]; /* Arg List */
1050 int ac; /* Arg Count */
1051 int i;
1053 if (pop_up_p)
1055 ac = 0;
1056 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1057 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1058 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1059 result = XmCreateDialogShell (parent, "dialog", al, ac);
1060 ac = 0;
1061 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1062 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1063 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1064 form = XmCreateForm (result, shell_title, al, ac);
1066 else
1068 ac = 0;
1069 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1070 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1071 form = XmCreateForm (parent, shell_title, al, ac);
1072 result = form;
1075 n_children = left_buttons + right_buttons + 1;
1076 ac = 0;
1077 XtSetArg(al[ac], XmNpacking, n_children == 3?
1078 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1079 XtSetArg(al[ac], XmNorientation, n_children == 3?
1080 XmVERTICAL: XmHORIZONTAL); ac++;
1081 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1082 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1083 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1084 XtSetArg(al[ac], XmNspacing, 13); ac++;
1085 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1086 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1087 XtSetArg(al[ac], XmNisAligned, True); ac++;
1088 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1089 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1090 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1091 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1092 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1093 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1094 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1095 row = XmCreateRowColumn (form, "row", al, ac);
1097 n_children = 0;
1098 for (i = 0; i < left_buttons; i++)
1100 char button_name [16];
1101 sprintf (button_name, "button%d", i + 1);
1102 ac = 0;
1103 if (i == 0)
1105 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1106 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1108 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1109 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1110 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1112 if (i == 0)
1114 button = children [n_children];
1115 ac = 0;
1116 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1117 XtSetValues (row, al, ac);
1120 n_children++;
1123 /* invisible separator button */
1124 ac = 0;
1125 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1126 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1127 n_children++;
1129 for (i = 0; i < right_buttons; i++)
1131 char button_name [16];
1132 sprintf (button_name, "button%d", left_buttons + i + 1);
1133 ac = 0;
1134 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1135 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1136 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1137 if (! button) button = children [n_children];
1138 n_children++;
1141 XtManageChildren (children, n_children);
1143 ac = 0;
1144 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1145 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1146 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1147 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1148 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1149 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1150 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1151 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1152 separator = XmCreateSeparator (form, "", al, ac);
1154 ac = 0;
1155 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1156 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1157 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1158 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1159 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1160 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1161 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1162 icon = XmCreateLabel (form, icon_name, al, ac);
1164 ac = 0;
1165 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1166 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1167 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1168 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1169 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1170 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1171 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1172 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1173 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1174 icon_separator = XmCreateLabel (form, "", al, ac);
1176 if (text_input_slot)
1178 ac = 0;
1179 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1180 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1181 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1182 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1183 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1184 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1185 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1186 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1187 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1188 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1189 value = XmCreateTextField (form, "value", al, ac);
1191 else if (radio_box)
1193 Widget radio_butt;
1194 ac = 0;
1195 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1196 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1197 XtSetArg(al[ac], XmNspacing, 13); ac++;
1198 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1199 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1200 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1201 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1202 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1203 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1204 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1205 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1206 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1207 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1208 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1209 ac = 0;
1210 i = 0;
1211 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1212 children [i++] = radio_butt;
1213 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1214 children [i++] = radio_butt;
1215 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1216 children [i++] = radio_butt;
1217 XtManageChildren (children, i);
1219 else if (list)
1221 ac = 0;
1222 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1223 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1224 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1225 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1226 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1227 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1228 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1229 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1230 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1231 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1232 value = XmCreateScrolledList (form, "list", al, ac);
1234 /* this is the easiest way I found to have the dble click in the
1235 list activate the default button */
1236 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1239 ac = 0;
1240 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1241 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1242 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1243 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1244 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1245 XtSetArg(al[ac], XmNbottomWidget,
1246 text_input_slot || radio_box || list ? value : separator); ac++;
1247 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1248 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1249 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1250 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1251 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1252 message = XmCreateLabel (form, "message", al, ac);
1254 if (list)
1255 XtManageChild (value);
1257 i = 0;
1258 children [i] = row; i++;
1259 children [i] = separator; i++;
1260 if (text_input_slot || radio_box)
1262 children [i] = value; i++;
1264 children [i] = message; i++;
1265 children [i] = icon; i++;
1266 children [i] = icon_separator; i++;
1267 XtManageChildren (children, i);
1269 if (text_input_slot || list)
1271 XtInstallAccelerators (value, button);
1272 XtSetKeyboardFocus (result, value);
1274 else
1276 XtInstallAccelerators (form, button);
1277 XtSetKeyboardFocus (result, button);
1280 return result;
1283 static destroyed_instance*
1284 find_matching_instance (instance)
1285 widget_instance* instance;
1287 destroyed_instance* cur;
1288 destroyed_instance* prev;
1289 char* type = instance->info->type;
1290 char* name = instance->info->name;
1292 for (prev = NULL, cur = all_destroyed_instances;
1293 cur;
1294 prev = cur, cur = cur->next)
1296 if (!strcmp (cur->name, name)
1297 && !strcmp (cur->type, type)
1298 && cur->parent == instance->parent
1299 && cur->pop_up_p == instance->pop_up_p)
1301 if (prev)
1302 prev->next = cur->next;
1303 else
1304 all_destroyed_instances = cur->next;
1305 return cur;
1307 /* do some cleanup */
1308 else if (!cur->widget)
1310 if (prev)
1311 prev->next = cur->next;
1312 else
1313 all_destroyed_instances = cur->next;
1314 free_destroyed_instance (cur);
1315 cur = prev ? prev : all_destroyed_instances;
1318 return NULL;
1321 static void
1322 mark_dead_instance_destroyed (widget, closure, call_data)
1323 Widget widget;
1324 XtPointer closure;
1325 XtPointer call_data;
1327 destroyed_instance* instance = (destroyed_instance*)closure;
1328 instance->widget = NULL;
1331 static void
1332 recenter_widget (widget)
1333 Widget widget;
1335 Widget parent = XtParent (widget);
1336 Screen* screen = XtScreen (widget);
1337 Dimension screen_width = WidthOfScreen (screen);
1338 Dimension screen_height = HeightOfScreen (screen);
1339 Dimension parent_width = 0;
1340 Dimension parent_height = 0;
1341 Dimension child_width = 0;
1342 Dimension child_height = 0;
1343 Position x;
1344 Position y;
1346 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1347 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1348 NULL);
1350 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1351 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1353 XtTranslateCoords (parent, x, y, &x, &y);
1355 if (x + child_width > screen_width)
1356 x = screen_width - child_width;
1357 if (x < 0)
1358 x = 0;
1360 if (y + child_height > screen_height)
1361 y = screen_height - child_height;
1362 if (y < 0)
1363 y = 0;
1365 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1368 static Widget
1369 recycle_instance (instance)
1370 destroyed_instance* instance;
1372 Widget widget = instance->widget;
1374 /* widget is NULL if the parent was destroyed. */
1375 if (widget)
1377 Widget focus;
1378 Widget separator;
1380 /* Remove the destroy callback as the instance is not in the list
1381 anymore */
1382 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1383 mark_dead_instance_destroyed,
1384 (XtPointer)instance);
1386 /* Give the focus to the initial item */
1387 focus = XtNameToWidget (widget, "*value");
1388 if (!focus)
1389 focus = XtNameToWidget (widget, "*button1");
1390 if (focus)
1391 XtSetKeyboardFocus (widget, focus);
1393 /* shrink the separator label back to their original size */
1394 separator = XtNameToWidget (widget, "*separator_button");
1395 if (separator)
1396 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1398 /* Center the dialog in its parent */
1399 recenter_widget (widget);
1401 free_destroyed_instance (instance);
1402 return widget;
1405 Widget
1406 xm_create_dialog (instance)
1407 widget_instance* instance;
1409 char* name = instance->info->type;
1410 Widget parent = instance->parent;
1411 Widget widget;
1412 Boolean pop_up_p = instance->pop_up_p;
1413 char* shell_name = 0;
1414 char* icon_name;
1415 Boolean text_input_slot = False;
1416 Boolean radio_box = False;
1417 Boolean list = False;
1418 int total_buttons;
1419 int left_buttons = 0;
1420 int right_buttons = 1;
1421 destroyed_instance* dead_one;
1423 /* try to find a widget to recycle */
1424 dead_one = find_matching_instance (instance);
1425 if (dead_one)
1427 Widget recycled_widget = recycle_instance (dead_one);
1428 if (recycled_widget)
1429 return recycled_widget;
1432 switch (name [0]){
1433 case 'E': case 'e':
1434 icon_name = "dbox-error";
1435 shell_name = "Error";
1436 break;
1438 case 'I': case 'i':
1439 icon_name = "dbox-info";
1440 shell_name = "Information";
1441 break;
1443 case 'L': case 'l':
1444 list = True;
1445 icon_name = "dbox-question";
1446 shell_name = "Prompt";
1447 break;
1449 case 'P': case 'p':
1450 text_input_slot = True;
1451 icon_name = "dbox-question";
1452 shell_name = "Prompt";
1453 break;
1455 case 'Q': case 'q':
1456 icon_name = "dbox-question";
1457 shell_name = "Question";
1458 break;
1461 total_buttons = name [1] - '0';
1463 if (name [3] == 'T' || name [3] == 't')
1465 text_input_slot = False;
1466 radio_box = True;
1468 else if (name [3])
1469 right_buttons = name [4] - '0';
1471 left_buttons = total_buttons - right_buttons;
1473 widget = make_dialog (name, parent, pop_up_p,
1474 shell_name, icon_name, text_input_slot, radio_box,
1475 list, left_buttons, right_buttons);
1477 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1478 (XtPointer) instance);
1479 return widget;
1482 /* Create a menu bar. We turn off the f10 key
1483 because we have not yet managed to make it work right in Motif. */
1485 static Widget
1486 make_menubar (instance)
1487 widget_instance* instance;
1489 Arg al[3];
1490 int ac;
1492 ac = 0;
1493 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1495 #if 0
1496 /* As of 2000-01-17, the LessTif menu bar resizes to height 0 when
1497 all its children are removed, causing an annoying flickering
1498 behavior. Prevent that by not allowing resizing. */
1499 XtSetArg(al[ac], XmNresizeHeight, False); ++ac;
1500 XtSetArg(al[ac], XmNresizeWidth, False); ++ac;
1501 #endif
1503 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1506 static void
1507 remove_grabs (shell, closure, call_data)
1508 Widget shell;
1509 XtPointer closure;
1510 XtPointer call_data;
1512 Widget menu = (Widget) closure;
1513 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1516 static Widget
1517 make_popup_menu (instance)
1518 widget_instance* instance;
1520 Widget parent = instance->parent;
1521 Window parent_window = parent->core.window;
1522 Widget result;
1524 /* sets the parent window to 0 to fool Motif into not generating a grab */
1525 parent->core.window = 0;
1526 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1527 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1528 (XtPointer)result);
1529 parent->core.window = parent_window;
1530 return result;
1533 static Widget
1534 make_main (instance)
1535 widget_instance* instance;
1537 Widget parent = instance->parent;
1538 Widget result;
1539 Arg al[2];
1540 int ac;
1542 ac = 0;
1543 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1544 XtSetArg (al[ac], XmNspacing, 0); ac++;
1545 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1546 return result;
1549 \f/* Table of functions to create widgets */
1551 #ifdef ENERGIZE
1553 /* interface with the XDesigner generated functions */
1554 typedef Widget (*widget_maker) (Widget);
1555 extern Widget create_project_p_sheet (Widget parent);
1556 extern Widget create_debugger_p_sheet (Widget parent);
1557 extern Widget create_breaklist_p_sheet (Widget parent);
1558 extern Widget create_le_browser_p_sheet (Widget parent);
1559 extern Widget create_class_browser_p_sheet (Widget parent);
1560 extern Widget create_call_browser_p_sheet (Widget parent);
1561 extern Widget create_build_dialog (Widget parent);
1562 extern Widget create_editmode_dialog (Widget parent);
1563 extern Widget create_search_dialog (Widget parent);
1564 extern Widget create_project_display_dialog (Widget parent);
1566 static Widget
1567 make_one (widget_instance* instance, widget_maker fn)
1569 Widget result;
1570 Arg al [64];
1571 int ac = 0;
1573 if (instance->pop_up_p)
1575 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1576 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1577 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1578 (XtPointer) instance);
1579 (*fn) (result);
1581 else
1583 result = (*fn) (instance->parent);
1584 XtRealizeWidget (result);
1586 return result;
1589 static Widget
1590 make_project_p_sheet (widget_instance* instance)
1592 return make_one (instance, create_project_p_sheet);
1595 static Widget
1596 make_debugger_p_sheet (widget_instance* instance)
1598 return make_one (instance, create_debugger_p_sheet);
1601 static Widget
1602 make_breaklist_p_sheet (widget_instance* instance)
1604 return make_one (instance, create_breaklist_p_sheet);
1607 static Widget
1608 make_le_browser_p_sheet (widget_instance* instance)
1610 return make_one (instance, create_le_browser_p_sheet);
1613 static Widget
1614 make_class_browser_p_sheet (widget_instance* instance)
1616 return make_one (instance, create_class_browser_p_sheet);
1619 static Widget
1620 make_call_browser_p_sheet (widget_instance* instance)
1622 return make_one (instance, create_call_browser_p_sheet);
1625 static Widget
1626 make_build_dialog (widget_instance* instance)
1628 return make_one (instance, create_build_dialog);
1631 static Widget
1632 make_editmode_dialog (widget_instance* instance)
1634 return make_one (instance, create_editmode_dialog);
1637 static Widget
1638 make_search_dialog (widget_instance* instance)
1640 return make_one (instance, create_search_dialog);
1643 static Widget
1644 make_project_display_dialog (widget_instance* instance)
1646 return make_one (instance, create_project_display_dialog);
1649 #endif /* ENERGIZE */
1651 widget_creation_entry
1652 xm_creation_table [] =
1654 {"menubar", make_menubar},
1655 {"popup", make_popup_menu},
1656 {"main", make_main},
1657 #ifdef ENERGIZE
1658 {"project_p_sheet", make_project_p_sheet},
1659 {"debugger_p_sheet", make_debugger_p_sheet},
1660 {"breaklist_psheet", make_breaklist_p_sheet},
1661 {"leb_psheet", make_le_browser_p_sheet},
1662 {"class_browser_psheet", make_class_browser_p_sheet},
1663 {"ctree_browser_psheet", make_call_browser_p_sheet},
1664 {"build", make_build_dialog},
1665 {"editmode", make_editmode_dialog},
1666 {"search", make_search_dialog},
1667 {"project_display", make_project_display_dialog},
1668 #endif /* ENERGIZE */
1669 {NULL, NULL}
1672 \f/* Destruction of instances */
1673 void
1674 xm_destroy_instance (instance)
1675 widget_instance* instance;
1677 Widget widget = instance->widget;
1678 /* recycle the dialog boxes */
1679 /* Disable the recycling until we can find a way to have the dialog box
1680 get reasonable layout after we modify its contents. */
1681 if (0
1682 && XtClass (widget) == xmDialogShellWidgetClass)
1684 destroyed_instance* dead_instance =
1685 make_destroyed_instance (instance->info->name,
1686 instance->info->type,
1687 instance->widget,
1688 instance->parent,
1689 instance->pop_up_p);
1690 dead_instance->next = all_destroyed_instances;
1691 all_destroyed_instances = dead_instance;
1692 XtUnmanageChild (first_child (instance->widget));
1693 XFlush (XtDisplay (instance->widget));
1694 XtAddCallback (instance->parent, XtNdestroyCallback,
1695 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1697 else
1699 /* This might not be necessary now that the nosel is attached to
1700 popdown instead of destroy, but it can't hurt. */
1701 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1702 xm_nosel_callback, (XtPointer)instance);
1703 XtDestroyWidget (instance->widget);
1707 \f/* popup utility */
1708 void
1709 xm_popup_menu (widget, event)
1710 Widget widget;
1711 XEvent *event;
1713 XButtonPressedEvent dummy;
1715 if (event == 0)
1717 dummy.type = ButtonPress;
1718 dummy.serial = 0;
1719 dummy.send_event = 0;
1720 dummy.display = XtDisplay (widget);
1721 dummy.window = XtWindow (XtParent (widget));
1722 dummy.time = 0;
1723 dummy.button = 0;
1724 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1725 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1726 &dummy.x, &dummy.y, &dummy.state);
1727 event = (XEvent *) &dummy;
1730 if (event->type == ButtonPress || event->type == ButtonRelease)
1732 /* This is so totally ridiculous: there's NO WAY to tell Motif
1733 that *any* button can select a menu item. Only one button
1734 can have that honor.
1736 char *trans = 0;
1737 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1738 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1739 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1740 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1741 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1742 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1743 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1745 XtManageChild (widget);
1748 static void
1749 set_min_dialog_size (w)
1750 Widget w;
1752 short width;
1753 short height;
1754 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1755 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1758 void
1759 xm_pop_instance (instance, up)
1760 widget_instance* instance;
1761 Boolean up;
1763 Widget widget = instance->widget;
1765 if (XtClass (widget) == xmDialogShellWidgetClass)
1767 Widget widget_to_manage = first_child (widget);
1768 if (up)
1770 XtManageChild (widget_to_manage);
1771 set_min_dialog_size (widget);
1772 XtSetKeyboardFocus (instance->parent, widget);
1774 else
1775 XtUnmanageChild (widget_to_manage);
1777 else
1779 if (up)
1780 XtManageChild (widget);
1781 else
1782 XtUnmanageChild (widget);
1787 /* motif callback */
1789 static void
1790 do_call (widget, closure, type)
1791 Widget widget;
1792 XtPointer closure;
1793 enum do_call_type type;
1795 Arg al [256];
1796 int ac;
1797 XtPointer user_data;
1798 widget_instance* instance = (widget_instance*)closure;
1799 Widget instance_widget;
1800 LWLIB_ID id;
1802 if (!instance)
1803 return;
1804 if (widget->core.being_destroyed)
1805 return;
1807 instance_widget = instance->widget;
1808 if (!instance_widget)
1809 return;
1811 id = instance->info->id;
1812 ac = 0;
1813 user_data = NULL;
1814 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1815 XtGetValues (widget, al, ac);
1816 switch (type)
1818 case pre_activate:
1819 if (instance->info->pre_activate_cb)
1820 instance->info->pre_activate_cb (widget, id, user_data);
1821 break;
1822 case selection:
1823 if (instance->info->selection_cb)
1824 instance->info->selection_cb (widget, id, user_data);
1825 break;
1826 case no_selection:
1827 if (instance->info->selection_cb)
1828 instance->info->selection_cb (widget, id, (XtPointer) -1);
1829 break;
1830 case post_activate:
1831 if (instance->info->post_activate_cb)
1832 instance->info->post_activate_cb (widget, id, user_data);
1833 break;
1834 default:
1835 abort ();
1839 /* Like lw_internal_update_other_instances except that it does not do
1840 anything if its shell parent is not managed. This is to protect
1841 lw_internal_update_other_instances to dereference freed memory
1842 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1843 list */
1844 static void
1845 xm_internal_update_other_instances (widget, closure, call_data)
1846 Widget widget;
1847 XtPointer closure;
1848 XtPointer call_data;
1850 Widget parent;
1851 for (parent = widget; parent; parent = XtParent (parent))
1852 if (XtIsShell (parent))
1853 break;
1854 else if (!XtIsManaged (parent))
1855 return;
1856 lw_internal_update_other_instances (widget, closure, call_data);
1859 static void
1860 xm_generic_callback (widget, closure, call_data)
1861 Widget widget;
1862 XtPointer closure;
1863 XtPointer call_data;
1865 lw_internal_update_other_instances (widget, closure, call_data);
1866 do_call (widget, closure, selection);
1869 static void
1870 xm_nosel_callback (widget, closure, call_data)
1871 Widget widget;
1872 XtPointer closure;
1873 XtPointer call_data;
1875 /* This callback is only called when a dialog box is dismissed with the wm's
1876 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1877 in that case, not just unmapped, so that it releases its keyboard grabs.
1878 But there are problems with running our callbacks while the widget is in
1879 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1880 instead of XmDESTROY and then destroy it ourself after having run the
1881 callback.
1883 do_call (widget, closure, no_selection);
1884 XtDestroyWidget (widget);
1887 static void
1888 xm_pull_down_callback (widget, closure, call_data)
1889 Widget widget;
1890 XtPointer closure;
1891 XtPointer call_data;
1893 Widget parent = XtParent (widget);
1895 if (XmIsRowColumn (parent))
1897 unsigned char type = 0xff;
1898 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1899 if (type == XmMENU_BAR)
1900 do_call (widget, closure, pre_activate);
1905 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1906 CLOSURE is a pointer to the widget_instance of the shell, CALL_DATA
1907 is always null under LessTif.
1909 2000-01-23: This callback is called for each cascade button in
1910 a menu, whether or not its submenu is visible. */
1912 static void
1913 xm_pop_down_callback (widget, closure, call_data)
1914 Widget widget;
1915 XtPointer closure;
1916 XtPointer call_data;
1918 widget_instance *instance = (widget_instance *) closure;
1920 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1921 || (XtParent (widget) == instance->parent))
1922 do_call (widget, closure, post_activate);
1925 static void
1926 xm_unmap_callback (widget, closure, call_data)
1927 Widget widget;
1928 XtPointer closure;
1929 XtPointer call_data;
1931 widget_instance *instance = (widget_instance *) closure;
1932 if (!instance->pop_up_p)
1933 do_call (widget, closure, post_activate);
1937 /* set the keyboard focus */
1938 void
1939 xm_set_keyboard_focus (parent, w)
1940 Widget parent;
1941 Widget w;
1943 XmProcessTraversal (w, 0);
1944 XtSetKeyboardFocus (parent, w);
1947 /* Motif hack to set the main window areas. */
1948 void
1949 xm_set_main_areas (parent, menubar, work_area)
1950 Widget parent;
1951 Widget menubar;
1952 Widget work_area;
1954 XmMainWindowSetAreas (parent,
1955 menubar, /* menubar (maybe 0) */
1956 0, /* command area (psheets) */
1957 0, /* horizontal scroll */
1958 0, /* vertical scroll */
1959 work_area); /* work area */
1962 /* Motif hack to control resizing on the menubar. */
1963 void
1964 xm_manage_resizing (w, flag)
1965 Widget w;
1966 Boolean flag;
1968 XtVaSetValues (w, XtNallowShellResize, flag, NULL);