* editfns.c (Fdelete_and_extract_region): New function.
[emacs.git] / lwlib / lwlib-Xm.c
blob460839f8a09ad40ea5140c1474cda03448741d16
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 #ifdef __STDC__
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 void xm_set_keyboard_focus P_ ((Widget, Widget));
129 void xm_set_main_areas P_ ((Widget, Widget, Widget));
130 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
131 XtPointer));
133 #if 0
134 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
135 Boolean));
136 void xm_pop_instance P_ ((widget_instance*, Boolean));
137 void xm_manage_resizing P_ ((Widget, Boolean));
138 #endif
141 static destroyed_instance*
142 all_destroyed_instances = NULL;
144 static destroyed_instance*
145 make_destroyed_instance (name, type, widget, parent, pop_up_p)
146 char* name;
147 char* type;
148 Widget widget;
149 Widget parent;
150 Boolean pop_up_p;
152 destroyed_instance* instance =
153 (destroyed_instance*)malloc (sizeof (destroyed_instance));
154 instance->name = safe_strdup (name);
155 instance->type = safe_strdup (type);
156 instance->widget = widget;
157 instance->parent = parent;
158 instance->pop_up_p = pop_up_p;
159 instance->next = NULL;
160 return instance;
163 static void
164 free_destroyed_instance (instance)
165 destroyed_instance* instance;
167 free (instance->name);
168 free (instance->type);
169 free (instance);
172 \f/* motif utility functions */
173 Widget
174 first_child (widget)
175 Widget widget;
177 return ((CompositeWidget)widget)->composite.children [0];
180 Boolean
181 lw_motif_widget_p (widget)
182 Widget widget;
184 return
185 XtClass (widget) == xmDialogShellWidgetClass
186 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
189 static XmString
190 resource_motif_string (widget, name)
191 Widget widget;
192 char* name;
194 XtResource resource;
195 XmString result = 0;
197 resource.resource_name = name;
198 resource.resource_class = XmCXmString;
199 resource.resource_type = XmRXmString;
200 resource.resource_size = sizeof (XmString);
201 resource.resource_offset = 0;
202 resource.default_type = XtRImmediate;
203 resource.default_addr = 0;
205 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
206 "DialogString", &resource, 1, NULL, 0);
207 return result;
210 /* Destroy all of the children of WIDGET
211 starting with number FIRST_CHILD_TO_DESTROY. */
213 static void
214 destroy_all_children (widget, first_child_to_destroy)
215 Widget widget;
216 int first_child_to_destroy;
218 Widget* children;
219 unsigned int number;
220 int i;
222 children = XtCompositeChildren (widget, &number);
223 if (children)
225 XtUnmanageChildren (children + first_child_to_destroy,
226 number - first_child_to_destroy);
228 /* Unmanage all children and destroy them. They will only be
229 really destroyed when we get out of DispatchEvent. */
230 for (i = first_child_to_destroy; i < number; i++)
232 Arg al[2];
233 Widget submenu = 0;
234 /* Cascade buttons have submenus,and these submenus
235 need to be freed. But they are not included in
236 XtCompositeChildren. So get it out of the cascade button
237 and free it. If this child is not a cascade button,
238 then submenu should remain unchanged. */
239 XtSetArg (al[0], XmNsubMenuId, &submenu);
240 XtGetValues (children[i], al, 1);
241 if (submenu)
242 XtDestroyWidget (submenu);
243 XtDestroyWidget (children[i]);
246 XtFree ((char *) children);
251 /* Update the label of widget WIDGET. WIDGET must be a Label widget
252 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
253 the value to update.
255 Menus:
257 Emacs fills VAL->name with the text to display in the menu, and
258 sets VAL->value to null. Function make_menu_in_widget creates
259 widgets with VAL->name as resource name. This works because the
260 Label widget uses its resource name for display if no
261 XmNlabelString is set.
263 Dialogs:
265 VAL->name is again set to the resource name, but VAL->value is
266 not null, and contains the label string to display. */
268 static void
269 xm_update_label (instance, widget, val)
270 widget_instance* instance;
271 Widget widget;
272 widget_value* val;
274 XmString res_string = 0;
275 XmString built_string = 0;
276 XmString key_string = 0;
277 Arg al [256];
278 int ac;
280 ac = 0;
282 if (val->value)
284 /* A label string is specified, i.e. we are in a dialog. First
285 see if it is overridden by something from the resource file. */
286 res_string = resource_motif_string (widget, val->value);
288 if (res_string)
290 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
292 else
294 built_string =
295 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
296 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
299 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
302 if (val->key)
304 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
305 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
308 if (ac)
309 XtSetValues (widget, al, ac);
311 if (built_string)
312 XmStringFree (built_string);
314 if (key_string)
315 XmStringFree (key_string);
318 \f/* update of list */
319 static void
320 xm_update_list (instance, widget, val)
321 widget_instance* instance;
322 Widget widget;
323 widget_value* val;
325 widget_value* cur;
326 int i;
327 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
328 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
329 instance);
330 for (cur = val->contents, i = 0; cur; cur = cur->next)
331 if (cur->value)
333 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
334 i += 1;
335 XmListAddItem (widget, xmstr, 0);
336 if (cur->selected)
337 XmListSelectPos (widget, i, False);
338 XmStringFree (xmstr);
342 \f/* update of buttons */
343 static void
344 xm_update_pushbutton (instance, widget, val)
345 widget_instance* instance;
346 Widget widget;
347 widget_value* val;
349 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
350 XtRemoveAllCallbacks (widget, XmNactivateCallback);
351 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
354 static void
355 xm_update_cascadebutton (instance, widget, val)
356 widget_instance* instance;
357 Widget widget;
358 widget_value* val;
360 /* Should also rebuild the menu by calling ...update_menu... */
361 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
362 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
363 instance);
366 \f/* update toggle and radiobox */
367 static void
368 xm_update_toggle (instance, widget, val)
369 widget_instance* instance;
370 Widget widget;
371 widget_value* val;
373 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
374 XtAddCallback (widget, XmNvalueChangedCallback,
375 xm_generic_callback, instance);
376 XtVaSetValues (widget, XmNset, val->selected,
377 XmNalignment, XmALIGNMENT_BEGINNING, 0);
380 static void
381 xm_update_radiobox (instance, widget, val)
382 widget_instance* instance;
383 Widget widget;
384 widget_value* val;
387 Widget toggle;
388 widget_value* cur;
390 /* update the callback */
391 XtRemoveAllCallbacks (widget, XmNentryCallback);
392 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
394 /* first update all the toggles */
395 /* Energize kernel interface is currently bad. It sets the selected widget
396 with the selected flag but returns it by its name. So we currently
397 have to support both setting the selection with the selected slot
398 of val contents and setting it with the "value" slot of val. The latter
399 has a higher priority. This to be removed when the kernel is fixed. */
400 for (cur = val->contents; cur; cur = cur->next)
402 toggle = XtNameToWidget (widget, cur->value);
403 if (toggle)
405 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
406 if (!val->value && cur->selected)
407 XtVaSetValues (toggle, XmNset, cur->selected, 0);
408 if (val->value && strcmp (val->value, cur->value))
409 XtVaSetValues (toggle, XmNset, False, 0);
413 /* The selected was specified by the value slot */
414 if (val->value)
416 toggle = XtNameToWidget (widget, val->value);
417 if (toggle)
418 XtVaSetValues (toggle, XmNset, True, 0);
423 /* update a popup menu, pulldown menu or a menubar */
425 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
427 static void
428 make_menu_in_widget (instance, widget, val, keep_first_children)
429 widget_instance* instance;
430 Widget widget;
431 widget_value* val;
432 int keep_first_children;
434 Widget* children = 0;
435 int num_children;
436 int child_index;
437 widget_value* cur;
438 Widget button = 0;
439 Widget title = 0;
440 Widget menu;
441 Arg al [256];
442 int ac;
443 Boolean menubar_p;
444 unsigned char type;
446 Widget* old_children;
447 unsigned int old_num_children;
449 old_children = XtCompositeChildren (widget, &old_num_children);
451 /* Allocate the children array */
452 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
453 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
455 /* WIDGET should be a RowColumn. */
456 if (!XmIsRowColumn (widget))
457 abort ();
459 /* Determine whether WIDGET is a menu bar. */
460 type = -1;
461 XtSetArg (al[0], XmNrowColumnType, &type);
462 XtGetValues (widget, al, 1);
463 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
464 abort ();
465 menubar_p = type == XmMENU_BAR;
467 /* Add a callback to popups and pulldowns that is called when
468 it is made invisible again. */
469 if (!menubar_p)
470 XtAddCallback (XtParent (widget), XmNpopdownCallback,
471 xm_pop_down_callback, (XtPointer)instance);
473 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
474 for (child_index = 0, cur = val; child_index < keep_first_children;
475 child_index++, cur = cur->next)
476 children[child_index] = old_children[child_index];
478 /* Check that those are all we have
479 (the caller should have deleted the rest). */
480 if (old_num_children != keep_first_children)
481 abort ();
483 /* Create the rest. */
484 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
486 enum menu_separator separator;
488 ac = 0;
489 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
490 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
491 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
493 if (instance->pop_up_p && !cur->contents && !cur->call_data
494 && !lw_separator_p (cur->name, &separator, 1))
496 ac = 0;
497 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
498 title = button = XmCreateLabel (widget, cur->name, al, ac);
500 else if (lw_separator_p (cur->name, &separator, 1))
502 ac = 0;
503 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
504 button = XmCreateSeparator (widget, cur->name, al, ac);
506 else if (!cur->contents)
508 if (menubar_p)
509 button = XmCreateCascadeButton (widget, cur->name, al, ac);
510 else if (!cur->call_data)
511 button = XmCreateLabel (widget, cur->name, al, ac);
512 else if (cur->button_type == BUTTON_TYPE_TOGGLE
513 || cur->button_type == BUTTON_TYPE_RADIO)
515 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
516 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
517 XtSetArg (al[ac], XmNindicatorType,
518 (cur->button_type == BUTTON_TYPE_TOGGLE
519 ? XmN_OF_MANY : XmONE_OF_MANY));
520 ++ac;
521 button = XmCreateToggleButton (widget, cur->name, al, ac);
523 else
524 button = XmCreatePushButton (widget, cur->name, al, ac);
526 xm_update_label (instance, button, cur);
528 /* Add a callback that is called when the button is
529 selected. Toggle buttons don't support
530 XmNactivateCallback, we use XmNvalueChangedCallback in
531 that case. Don't add a callback to a simple label. */
532 if (cur->button_type)
533 xm_update_toggle (instance, button, cur);
534 else if (cur->call_data)
535 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
536 (XtPointer)instance);
538 else
540 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
541 make_menu_in_widget (instance, menu, cur->contents, 0);
542 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
543 /* Non-zero values don't work reliably in conjunction with
544 Emacs' event loop */
545 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
546 button = XmCreateCascadeButton (widget, cur->name, al, ac);
548 xm_update_label (instance, button, cur);
550 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
551 (XtPointer)instance);
554 children[child_index] = button;
557 /* Last entry is the help button. The original comment read "Has to
558 be done after managing the buttons otherwise the menubar is only
559 4 pixels high." This is no longer true, and to make
560 XmNmenuHelpWidget work, we need to set it before managing the
561 children.. --gerd. */
562 if (button)
563 XtVaSetValues (widget, XmNmenuHelpWidget, button, 0);
565 /* LessTif apparently doesn't recompute centered text when more
566 widgets are added. So, do it after all widgets have been
567 created. */
568 if (title)
569 XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, 0);
571 if (num_children)
572 XtManageChildren (children, num_children);
574 XtFree ((char *) children);
575 if (old_children)
576 XtFree ((char *) old_children);
579 static void
580 update_one_menu_entry (instance, widget, val, deep_p)
581 widget_instance* instance;
582 Widget widget;
583 widget_value* val;
584 Boolean deep_p;
586 Arg al [256];
587 int ac;
588 Widget menu;
589 widget_value* contents;
591 if (val->this_one_change == NO_CHANGE)
592 return;
594 /* update the sensitivity and userdata */
595 /* Common to all widget types */
596 XtVaSetValues (widget,
597 XmNsensitive, val->enabled,
598 XmNuserData, val->call_data,
601 /* update the menu button as a label. */
602 if (val->this_one_change >= VISIBLE_CHANGE)
604 xm_update_label (instance, widget, val);
605 if (val->button_type)
606 xm_update_toggle (instance, widget, val);
609 /* update the pulldown/pullaside as needed */
610 ac = 0;
611 menu = NULL;
612 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
613 XtGetValues (widget, al, ac);
615 contents = val->contents;
617 if (!menu)
619 if (contents)
621 unsigned int old_num_children, i;
622 Widget parent;
623 Widget *widget_list;
625 parent = XtParent (widget);
626 widget_list = XtCompositeChildren (parent, &old_num_children);
628 /* Find the widget position within the parent's widget list. */
629 for (i = 0; i < old_num_children; i++)
630 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
631 break;
632 if (i == old_num_children)
633 abort ();
634 if (XmIsCascadeButton (widget_list[i]))
636 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
637 make_menu_in_widget (instance, menu, contents, 0);
638 ac = 0;
639 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
640 XtSetValues (widget, al, ac);
642 else
644 Widget button;
646 /* The current menuitem is a XmPushButtonGadget, it
647 needs to be replaced by a CascadeButtonGadget */
648 XtDestroyWidget (widget_list[i]);
649 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
650 make_menu_in_widget (instance, menu, contents, 0);
651 ac = 0;
652 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
653 /* Non-zero values don't work reliably in
654 conjunction with Emacs' event loop */
655 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
656 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
657 /* Tell Motif to put it in the right place */
658 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
659 #endif
660 button = XmCreateCascadeButton (parent, val->name, al, ac);
661 xm_update_label (instance, button, val);
663 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
664 (XtPointer)instance);
665 XtManageChild (button);
669 else if (!contents)
671 ac = 0;
672 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
673 XtSetValues (widget, al, ac);
674 XtDestroyWidget (menu);
676 else if (deep_p && contents->change != NO_CHANGE)
677 xm_update_menu (instance, menu, val, 1);
680 static void
681 xm_update_menu (instance, widget, val, deep_p)
682 widget_instance* instance;
683 Widget widget;
684 widget_value* val;
685 Boolean deep_p;
687 Widget* children;
688 unsigned int num_children;
689 int num_children_to_keep = 0;
690 int i;
691 widget_value* cur;
693 children = XtCompositeChildren (widget, &num_children);
695 /* Widget is a RowColumn widget whose contents have to be updated
696 * to reflect the list of items in val->contents */
698 /* See how many buttons we can keep, and how many we
699 must completely replace. */
700 if (val->contents == 0)
701 num_children_to_keep = 0;
702 else if (val->contents->change == STRUCTURAL_CHANGE)
704 if (children)
706 for (i = 0, cur = val->contents;
707 (i < num_children
708 && cur); /* how else to ditch unwanted children ?? - mgd */
709 i++, cur = cur->next)
711 if (cur->this_one_change == STRUCTURAL_CHANGE)
712 break;
715 num_children_to_keep = i;
718 else
719 num_children_to_keep = num_children;
721 /* Update all the buttons of the RowColumn, in order,
722 except for those we are going to replace entirely. */
723 if (children)
725 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
727 if (!cur)
729 num_children_to_keep = i;
730 break;
732 if (children [i]->core.being_destroyed
733 || strcmp (XtName (children [i]), cur->name))
734 continue;
735 update_one_menu_entry (instance, children [i], cur, deep_p);
736 cur = cur->next;
740 /* Now replace from scratch all the buttons after the last
741 place that the top-level structure changed. */
742 if (val->contents->change == STRUCTURAL_CHANGE)
744 destroy_all_children (widget, num_children_to_keep);
745 make_menu_in_widget (instance, widget, val->contents,
746 num_children_to_keep);
749 XtFree ((char *) children);
753 /* update text widgets */
755 static void
756 xm_update_text (instance, widget, val)
757 widget_instance* instance;
758 Widget widget;
759 widget_value* val;
761 XmTextSetString (widget, val->value ? val->value : "");
762 XtRemoveAllCallbacks (widget, XmNactivateCallback);
763 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
764 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
765 XtAddCallback (widget, XmNvalueChangedCallback,
766 xm_internal_update_other_instances, instance);
769 static void
770 xm_update_text_field (instance, widget, val)
771 widget_instance* instance;
772 Widget widget;
773 widget_value* val;
775 XmTextFieldSetString (widget, val->value ? val->value : "");
776 XtRemoveAllCallbacks (widget, XmNactivateCallback);
777 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
778 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
779 XtAddCallback (widget, XmNvalueChangedCallback,
780 xm_internal_update_other_instances, instance);
784 /* update a motif widget */
786 void
787 xm_update_one_widget (instance, widget, val, deep_p)
788 widget_instance* instance;
789 Widget widget;
790 widget_value* val;
791 Boolean deep_p;
793 WidgetClass class;
795 /* Mark as not edited */
796 val->edited = False;
798 /* Common to all widget types */
799 XtVaSetValues (widget,
800 XmNsensitive, val->enabled,
801 XmNuserData, val->call_data,
804 /* Common to all label like widgets */
805 if (XtIsSubclass (widget, xmLabelWidgetClass))
806 xm_update_label (instance, widget, val);
808 class = XtClass (widget);
809 /* Class specific things */
810 if (class == xmPushButtonWidgetClass ||
811 class == xmArrowButtonWidgetClass)
813 xm_update_pushbutton (instance, widget, val);
815 else if (class == xmCascadeButtonWidgetClass)
817 xm_update_cascadebutton (instance, widget, val);
819 else if (class == xmToggleButtonWidgetClass
820 || class == xmToggleButtonGadgetClass)
822 xm_update_toggle (instance, widget, val);
824 else if (class == xmRowColumnWidgetClass)
826 Boolean radiobox = 0;
827 int ac = 0;
828 Arg al [1];
830 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
831 XtGetValues (widget, al, ac);
833 if (radiobox)
834 xm_update_radiobox (instance, widget, val);
835 else
836 xm_update_menu (instance, widget, val, deep_p);
838 else if (class == xmTextWidgetClass)
840 xm_update_text (instance, widget, val);
842 else if (class == xmTextFieldWidgetClass)
844 xm_update_text_field (instance, widget, val);
846 else if (class == xmListWidgetClass)
848 xm_update_list (instance, widget, val);
852 \f/* getting the value back */
853 void
854 xm_update_one_value (instance, widget, val)
855 widget_instance* instance;
856 Widget widget;
857 widget_value* val;
859 WidgetClass class = XtClass (widget);
860 widget_value *old_wv;
862 /* copy the call_data slot into the "return" widget_value */
863 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
864 if (!strcmp (val->name, old_wv->name))
866 val->call_data = old_wv->call_data;
867 break;
870 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
872 XtVaGetValues (widget, XmNset, &val->selected, 0);
873 val->edited = True;
875 else if (class == xmTextWidgetClass)
877 if (val->value)
878 free (val->value);
879 val->value = XmTextGetString (widget);
880 val->edited = True;
882 else if (class == xmTextFieldWidgetClass)
884 if (val->value)
885 free (val->value);
886 val->value = XmTextFieldGetString (widget);
887 val->edited = True;
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)
900 CompositeWidget radio = (CompositeWidget)widget;
901 int i;
902 for (i = 0; i < radio->composite.num_children; i++)
904 int set = False;
905 Widget toggle = radio->composite.children [i];
907 XtVaGetValues (toggle, XmNset, &set, 0);
908 if (set)
910 if (val->value)
911 free (val->value);
912 val->value = safe_strdup (XtName (toggle));
915 val->edited = True;
918 else if (class == xmListWidgetClass)
920 int pos_cnt;
921 int* pos_list;
922 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
924 int i;
925 widget_value* cur;
926 for (cur = val->contents, i = 0; cur; cur = cur->next)
927 if (cur->value)
929 int j;
930 cur->selected = False;
931 i += 1;
932 for (j = 0; j < pos_cnt; j++)
933 if (pos_list [j] == i)
935 cur->selected = True;
936 val->value = safe_strdup (cur->name);
939 val->edited = 1;
940 XtFree ((char *) pos_list);
946 /* This function is for activating a button from a program. It's wrong because
947 we pass a NULL argument in the call_data which is not Motif compatible.
948 This is used from the XmNdefaultAction callback of the List widgets to
949 have a double-click put down a dialog box like the button would do.
950 I could not find a way to do that with accelerators.
952 static void
953 activate_button (widget, closure, call_data)
954 Widget widget;
955 XtPointer closure;
956 XtPointer call_data;
958 Widget button = (Widget)closure;
959 XtCallCallbacks (button, XmNactivateCallback, NULL);
962 /* creation functions */
964 /* dialogs */
965 static Widget
966 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
967 radio_box, list, left_buttons, right_buttons)
968 char* name;
969 Widget parent;
970 Boolean pop_up_p;
971 char* shell_title;
972 char* icon_name;
973 Boolean text_input_slot;
974 Boolean radio_box;
975 Boolean list;
976 int left_buttons;
977 int right_buttons;
979 Widget result;
980 Widget form;
981 Widget row;
982 Widget icon;
983 Widget icon_separator;
984 Widget message;
985 Widget value = 0;
986 Widget separator;
987 Widget button = 0;
988 Widget children [16]; /* for the final XtManageChildren */
989 int n_children;
990 Arg al[64]; /* Arg List */
991 int ac; /* Arg Count */
992 int i;
994 if (pop_up_p)
996 ac = 0;
997 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
998 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
999 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1000 result = XmCreateDialogShell (parent, "dialog", al, ac);
1001 ac = 0;
1002 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1003 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1004 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1005 form = XmCreateForm (result, shell_title, al, ac);
1007 else
1009 ac = 0;
1010 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1011 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1012 form = XmCreateForm (parent, shell_title, al, ac);
1013 result = form;
1016 n_children = left_buttons + right_buttons + 1;
1017 ac = 0;
1018 XtSetArg(al[ac], XmNpacking, n_children == 3?
1019 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1020 XtSetArg(al[ac], XmNorientation, n_children == 3?
1021 XmVERTICAL: XmHORIZONTAL); ac++;
1022 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1023 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1024 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1025 XtSetArg(al[ac], XmNspacing, 13); ac++;
1026 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1027 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1028 XtSetArg(al[ac], XmNisAligned, True); ac++;
1029 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1030 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1031 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1032 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1033 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1034 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1035 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1036 row = XmCreateRowColumn (form, "row", al, ac);
1038 n_children = 0;
1039 for (i = 0; i < left_buttons; i++)
1041 char button_name [16];
1042 sprintf (button_name, "button%d", i + 1);
1043 ac = 0;
1044 if (i == 0)
1046 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1047 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1049 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1050 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1051 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1053 if (i == 0)
1055 button = children [n_children];
1056 ac = 0;
1057 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1058 XtSetValues (row, al, ac);
1061 n_children++;
1064 /* invisible separator button */
1065 ac = 0;
1066 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1067 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1068 n_children++;
1070 for (i = 0; i < right_buttons; i++)
1072 char button_name [16];
1073 sprintf (button_name, "button%d", left_buttons + i + 1);
1074 ac = 0;
1075 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1076 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1077 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1078 if (! button) button = children [n_children];
1079 n_children++;
1082 XtManageChildren (children, n_children);
1084 ac = 0;
1085 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1086 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1087 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1088 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1089 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1090 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1091 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1092 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1093 separator = XmCreateSeparator (form, "", al, ac);
1095 ac = 0;
1096 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1097 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1098 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1099 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1100 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1101 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1102 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1103 icon = XmCreateLabel (form, icon_name, al, ac);
1105 ac = 0;
1106 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1107 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1108 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1109 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1110 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1111 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1112 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1113 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1114 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1115 icon_separator = XmCreateLabel (form, "", al, ac);
1117 if (text_input_slot)
1119 ac = 0;
1120 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1121 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1122 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1123 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1124 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1125 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1126 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1127 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1128 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1129 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1130 value = XmCreateTextField (form, "value", al, ac);
1132 else if (radio_box)
1134 Widget radio_butt;
1135 ac = 0;
1136 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1137 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1138 XtSetArg(al[ac], XmNspacing, 13); ac++;
1139 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1140 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1141 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1142 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1143 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1144 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1145 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1146 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1147 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1148 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1149 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1150 ac = 0;
1151 i = 0;
1152 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1153 children [i++] = radio_butt;
1154 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1155 children [i++] = radio_butt;
1156 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1157 children [i++] = radio_butt;
1158 XtManageChildren (children, i);
1160 else if (list)
1162 ac = 0;
1163 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1164 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1165 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1166 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1167 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1168 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1169 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1170 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1171 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1172 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1173 value = XmCreateScrolledList (form, "list", al, ac);
1175 /* this is the easiest way I found to have the dble click in the
1176 list activate the default button */
1177 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1180 ac = 0;
1181 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1182 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1183 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1184 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1185 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1186 XtSetArg(al[ac], XmNbottomWidget,
1187 text_input_slot || radio_box || list ? value : separator); ac++;
1188 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1189 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1190 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1191 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1192 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1193 message = XmCreateLabel (form, "message", al, ac);
1195 if (list)
1196 XtManageChild (value);
1198 i = 0;
1199 children [i] = row; i++;
1200 children [i] = separator; i++;
1201 if (text_input_slot || radio_box)
1203 children [i] = value; i++;
1205 children [i] = message; i++;
1206 children [i] = icon; i++;
1207 children [i] = icon_separator; i++;
1208 XtManageChildren (children, i);
1210 if (text_input_slot || list)
1212 XtInstallAccelerators (value, button);
1213 XtSetKeyboardFocus (result, value);
1215 else
1217 XtInstallAccelerators (form, button);
1218 XtSetKeyboardFocus (result, button);
1221 return result;
1224 static destroyed_instance*
1225 find_matching_instance (instance)
1226 widget_instance* instance;
1228 destroyed_instance* cur;
1229 destroyed_instance* prev;
1230 char* type = instance->info->type;
1231 char* name = instance->info->name;
1233 for (prev = NULL, cur = all_destroyed_instances;
1234 cur;
1235 prev = cur, cur = cur->next)
1237 if (!strcmp (cur->name, name)
1238 && !strcmp (cur->type, type)
1239 && cur->parent == instance->parent
1240 && cur->pop_up_p == instance->pop_up_p)
1242 if (prev)
1243 prev->next = cur->next;
1244 else
1245 all_destroyed_instances = cur->next;
1246 return cur;
1248 /* do some cleanup */
1249 else if (!cur->widget)
1251 if (prev)
1252 prev->next = cur->next;
1253 else
1254 all_destroyed_instances = cur->next;
1255 free_destroyed_instance (cur);
1256 cur = prev ? prev : all_destroyed_instances;
1259 return NULL;
1262 static void
1263 mark_dead_instance_destroyed (widget, closure, call_data)
1264 Widget widget;
1265 XtPointer closure;
1266 XtPointer call_data;
1268 destroyed_instance* instance = (destroyed_instance*)closure;
1269 instance->widget = NULL;
1272 static void
1273 recenter_widget (widget)
1274 Widget widget;
1276 Widget parent = XtParent (widget);
1277 Screen* screen = XtScreen (widget);
1278 Dimension screen_width = WidthOfScreen (screen);
1279 Dimension screen_height = HeightOfScreen (screen);
1280 Dimension parent_width = 0;
1281 Dimension parent_height = 0;
1282 Dimension child_width = 0;
1283 Dimension child_height = 0;
1284 Position x;
1285 Position y;
1287 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1288 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1291 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1292 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1294 XtTranslateCoords (parent, x, y, &x, &y);
1296 if (x + child_width > screen_width)
1297 x = screen_width - child_width;
1298 if (x < 0)
1299 x = 0;
1301 if (y + child_height > screen_height)
1302 y = screen_height - child_height;
1303 if (y < 0)
1304 y = 0;
1306 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1309 static Widget
1310 recycle_instance (instance)
1311 destroyed_instance* instance;
1313 Widget widget = instance->widget;
1315 /* widget is NULL if the parent was destroyed. */
1316 if (widget)
1318 Widget focus;
1319 Widget separator;
1321 /* Remove the destroy callback as the instance is not in the list
1322 anymore */
1323 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1324 mark_dead_instance_destroyed,
1325 (XtPointer)instance);
1327 /* Give the focus to the initial item */
1328 focus = XtNameToWidget (widget, "*value");
1329 if (!focus)
1330 focus = XtNameToWidget (widget, "*button1");
1331 if (focus)
1332 XtSetKeyboardFocus (widget, focus);
1334 /* shrink the separator label back to their original size */
1335 separator = XtNameToWidget (widget, "*separator_button");
1336 if (separator)
1337 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1339 /* Center the dialog in its parent */
1340 recenter_widget (widget);
1342 free_destroyed_instance (instance);
1343 return widget;
1346 Widget
1347 xm_create_dialog (instance)
1348 widget_instance* instance;
1350 char* name = instance->info->type;
1351 Widget parent = instance->parent;
1352 Widget widget;
1353 Boolean pop_up_p = instance->pop_up_p;
1354 char* shell_name = 0;
1355 char* icon_name;
1356 Boolean text_input_slot = False;
1357 Boolean radio_box = False;
1358 Boolean list = False;
1359 int total_buttons;
1360 int left_buttons = 0;
1361 int right_buttons = 1;
1362 destroyed_instance* dead_one;
1364 /* try to find a widget to recycle */
1365 dead_one = find_matching_instance (instance);
1366 if (dead_one)
1368 Widget recycled_widget = recycle_instance (dead_one);
1369 if (recycled_widget)
1370 return recycled_widget;
1373 switch (name [0]){
1374 case 'E': case 'e':
1375 icon_name = "dbox-error";
1376 shell_name = "Error";
1377 break;
1379 case 'I': case 'i':
1380 icon_name = "dbox-info";
1381 shell_name = "Information";
1382 break;
1384 case 'L': case 'l':
1385 list = True;
1386 icon_name = "dbox-question";
1387 shell_name = "Prompt";
1388 break;
1390 case 'P': case 'p':
1391 text_input_slot = True;
1392 icon_name = "dbox-question";
1393 shell_name = "Prompt";
1394 break;
1396 case 'Q': case 'q':
1397 icon_name = "dbox-question";
1398 shell_name = "Question";
1399 break;
1402 total_buttons = name [1] - '0';
1404 if (name [3] == 'T' || name [3] == 't')
1406 text_input_slot = False;
1407 radio_box = True;
1409 else if (name [3])
1410 right_buttons = name [4] - '0';
1412 left_buttons = total_buttons - right_buttons;
1414 widget = make_dialog (name, parent, pop_up_p,
1415 shell_name, icon_name, text_input_slot, radio_box,
1416 list, left_buttons, right_buttons);
1418 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1419 (XtPointer) instance);
1420 return widget;
1423 /* Create a menu bar. We turn off the f10 key
1424 because we have not yet managed to make it work right in Motif. */
1426 static Widget
1427 make_menubar (instance)
1428 widget_instance* instance;
1430 Arg al[1];
1431 int ac;
1433 ac = 0;
1434 XtSetArg(al[0], XmNmenuAccelerator, 0);
1435 return XmCreateMenuBar (instance->parent, instance->info->name, al, 1);
1438 static void
1439 remove_grabs (shell, closure, call_data)
1440 Widget shell;
1441 XtPointer closure;
1442 XtPointer call_data;
1444 Widget menu = (Widget) closure;
1445 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1448 static Widget
1449 make_popup_menu (instance)
1450 widget_instance* instance;
1452 Widget parent = instance->parent;
1453 Window parent_window = parent->core.window;
1454 Widget result;
1456 /* sets the parent window to 0 to fool Motif into not generating a grab */
1457 parent->core.window = 0;
1458 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1459 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1460 (XtPointer)result);
1461 parent->core.window = parent_window;
1462 return result;
1465 static Widget
1466 make_main (instance)
1467 widget_instance* instance;
1469 Widget parent = instance->parent;
1470 Widget result;
1471 Arg al[2];
1472 int ac;
1474 ac = 0;
1475 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1476 XtSetArg (al[ac], XmNspacing, 0); ac++;
1477 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1478 return result;
1481 \f/* Table of functions to create widgets */
1483 #ifdef ENERGIZE
1485 /* interface with the XDesigner generated functions */
1486 typedef Widget (*widget_maker) (Widget);
1487 extern Widget create_project_p_sheet (Widget parent);
1488 extern Widget create_debugger_p_sheet (Widget parent);
1489 extern Widget create_breaklist_p_sheet (Widget parent);
1490 extern Widget create_le_browser_p_sheet (Widget parent);
1491 extern Widget create_class_browser_p_sheet (Widget parent);
1492 extern Widget create_call_browser_p_sheet (Widget parent);
1493 extern Widget create_build_dialog (Widget parent);
1494 extern Widget create_editmode_dialog (Widget parent);
1495 extern Widget create_search_dialog (Widget parent);
1496 extern Widget create_project_display_dialog (Widget parent);
1498 static Widget
1499 make_one (widget_instance* instance, widget_maker fn)
1501 Widget result;
1502 Arg al [64];
1503 int ac = 0;
1505 if (instance->pop_up_p)
1507 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1508 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1509 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1510 (XtPointer) instance);
1511 (*fn) (result);
1513 else
1515 result = (*fn) (instance->parent);
1516 XtRealizeWidget (result);
1518 return result;
1521 static Widget
1522 make_project_p_sheet (widget_instance* instance)
1524 return make_one (instance, create_project_p_sheet);
1527 static Widget
1528 make_debugger_p_sheet (widget_instance* instance)
1530 return make_one (instance, create_debugger_p_sheet);
1533 static Widget
1534 make_breaklist_p_sheet (widget_instance* instance)
1536 return make_one (instance, create_breaklist_p_sheet);
1539 static Widget
1540 make_le_browser_p_sheet (widget_instance* instance)
1542 return make_one (instance, create_le_browser_p_sheet);
1545 static Widget
1546 make_class_browser_p_sheet (widget_instance* instance)
1548 return make_one (instance, create_class_browser_p_sheet);
1551 static Widget
1552 make_call_browser_p_sheet (widget_instance* instance)
1554 return make_one (instance, create_call_browser_p_sheet);
1557 static Widget
1558 make_build_dialog (widget_instance* instance)
1560 return make_one (instance, create_build_dialog);
1563 static Widget
1564 make_editmode_dialog (widget_instance* instance)
1566 return make_one (instance, create_editmode_dialog);
1569 static Widget
1570 make_search_dialog (widget_instance* instance)
1572 return make_one (instance, create_search_dialog);
1575 static Widget
1576 make_project_display_dialog (widget_instance* instance)
1578 return make_one (instance, create_project_display_dialog);
1581 #endif /* ENERGIZE */
1583 widget_creation_entry
1584 xm_creation_table [] =
1586 {"menubar", make_menubar},
1587 {"popup", make_popup_menu},
1588 {"main", make_main},
1589 #ifdef ENERGIZE
1590 {"project_p_sheet", make_project_p_sheet},
1591 {"debugger_p_sheet", make_debugger_p_sheet},
1592 {"breaklist_psheet", make_breaklist_p_sheet},
1593 {"leb_psheet", make_le_browser_p_sheet},
1594 {"class_browser_psheet", make_class_browser_p_sheet},
1595 {"ctree_browser_psheet", make_call_browser_p_sheet},
1596 {"build", make_build_dialog},
1597 {"editmode", make_editmode_dialog},
1598 {"search", make_search_dialog},
1599 {"project_display", make_project_display_dialog},
1600 #endif /* ENERGIZE */
1601 {NULL, NULL}
1604 \f/* Destruction of instances */
1605 void
1606 xm_destroy_instance (instance)
1607 widget_instance* instance;
1609 Widget widget = instance->widget;
1610 /* recycle the dialog boxes */
1611 /* Disable the recycling until we can find a way to have the dialog box
1612 get reasonable layout after we modify its contents. */
1613 if (0
1614 && XtClass (widget) == xmDialogShellWidgetClass)
1616 destroyed_instance* dead_instance =
1617 make_destroyed_instance (instance->info->name,
1618 instance->info->type,
1619 instance->widget,
1620 instance->parent,
1621 instance->pop_up_p);
1622 dead_instance->next = all_destroyed_instances;
1623 all_destroyed_instances = dead_instance;
1624 XtUnmanageChild (first_child (instance->widget));
1625 XFlush (XtDisplay (instance->widget));
1626 XtAddCallback (instance->parent, XtNdestroyCallback,
1627 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1629 else
1631 /* This might not be necessary now that the nosel is attached to
1632 popdown instead of destroy, but it can't hurt. */
1633 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1634 xm_nosel_callback, (XtPointer)instance);
1635 XtDestroyWidget (instance->widget);
1639 \f/* popup utility */
1640 void
1641 xm_popup_menu (widget, event)
1642 Widget widget;
1643 XEvent *event;
1645 XButtonPressedEvent dummy;
1647 if (event == 0)
1649 dummy.type = ButtonPress;
1650 dummy.serial = 0;
1651 dummy.send_event = 0;
1652 dummy.display = XtDisplay (widget);
1653 dummy.window = XtWindow (XtParent (widget));
1654 dummy.time = 0;
1655 dummy.button = 0;
1656 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1657 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1658 &dummy.x, &dummy.y, &dummy.state);
1659 event = (XEvent *) &dummy;
1662 if (event->type == ButtonPress || event->type == ButtonRelease)
1664 /* This is so totally ridiculous: there's NO WAY to tell Motif
1665 that *any* button can select a menu item. Only one button
1666 can have that honor.
1668 char *trans = 0;
1669 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1670 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1671 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1672 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1673 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1674 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1675 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1677 XtManageChild (widget);
1680 static void
1681 set_min_dialog_size (w)
1682 Widget w;
1684 short width;
1685 short height;
1686 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1687 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1690 void
1691 xm_pop_instance (instance, up)
1692 widget_instance* instance;
1693 Boolean up;
1695 Widget widget = instance->widget;
1697 if (XtClass (widget) == xmDialogShellWidgetClass)
1699 Widget widget_to_manage = first_child (widget);
1700 if (up)
1702 XtManageChild (widget_to_manage);
1703 set_min_dialog_size (widget);
1704 XtSetKeyboardFocus (instance->parent, widget);
1706 else
1707 XtUnmanageChild (widget_to_manage);
1709 else
1711 if (up)
1712 XtManageChild (widget);
1713 else
1714 XtUnmanageChild (widget);
1719 /* motif callback */
1721 static void
1722 do_call (widget, closure, type)
1723 Widget widget;
1724 XtPointer closure;
1725 enum do_call_type type;
1727 Arg al [256];
1728 int ac;
1729 XtPointer user_data;
1730 widget_instance* instance = (widget_instance*)closure;
1731 Widget instance_widget;
1732 LWLIB_ID id;
1734 if (!instance)
1735 return;
1736 if (widget->core.being_destroyed)
1737 return;
1739 instance_widget = instance->widget;
1740 if (!instance_widget)
1741 return;
1743 id = instance->info->id;
1744 ac = 0;
1745 user_data = NULL;
1746 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1747 XtGetValues (widget, al, ac);
1748 switch (type)
1750 case pre_activate:
1751 if (instance->info->pre_activate_cb)
1752 instance->info->pre_activate_cb (widget, id, user_data);
1753 break;
1754 case selection:
1755 if (instance->info->selection_cb)
1756 instance->info->selection_cb (widget, id, user_data);
1757 break;
1758 case no_selection:
1759 if (instance->info->selection_cb)
1760 instance->info->selection_cb (widget, id, (XtPointer) -1);
1761 break;
1762 case post_activate:
1763 if (instance->info->post_activate_cb)
1764 instance->info->post_activate_cb (widget, id, user_data);
1765 break;
1766 default:
1767 abort ();
1771 /* Like lw_internal_update_other_instances except that it does not do
1772 anything if its shell parent is not managed. This is to protect
1773 lw_internal_update_other_instances to dereference freed memory
1774 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1775 list */
1776 static void
1777 xm_internal_update_other_instances (widget, closure, call_data)
1778 Widget widget;
1779 XtPointer closure;
1780 XtPointer call_data;
1782 Widget parent;
1783 for (parent = widget; parent; parent = XtParent (parent))
1784 if (XtIsShell (parent))
1785 break;
1786 else if (!XtIsManaged (parent))
1787 return;
1788 lw_internal_update_other_instances (widget, closure, call_data);
1791 static void
1792 xm_generic_callback (widget, closure, call_data)
1793 Widget widget;
1794 XtPointer closure;
1795 XtPointer call_data;
1797 lw_internal_update_other_instances (widget, closure, call_data);
1798 do_call (widget, closure, selection);
1801 static void
1802 xm_nosel_callback (widget, closure, call_data)
1803 Widget widget;
1804 XtPointer closure;
1805 XtPointer call_data;
1807 /* This callback is only called when a dialog box is dismissed with the wm's
1808 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1809 in that case, not just unmapped, so that it releases its keyboard grabs.
1810 But there are problems with running our callbacks while the widget is in
1811 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1812 instead of XmDESTROY and then destroy it ourself after having run the
1813 callback.
1815 do_call (widget, closure, no_selection);
1816 XtDestroyWidget (widget);
1819 static void
1820 xm_pull_down_callback (widget, closure, call_data)
1821 Widget widget;
1822 XtPointer closure;
1823 XtPointer call_data;
1825 do_call (widget, closure, pre_activate);
1828 static void
1829 xm_pop_down_callback (widget, closure, call_data)
1830 Widget widget;
1831 XtPointer closure;
1832 XtPointer call_data;
1834 widget_instance *instance = (widget_instance *) closure;
1836 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1837 || (XtParent (widget) == instance->parent))
1838 do_call (widget, closure, post_activate);
1842 /* set the keyboard focus */
1843 void
1844 xm_set_keyboard_focus (parent, w)
1845 Widget parent;
1846 Widget w;
1848 XmProcessTraversal (w, 0);
1849 XtSetKeyboardFocus (parent, w);
1852 /* Motif hack to set the main window areas. */
1853 void
1854 xm_set_main_areas (parent, menubar, work_area)
1855 Widget parent;
1856 Widget menubar;
1857 Widget work_area;
1859 XmMainWindowSetAreas (parent,
1860 menubar, /* menubar (maybe 0) */
1861 0, /* command area (psheets) */
1862 0, /* horizontal scroll */
1863 0, /* vertical scroll */
1864 work_area); /* work area */
1867 /* Motif hack to control resizing on the menubar. */
1868 void
1869 xm_manage_resizing (w, flag)
1870 Widget w;
1871 Boolean flag;
1873 if (flag)
1875 /* Enable the edit widget for resizing. */
1876 Arg al[1];
1878 XtSetArg (al[0], XtNallowShellResize, 0);
1879 XtSetValues (w, al, 1);
1881 else
1883 /* Disable the edit widget from resizing. */
1884 Arg al[1];
1886 XtSetArg (al[0], XtNallowShellResize, 0);
1887 XtSetValues (w, al, 1);