Minor fixes in window resizing routines and documentation update.
[emacs.git] / lwlib / lwlib-Xm.c
blob2b7677a02f5d92c47ba8e0eb81a3cb09f8c55319
1 /* The lwlib interface to Motif widgets.
3 Copyright (C) 1994-1997, 1999-2011 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
11 any later version.
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <setjmp.h>
31 #include <X11/StringDefs.h>
32 #include <X11/IntrinsicP.h>
33 #include <X11/ObjectP.h>
34 #include <X11/CoreP.h>
35 #include <X11/CompositeP.h>
37 #include <lisp.h>
39 #include "lwlib-Xm.h"
40 #include "lwlib-utils.h"
42 #include <Xm/BulletinB.h>
43 #include <Xm/CascadeB.h>
44 #include <Xm/CascadeBG.h>
45 #include <Xm/DrawingA.h>
46 #include <Xm/FileSB.h>
47 #include <Xm/Label.h>
48 #include <Xm/List.h>
49 #include <Xm/MainW.h>
50 #include <Xm/MenuShell.h>
51 #include <Xm/MessageB.h>
52 #include <Xm/PanedW.h>
53 #include <Xm/PushB.h>
54 #include <Xm/PushBG.h>
55 #include <Xm/ArrowB.h>
56 #include <Xm/SelectioB.h>
57 #include <Xm/Text.h>
58 #include <Xm/TextF.h>
59 #include <Xm/ToggleB.h>
60 #include <Xm/ToggleBG.h>
61 #include <Xm/RowColumn.h>
62 #include <Xm/ScrolledW.h>
63 #include <Xm/Separator.h>
64 #include <Xm/DialogS.h>
65 #include <Xm/Form.h>
67 enum do_call_type { pre_activate, selection, no_selection, post_activate };
70 \f/* Structures to keep destroyed instances */
71 typedef struct _destroyed_instance
73 char* name;
74 char* type;
75 Widget widget;
76 Widget parent;
77 Boolean pop_up_p;
78 struct _destroyed_instance* next;
79 } destroyed_instance;
81 static destroyed_instance *make_destroyed_instance (char *, char *,
82 Widget, Widget,
83 Boolean);
84 static void free_destroyed_instance (destroyed_instance*);
85 Widget first_child (Widget);
86 Boolean lw_motif_widget_p (Widget);
87 static XmString resource_motif_string (Widget, char *);
88 static void destroy_all_children (Widget, int);
89 static void xm_update_label (widget_instance *, Widget, widget_value *);
90 static void xm_update_list (widget_instance *, Widget, widget_value *);
91 static void xm_update_pushbutton (widget_instance *, Widget,
92 widget_value *);
93 static void xm_update_cascadebutton (widget_instance *, Widget,
94 widget_value *);
95 static void xm_update_toggle (widget_instance *, Widget, widget_value *);
96 static void xm_update_radiobox (widget_instance *, Widget, widget_value *);
97 static void make_menu_in_widget (widget_instance *, Widget,
98 widget_value *, int);
99 static void update_one_menu_entry (widget_instance *, Widget,
100 widget_value *, Boolean);
101 static void xm_update_menu (widget_instance *, Widget, widget_value *,
102 Boolean);
103 static void xm_update_text (widget_instance *, Widget, widget_value *);
104 static void xm_update_text_field (widget_instance *, Widget,
105 widget_value *);
106 void xm_update_one_value (widget_instance *, Widget, widget_value *);
107 static void activate_button (Widget, XtPointer, XtPointer);
108 static Widget make_dialog (char *, Widget, Boolean, char *, char *,
109 Boolean, Boolean, Boolean, int, int);
110 static destroyed_instance* find_matching_instance (widget_instance*);
111 static void mark_dead_instance_destroyed (Widget, XtPointer, XtPointer);
112 static void recenter_widget (Widget);
113 static Widget recycle_instance (destroyed_instance*);
114 Widget xm_create_dialog (widget_instance*);
115 static Widget make_menubar (widget_instance*);
116 static void remove_grabs (Widget, XtPointer, XtPointer);
117 static Widget make_popup_menu (widget_instance*);
118 static Widget make_main (widget_instance*);
119 void xm_destroy_instance (widget_instance*);
120 void xm_popup_menu (Widget, XEvent *);
121 static void set_min_dialog_size (Widget);
122 static void do_call (Widget, XtPointer, enum do_call_type);
123 static void xm_generic_callback (Widget, XtPointer, XtPointer);
124 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
125 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
126 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
127 void xm_set_keyboard_focus (Widget, Widget);
128 void xm_set_main_areas (Widget, Widget, Widget);
129 static void xm_internal_update_other_instances (Widget, XtPointer,
130 XtPointer);
131 static void xm_arm_callback (Widget, XtPointer, XtPointer);
133 #if 0
134 void xm_update_one_widget (widget_instance *, Widget, widget_value *,
135 Boolean);
136 void xm_pop_instance (widget_instance*, Boolean);
137 void xm_manage_resizing (Widget, Boolean);
138 #endif
141 #if 0
143 /* Print the complete X resource name of widget WIDGET to stderr.
144 This is sometimes handy to have available. */
146 void
147 x_print_complete_resource_name (Widget widget)
149 int i;
150 String names[100];
152 for (i = 0; i < 100 && widget != NULL; ++i)
154 names[i] = XtName (widget);
155 widget = XtParent (widget);
158 for (--i; i >= 1; --i)
159 fprintf (stderr, "%s.", names[i]);
160 fprintf (stderr, "%s\n", names[0]);
163 #endif /* 0 */
166 static destroyed_instance *all_destroyed_instances = NULL;
168 static destroyed_instance*
169 make_destroyed_instance (char* name,
170 char* type,
171 Widget widget,
172 Widget parent,
173 Boolean pop_up_p)
175 destroyed_instance* instance =
176 (destroyed_instance*) xmalloc (sizeof (destroyed_instance));
177 instance->name = safe_strdup (name);
178 instance->type = safe_strdup (type);
179 instance->widget = widget;
180 instance->parent = parent;
181 instance->pop_up_p = pop_up_p;
182 instance->next = NULL;
183 return instance;
186 static void
187 free_destroyed_instance (destroyed_instance* instance)
189 free (instance->name);
190 free (instance->type);
191 free (instance);
194 \f/* motif utility functions */
195 Widget
196 first_child (Widget widget)
198 return ((CompositeWidget)widget)->composite.children [0];
201 Boolean
202 lw_motif_widget_p (Widget widget)
204 return
205 XtClass (widget) == xmDialogShellWidgetClass
206 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
209 static XmString
210 resource_motif_string (Widget widget,
211 char* name)
213 XtResource resource;
214 XmString result = 0;
216 resource.resource_name = name;
217 resource.resource_class = XmCXmString;
218 resource.resource_type = XmRXmString;
219 resource.resource_size = sizeof (XmString);
220 resource.resource_offset = 0;
221 resource.default_type = XtRImmediate;
222 resource.default_addr = 0;
224 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
225 "DialogString", &resource, 1, NULL, 0);
226 return result;
229 /* Destroy all of the children of WIDGET
230 starting with number FIRST_CHILD_TO_DESTROY. */
232 static void
233 destroy_all_children (Widget widget,
234 int first_child_to_destroy)
236 Widget* children;
237 unsigned int number;
238 int i;
240 children = XtCompositeChildren (widget, &number);
241 if (children)
243 XtUnmanageChildren (children + first_child_to_destroy,
244 number - first_child_to_destroy);
246 /* Unmanage all children and destroy them. They will only be
247 really destroyed when we get out of DispatchEvent. */
248 for (i = first_child_to_destroy; i < number; i++)
250 Arg al[2];
251 Widget submenu = 0;
252 /* Cascade buttons have submenus,and these submenus
253 need to be freed. But they are not included in
254 XtCompositeChildren. So get it out of the cascade button
255 and free it. If this child is not a cascade button,
256 then submenu should remain unchanged. */
257 XtSetArg (al[0], XmNsubMenuId, &submenu);
258 XtGetValues (children[i], al, 1);
259 if (submenu)
261 destroy_all_children (submenu, 0);
262 XtDestroyWidget (submenu);
264 XtDestroyWidget (children[i]);
267 XtFree ((char *) children);
273 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
274 menu. CLIENT_DATA contains a pointer to the widget_value
275 corresponding to widget W. CALL_DATA contains a
276 XmPushButtonCallbackStruct containing the reason why the callback
277 is called. */
279 static void
280 xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
282 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
283 widget_value *wv = (widget_value *) client_data;
284 widget_instance *instance;
286 /* Get the id of the menu bar or popup menu this widget is in. */
287 while (w != NULL)
289 if (XmIsRowColumn (w))
291 unsigned char type = 0xff;
293 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
294 if (type == XmMENU_BAR || type == XmMENU_POPUP)
295 break;
298 w = XtParent (w);
301 if (w != NULL)
303 instance = lw_get_widget_instance (w);
304 if (instance && instance->info->highlight_cb)
306 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
307 instance->info->highlight_cb (w, instance->info->id, call_data);
314 /* Update the label of widget WIDGET. WIDGET must be a Label widget
315 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
316 the value to update.
318 Menus:
320 Emacs fills VAL->name with the text to display in the menu, and
321 sets VAL->value to null. Function make_menu_in_widget creates
322 widgets with VAL->name as resource name. This works because the
323 Label widget uses its resource name for display if no
324 XmNlabelString is set.
326 Dialogs:
328 VAL->name is again set to the resource name, but VAL->value is
329 not null, and contains the label string to display. */
331 static void
332 xm_update_label (widget_instance* instance,
333 Widget widget,
334 widget_value* val)
336 XmString res_string = 0;
337 XmString built_string = 0;
338 XmString key_string = 0;
339 Arg al [256];
340 int ac;
342 ac = 0;
344 if (val->value)
346 /* A label string is specified, i.e. we are in a dialog. First
347 see if it is overridden by something from the resource file. */
348 res_string = resource_motif_string (widget, val->value);
350 if (res_string)
352 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
354 else
356 built_string =
357 XmStringCreateLocalized (val->value);
358 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
361 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
364 if (val->key)
366 key_string = XmStringCreateLocalized (val->key);
367 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
370 if (ac)
371 XtSetValues (widget, al, ac);
373 if (built_string)
374 XmStringFree (built_string);
376 if (key_string)
377 XmStringFree (key_string);
380 \f/* update of list */
381 static void
382 xm_update_list (widget_instance* instance,
383 Widget widget,
384 widget_value* val)
386 widget_value* cur;
387 int i;
388 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
389 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
390 instance);
391 for (cur = val->contents, i = 0; cur; cur = cur->next)
392 if (cur->value)
394 XmString xmstr = XmStringCreateLocalized (cur->value);
395 i += 1;
396 XmListAddItem (widget, xmstr, 0);
397 if (cur->selected)
398 XmListSelectPos (widget, i, False);
399 XmStringFree (xmstr);
403 \f/* update of buttons */
404 static void
405 xm_update_pushbutton (widget_instance* instance,
406 Widget widget,
407 widget_value* val)
409 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
410 XtRemoveAllCallbacks (widget, XmNactivateCallback);
411 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
414 static void
415 xm_update_cascadebutton (widget_instance* instance,
416 Widget widget,
417 widget_value* val)
419 /* Should also rebuild the menu by calling ...update_menu... */
420 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
421 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
422 instance);
425 \f/* update toggle and radiobox */
426 static void
427 xm_update_toggle (widget_instance* instance,
428 Widget widget,
429 widget_value* val)
431 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
432 XtAddCallback (widget, XmNvalueChangedCallback,
433 xm_generic_callback, instance);
434 XtVaSetValues (widget, XmNset, val->selected,
435 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
438 static void
439 xm_update_radiobox (widget_instance* instance,
440 Widget widget,
441 widget_value* val)
444 Widget toggle;
445 widget_value* cur;
447 /* update the callback */
448 XtRemoveAllCallbacks (widget, XmNentryCallback);
449 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
451 /* first update all the toggles */
452 /* Energize kernel interface is currently bad. It sets the selected widget
453 with the selected flag but returns it by its name. So we currently
454 have to support both setting the selection with the selected slot
455 of val contents and setting it with the "value" slot of val. The latter
456 has a higher priority. This to be removed when the kernel is fixed. */
457 for (cur = val->contents; cur; cur = cur->next)
459 toggle = XtNameToWidget (widget, cur->value);
460 if (toggle)
462 XtSetSensitive (toggle, cur->enabled);
463 if (!val->value && cur->selected)
464 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
465 if (val->value && strcmp (val->value, cur->value))
466 XtVaSetValues (toggle, XmNset, False, NULL);
470 /* The selected was specified by the value slot */
471 if (val->value)
473 toggle = XtNameToWidget (widget, val->value);
474 if (toggle)
475 XtVaSetValues (toggle, XmNset, True, NULL);
480 /* update a popup menu, pulldown menu or a menubar */
482 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
484 static void
485 make_menu_in_widget (widget_instance* instance,
486 Widget widget,
487 widget_value* val,
488 int keep_first_children)
490 Widget* children = 0;
491 int num_children;
492 int child_index;
493 widget_value* cur;
494 Widget button = 0;
495 Widget title = 0;
496 Widget menu;
497 Arg al [256];
498 int ac;
499 Boolean menubar_p;
500 unsigned char type;
502 Widget* old_children;
503 unsigned int old_num_children;
505 /* Disable drag and drop for labels in menu bar. */
506 static char overrideTrans[] = "<Btn2Down>: Noop()";
507 XtTranslations override = XtParseTranslationTable (overrideTrans);
509 old_children = XtCompositeChildren (widget, &old_num_children);
511 /* Allocate the children array */
512 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
514 children = (Widget*)(void*)XtMalloc (num_children * sizeof (Widget));
516 /* WIDGET should be a RowColumn. */
517 if (!XmIsRowColumn (widget))
518 abort ();
520 /* Determine whether WIDGET is a menu bar. */
521 type = -1;
522 XtSetArg (al[0], XmNrowColumnType, &type);
523 XtGetValues (widget, al, 1);
524 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
525 abort ();
526 menubar_p = type == XmMENU_BAR;
528 /* Add a callback to popups and pulldowns that is called when
529 it is made invisible again. */
530 if (!menubar_p)
531 XtAddCallback (XtParent (widget), XmNpopdownCallback,
532 xm_pop_down_callback, (XtPointer)instance);
534 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
535 for (child_index = 0, cur = val; child_index < keep_first_children;
536 child_index++, cur = cur->next)
537 children[child_index] = old_children[child_index];
539 /* Check that those are all we have
540 (the caller should have deleted the rest). */
541 if (old_num_children != keep_first_children)
542 abort ();
544 /* Create the rest. */
545 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
547 enum menu_separator separator;
549 ac = 0;
550 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
551 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
552 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
554 if (instance->pop_up_p && !cur->contents && !cur->call_data
555 && !lw_separator_p (cur->name, &separator, 1))
557 ac = 0;
558 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
559 title = button = XmCreateLabel (widget, cur->name, al, ac);
561 else if (lw_separator_p (cur->name, &separator, 1))
563 ac = 0;
564 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
565 button = XmCreateSeparator (widget, cur->name, al, ac);
567 else if (!cur->contents)
569 if (menubar_p)
570 button = XmCreateCascadeButton (widget, cur->name, al, ac);
571 else if (!cur->call_data)
572 button = XmCreateLabel (widget, cur->name, al, ac);
573 else if (cur->button_type == BUTTON_TYPE_TOGGLE
574 || cur->button_type == BUTTON_TYPE_RADIO)
576 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
577 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
578 XtSetArg (al[ac], XmNindicatorType,
579 (cur->button_type == BUTTON_TYPE_TOGGLE
580 ? XmN_OF_MANY : XmONE_OF_MANY));
581 ++ac;
582 button = XmCreateToggleButton (widget, cur->name, al, ac);
583 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
584 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
586 else
588 button = XmCreatePushButton (widget, cur->name, al, ac);
589 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
590 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
593 xm_update_label (instance, button, cur);
595 /* Add a callback that is called when the button is
596 selected. Toggle buttons don't support
597 XmNactivateCallback, we use XmNvalueChangedCallback in
598 that case. Don't add a callback to a simple label. */
599 if (cur->button_type)
600 xm_update_toggle (instance, button, cur);
601 else if (cur->call_data)
602 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
603 (XtPointer)instance);
605 else
607 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
609 make_menu_in_widget (instance, menu, cur->contents, 0);
610 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
611 button = XmCreateCascadeButton (widget, cur->name, al, ac);
613 xm_update_label (instance, button, cur);
615 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
616 (XtPointer)instance);
617 XtOverrideTranslations (button, override);
621 children[child_index] = button;
624 /* Last entry is the help button. The original comment read "Has to
625 be done after managing the buttons otherwise the menubar is only
626 4 pixels high." This is no longer true, and to make
627 XmNmenuHelpWidget work, we need to set it before managing the
628 children.. --gerd. */
629 if (button)
630 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
632 if (num_children)
633 XtManageChildren (children, num_children);
635 XtFree ((char *) children);
636 if (old_children)
637 XtFree ((char *) old_children);
640 static void
641 update_one_menu_entry (widget_instance* instance,
642 Widget widget,
643 widget_value* val,
644 Boolean deep_p)
646 Arg al [256];
647 int ac;
648 Widget menu;
649 widget_value* contents;
651 if (val->this_one_change == NO_CHANGE)
652 return;
654 /* update the sensitivity and userdata */
655 /* Common to all widget types */
656 XtSetSensitive (widget, val->enabled);
657 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
659 /* update the menu button as a label. */
660 if (val->this_one_change >= VISIBLE_CHANGE)
662 xm_update_label (instance, widget, val);
663 if (val->button_type)
664 xm_update_toggle (instance, widget, val);
667 /* update the pulldown/pullaside as needed */
668 ac = 0;
669 menu = NULL;
670 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
671 XtGetValues (widget, al, ac);
673 contents = val->contents;
675 if (!menu)
677 if (contents)
679 unsigned int old_num_children, i;
680 Widget parent;
681 Widget *widget_list;
683 parent = XtParent (widget);
684 widget_list = XtCompositeChildren (parent, &old_num_children);
686 /* Find the widget position within the parent's widget list. */
687 for (i = 0; i < old_num_children; i++)
688 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
689 break;
690 if (i == old_num_children)
691 abort ();
692 if (XmIsCascadeButton (widget_list[i]))
694 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
695 make_menu_in_widget (instance, menu, contents, 0);
696 ac = 0;
697 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
698 XtSetValues (widget, al, ac);
700 else
702 Widget button;
704 /* The current menuitem is a XmPushButtonGadget, it
705 needs to be replaced by a CascadeButtonGadget */
706 XtDestroyWidget (widget_list[i]);
707 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
708 make_menu_in_widget (instance, menu, contents, 0);
709 ac = 0;
710 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
711 /* Non-zero values don't work reliably in
712 conjunction with Emacs' event loop */
713 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
714 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
715 /* Tell Motif to put it in the right place */
716 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
717 #endif
718 button = XmCreateCascadeButton (parent, val->name, al, ac);
719 xm_update_label (instance, button, val);
721 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
722 (XtPointer)instance);
723 XtManageChild (button);
726 if (widget_list)
727 XtFree ((char*) widget_list);
730 else if (!contents)
732 ac = 0;
733 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
734 XtSetValues (widget, al, ac);
735 XtDestroyWidget (menu);
737 else if (deep_p && contents->change != NO_CHANGE)
738 xm_update_menu (instance, menu, val, 1);
741 static void
742 xm_update_menu (widget_instance* instance,
743 Widget widget,
744 widget_value* val,
745 Boolean deep_p)
747 Widget* children;
748 unsigned int num_children;
749 int num_children_to_keep = 0;
750 int i;
751 widget_value* cur;
753 children = XtCompositeChildren (widget, &num_children);
755 /* Widget is a RowColumn widget whose contents have to be updated
756 * to reflect the list of items in val->contents */
758 /* See how many buttons we can keep, and how many we
759 must completely replace. */
760 if (val->contents == 0)
761 num_children_to_keep = 0;
762 else if (val->contents->change == STRUCTURAL_CHANGE)
764 if (children)
766 for (i = 0, cur = val->contents;
767 (i < num_children
768 && cur); /* how else to ditch unwanted children ?? - mgd */
769 i++, cur = cur->next)
771 if (cur->this_one_change == STRUCTURAL_CHANGE)
772 break;
775 num_children_to_keep = i;
778 else
779 num_children_to_keep = num_children;
781 /* Update all the buttons of the RowColumn, in order,
782 except for those we are going to replace entirely. */
783 if (children)
785 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
787 if (!cur)
789 num_children_to_keep = i;
790 break;
792 if (children [i]->core.being_destroyed
793 || strcmp (XtName (children [i]), cur->name))
794 continue;
795 update_one_menu_entry (instance, children [i], cur, deep_p);
796 cur = cur->next;
800 /* Now replace from scratch all the buttons after the last
801 place that the top-level structure changed. */
802 if (val->contents && val->contents->change == STRUCTURAL_CHANGE)
804 destroy_all_children (widget, num_children_to_keep);
805 make_menu_in_widget (instance, widget, val->contents,
806 num_children_to_keep);
809 XtFree ((char *) children);
813 /* update text widgets */
815 static void
816 xm_update_text (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 (widget_instance* instance,
830 Widget widget,
831 widget_value* val)
833 XmTextFieldSetString (widget, val->value ? val->value : "");
834 XtRemoveAllCallbacks (widget, XmNactivateCallback);
835 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
836 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
837 XtAddCallback (widget, XmNvalueChangedCallback,
838 xm_internal_update_other_instances, instance);
842 /* update a motif widget */
844 void
845 xm_update_one_widget (widget_instance* instance,
846 Widget widget,
847 widget_value* val,
848 Boolean deep_p)
850 WidgetClass class;
852 /* Mark as not edited */
853 val->edited = False;
855 /* Common to all widget types */
856 XtSetSensitive (widget, val->enabled);
857 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
859 /* Common to all label like widgets */
860 if (XtIsSubclass (widget, xmLabelWidgetClass))
861 xm_update_label (instance, widget, val);
863 class = XtClass (widget);
864 /* Class specific things */
865 if (class == xmPushButtonWidgetClass ||
866 class == xmArrowButtonWidgetClass)
868 xm_update_pushbutton (instance, widget, val);
870 else if (class == xmCascadeButtonWidgetClass)
872 xm_update_cascadebutton (instance, widget, val);
874 else if (class == xmToggleButtonWidgetClass
875 || class == xmToggleButtonGadgetClass)
877 xm_update_toggle (instance, widget, val);
879 else if (class == xmRowColumnWidgetClass)
881 Boolean radiobox = 0;
882 int ac = 0;
883 Arg al [1];
885 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
886 XtGetValues (widget, al, ac);
888 if (radiobox)
889 xm_update_radiobox (instance, widget, val);
890 else
891 xm_update_menu (instance, widget, val, deep_p);
893 else if (class == xmTextWidgetClass)
895 xm_update_text (instance, widget, val);
897 else if (class == xmTextFieldWidgetClass)
899 xm_update_text_field (instance, widget, val);
901 else if (class == xmListWidgetClass)
903 xm_update_list (instance, widget, val);
907 \f/* getting the value back */
908 void
909 xm_update_one_value (widget_instance* instance,
910 Widget widget,
911 widget_value* val)
913 WidgetClass class = XtClass (widget);
914 widget_value *old_wv;
916 /* copy the call_data slot into the "return" widget_value */
917 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
918 if (!strcmp (val->name, old_wv->name))
920 val->call_data = old_wv->call_data;
921 break;
924 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
926 XtVaGetValues (widget, XmNset, &val->selected, NULL);
927 val->edited = True;
929 else if (class == xmTextWidgetClass)
931 free (val->value);
932 val->value = XmTextGetString (widget);
933 val->edited = True;
935 else if (class == xmTextFieldWidgetClass)
937 free (val->value);
938 val->value = XmTextFieldGetString (widget);
939 val->edited = True;
941 else if (class == xmRowColumnWidgetClass)
943 Boolean radiobox = 0;
944 int ac = 0;
945 Arg al [1];
947 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
948 XtGetValues (widget, al, ac);
950 if (radiobox)
952 CompositeWidget radio = (CompositeWidget)widget;
953 int i;
954 for (i = 0; i < radio->composite.num_children; i++)
956 int set = False;
957 Widget toggle = radio->composite.children [i];
959 XtVaGetValues (toggle, XmNset, &set, NULL);
960 if (set)
962 free (val->value);
963 val->value = safe_strdup (XtName (toggle));
966 val->edited = True;
969 else if (class == xmListWidgetClass)
971 int pos_cnt;
972 int* pos_list;
973 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
975 int i;
976 widget_value* cur;
977 for (cur = val->contents, i = 0; cur; cur = cur->next)
978 if (cur->value)
980 int j;
981 cur->selected = False;
982 i += 1;
983 for (j = 0; j < pos_cnt; j++)
984 if (pos_list [j] == i)
986 cur->selected = True;
987 val->value = safe_strdup (cur->name);
990 val->edited = 1;
991 XtFree ((char *) pos_list);
997 /* This function is for activating a button from a program. It's wrong because
998 we pass a NULL argument in the call_data which is not Motif compatible.
999 This is used from the XmNdefaultAction callback of the List widgets to
1000 have a double-click put down a dialog box like the button would do.
1001 I could not find a way to do that with accelerators.
1003 static void
1004 activate_button (Widget widget,
1005 XtPointer closure,
1006 XtPointer call_data)
1008 Widget button = (Widget)closure;
1009 XtCallCallbacks (button, XmNactivateCallback, NULL);
1012 /* creation functions */
1014 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1015 static void
1016 dialog_key_cb (Widget widget,
1017 XtPointer closure,
1018 XEvent *event,
1019 Boolean *continue_to_dispatch)
1021 KeySym sym = 0;
1022 Modifiers modif_ret;
1024 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1025 &modif_ret, &sym);
1027 if (sym == osfXK_Cancel)
1029 Widget w = *((Widget *) closure);
1031 while (w && ! XtIsShell (w))
1032 w = XtParent (w);
1034 if (XtIsShell (w)) XtPopdown (w);
1037 *continue_to_dispatch = TRUE;
1040 /* dialogs */
1041 static Widget
1042 make_dialog (char* name,
1043 Widget parent,
1044 Boolean pop_up_p,
1045 char* shell_title,
1046 char* icon_name,
1047 Boolean text_input_slot,
1048 Boolean radio_box,
1049 Boolean list,
1050 int left_buttons,
1051 int right_buttons)
1053 Widget result;
1054 Widget form;
1055 Widget row;
1056 Widget icon;
1057 Widget icon_separator;
1058 Widget message_label;
1059 Widget value = 0;
1060 Widget separator;
1061 Widget button = 0;
1062 Widget children [16]; /* for the final XtManageChildren */
1063 int n_children;
1064 Arg al[64]; /* Arg List */
1065 int ac; /* Arg Count */
1066 int i;
1068 if (pop_up_p)
1070 ac = 0;
1071 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1072 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1073 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1074 result = XmCreateDialogShell (parent, "dialog", al, ac);
1075 ac = 0;
1076 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1077 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1078 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1079 form = XmCreateForm (result, shell_title, al, ac);
1081 else
1083 ac = 0;
1084 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1085 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1086 form = XmCreateForm (parent, shell_title, al, ac);
1087 result = form;
1090 n_children = left_buttons + right_buttons + 1;
1091 ac = 0;
1092 XtSetArg(al[ac], XmNpacking, n_children == 3?
1093 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1094 XtSetArg(al[ac], XmNorientation, n_children == 3?
1095 XmVERTICAL: XmHORIZONTAL); ac++;
1096 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1097 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1098 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1099 XtSetArg(al[ac], XmNspacing, 13); ac++;
1100 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1101 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1102 XtSetArg(al[ac], XmNisAligned, True); ac++;
1103 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1104 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1105 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1106 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1107 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1108 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1109 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1110 row = XmCreateRowColumn (form, "row", al, ac);
1112 n_children = 0;
1113 for (i = 0; i < left_buttons; i++)
1115 char button_name [16];
1116 sprintf (button_name, "button%d", i + 1);
1117 ac = 0;
1118 if (i == 0)
1120 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1121 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1123 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1124 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1125 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1126 XtAddEventHandler (children [n_children],
1127 KeyPressMask, False, dialog_key_cb, result);
1129 if (i == 0)
1131 button = children [n_children];
1132 ac = 0;
1133 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1134 XtSetValues (row, al, ac);
1137 n_children++;
1140 /* invisible separator button */
1141 ac = 0;
1142 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1143 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1144 n_children++;
1146 for (i = 0; i < right_buttons; i++)
1148 char button_name [16];
1149 sprintf (button_name, "button%d", left_buttons + i + 1);
1150 ac = 0;
1151 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1152 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1153 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1154 XtAddEventHandler (children [n_children],
1155 KeyPressMask, False, dialog_key_cb, result);
1157 if (! button) button = children [n_children];
1158 n_children++;
1161 XtManageChildren (children, n_children);
1163 ac = 0;
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, row); ac++;
1168 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1169 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1170 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1171 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1172 separator = XmCreateSeparator (form, "", al, ac);
1174 ac = 0;
1175 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1176 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1177 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1178 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1179 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1180 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1181 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1182 icon = XmCreateLabel (form, icon_name, al, ac);
1184 ac = 0;
1185 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1186 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1187 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1188 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1189 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1190 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1191 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1192 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1193 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1194 icon_separator = XmCreateLabel (form, "", al, ac);
1196 if (text_input_slot)
1198 ac = 0;
1199 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1200 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1201 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1202 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1203 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1204 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1205 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1206 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1207 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1208 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1209 value = XmCreateTextField (form, "value", al, ac);
1211 else if (radio_box)
1213 Widget radio_butt;
1214 ac = 0;
1215 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1216 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1217 XtSetArg(al[ac], XmNspacing, 13); ac++;
1218 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1219 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1220 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1221 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1222 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1223 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1224 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1225 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1226 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1227 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1228 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1229 ac = 0;
1230 i = 0;
1231 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1232 children [i++] = radio_butt;
1233 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1234 children [i++] = radio_butt;
1235 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1236 children [i++] = radio_butt;
1237 XtManageChildren (children, i);
1239 else if (list)
1241 ac = 0;
1242 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1243 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1244 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1245 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1246 XtSetArg(al[ac], XmNbottomWidget, 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 value = XmCreateScrolledList (form, "list", al, ac);
1254 /* this is the easiest way I found to have the dble click in the
1255 list activate the default button */
1256 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1259 ac = 0;
1260 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1261 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1262 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1263 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1264 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1265 XtSetArg(al[ac], XmNbottomWidget,
1266 text_input_slot || radio_box || list ? value : separator); ac++;
1267 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1268 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1269 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1270 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1271 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1272 message_label = XmCreateLabel (form, "message", al, ac);
1274 if (list)
1275 XtManageChild (value);
1277 i = 0;
1278 children [i] = row; i++;
1279 children [i] = separator; i++;
1280 if (text_input_slot || radio_box)
1282 children [i] = value; i++;
1284 children [i] = message_label; i++;
1285 children [i] = icon; i++;
1286 children [i] = icon_separator; i++;
1287 XtManageChildren (children, i);
1289 if (text_input_slot || list)
1291 XtInstallAccelerators (value, button);
1292 XtSetKeyboardFocus (result, value);
1294 else
1296 XtInstallAccelerators (form, button);
1297 XtSetKeyboardFocus (result, button);
1300 return result;
1303 static destroyed_instance*
1304 find_matching_instance (widget_instance* instance)
1306 destroyed_instance* cur;
1307 destroyed_instance* prev;
1308 char* type = instance->info->type;
1309 char* name = instance->info->name;
1311 for (prev = NULL, cur = all_destroyed_instances;
1312 cur;
1313 prev = cur, cur = cur->next)
1315 if (!strcmp (cur->name, name)
1316 && !strcmp (cur->type, type)
1317 && cur->parent == instance->parent
1318 && cur->pop_up_p == instance->pop_up_p)
1320 if (prev)
1321 prev->next = cur->next;
1322 else
1323 all_destroyed_instances = cur->next;
1324 return cur;
1326 /* do some cleanup */
1327 else if (!cur->widget)
1329 if (prev)
1330 prev->next = cur->next;
1331 else
1332 all_destroyed_instances = cur->next;
1333 free_destroyed_instance (cur);
1334 cur = prev ? prev : all_destroyed_instances;
1337 return NULL;
1340 static void
1341 mark_dead_instance_destroyed (Widget widget,
1342 XtPointer closure,
1343 XtPointer call_data)
1345 destroyed_instance* instance = (destroyed_instance*)closure;
1346 instance->widget = NULL;
1349 static void
1350 recenter_widget (Widget widget)
1352 Widget parent = XtParent (widget);
1353 Screen* screen = XtScreen (widget);
1354 Dimension screen_width = WidthOfScreen (screen);
1355 Dimension screen_height = HeightOfScreen (screen);
1356 Dimension parent_width = 0;
1357 Dimension parent_height = 0;
1358 Dimension child_width = 0;
1359 Dimension child_height = 0;
1360 Position x;
1361 Position y;
1363 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1364 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1365 NULL);
1367 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1368 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1370 XtTranslateCoords (parent, x, y, &x, &y);
1372 if (x + child_width > screen_width)
1373 x = screen_width - child_width;
1374 if (x < 0)
1375 x = 0;
1377 if (y + child_height > screen_height)
1378 y = screen_height - child_height;
1379 if (y < 0)
1380 y = 0;
1382 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1385 static Widget
1386 recycle_instance (destroyed_instance* instance)
1388 Widget widget = instance->widget;
1390 /* widget is NULL if the parent was destroyed. */
1391 if (widget)
1393 Widget focus;
1394 Widget separator;
1396 /* Remove the destroy callback as the instance is not in the list
1397 anymore */
1398 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1399 mark_dead_instance_destroyed,
1400 (XtPointer)instance);
1402 /* Give the focus to the initial item */
1403 focus = XtNameToWidget (widget, "*value");
1404 if (!focus)
1405 focus = XtNameToWidget (widget, "*button1");
1406 if (focus)
1407 XtSetKeyboardFocus (widget, focus);
1409 /* shrink the separator label back to their original size */
1410 separator = XtNameToWidget (widget, "*separator_button");
1411 if (separator)
1412 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1414 /* Center the dialog in its parent */
1415 recenter_widget (widget);
1417 free_destroyed_instance (instance);
1418 return widget;
1421 Widget
1422 xm_create_dialog (widget_instance* instance)
1424 char* name = instance->info->type;
1425 Widget parent = instance->parent;
1426 Widget widget;
1427 Boolean pop_up_p = instance->pop_up_p;
1428 char* shell_name = 0;
1429 char* icon_name = 0;
1430 Boolean text_input_slot = False;
1431 Boolean radio_box = False;
1432 Boolean list = False;
1433 int total_buttons;
1434 int left_buttons = 0;
1435 int right_buttons = 1;
1436 destroyed_instance* dead_one;
1438 /* try to find a widget to recycle */
1439 dead_one = find_matching_instance (instance);
1440 if (dead_one)
1442 Widget recycled_widget = recycle_instance (dead_one);
1443 if (recycled_widget)
1444 return recycled_widget;
1447 switch (name [0]){
1448 case 'E': case 'e':
1449 icon_name = "dbox-error";
1450 shell_name = "Error";
1451 break;
1453 case 'I': case 'i':
1454 icon_name = "dbox-info";
1455 shell_name = "Information";
1456 break;
1458 case 'L': case 'l':
1459 list = True;
1460 icon_name = "dbox-question";
1461 shell_name = "Prompt";
1462 break;
1464 case 'P': case 'p':
1465 text_input_slot = True;
1466 icon_name = "dbox-question";
1467 shell_name = "Prompt";
1468 break;
1470 case 'Q': case 'q':
1471 icon_name = "dbox-question";
1472 shell_name = "Question";
1473 break;
1476 total_buttons = name [1] - '0';
1478 if (name [3] == 'T' || name [3] == 't')
1480 text_input_slot = False;
1481 radio_box = True;
1483 else if (name [3])
1484 right_buttons = name [4] - '0';
1486 left_buttons = total_buttons - right_buttons;
1488 widget = make_dialog (name, parent, pop_up_p,
1489 shell_name, icon_name, text_input_slot, radio_box,
1490 list, left_buttons, right_buttons);
1492 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1493 (XtPointer) instance);
1495 return widget;
1498 /* Create a menu bar. We turn off the f10 key
1499 because we have not yet managed to make it work right in Motif. */
1501 static Widget
1502 make_menubar (widget_instance* instance)
1504 Arg al[3];
1505 int ac;
1507 ac = 0;
1508 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1509 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1512 static void
1513 remove_grabs (Widget shell,
1514 XtPointer closure,
1515 XtPointer call_data)
1517 Widget menu = (Widget) closure;
1518 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1521 static Widget
1522 make_popup_menu (widget_instance* instance)
1524 Widget parent = instance->parent;
1525 Window parent_window = parent->core.window;
1526 Widget result;
1528 /* sets the parent window to 0 to fool Motif into not generating a grab */
1529 parent->core.window = 0;
1530 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1531 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1532 (XtPointer)result);
1533 parent->core.window = parent_window;
1534 return result;
1537 static Widget
1538 make_main (widget_instance* instance)
1540 Widget parent = instance->parent;
1541 Widget result;
1542 Arg al[2];
1543 int ac;
1545 ac = 0;
1546 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1547 XtSetArg (al[ac], XmNspacing, 0); ac++;
1548 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1549 return result;
1552 \f/* Table of functions to create widgets */
1554 #ifdef ENERGIZE
1556 /* interface with the XDesigner generated functions */
1557 typedef Widget (*widget_maker) (Widget);
1558 extern Widget create_project_p_sheet (Widget parent);
1559 extern Widget create_debugger_p_sheet (Widget parent);
1560 extern Widget create_breaklist_p_sheet (Widget parent);
1561 extern Widget create_le_browser_p_sheet (Widget parent);
1562 extern Widget create_class_browser_p_sheet (Widget parent);
1563 extern Widget create_call_browser_p_sheet (Widget parent);
1564 extern Widget create_build_dialog (Widget parent);
1565 extern Widget create_editmode_dialog (Widget parent);
1566 extern Widget create_search_dialog (Widget parent);
1567 extern Widget create_project_display_dialog (Widget parent);
1569 static Widget
1570 make_one (widget_instance* instance, widget_maker fn)
1572 Widget result;
1573 Arg al [64];
1574 int ac = 0;
1576 if (instance->pop_up_p)
1578 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1579 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1580 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1581 (XtPointer) instance);
1582 (*fn) (result);
1584 else
1586 result = (*fn) (instance->parent);
1587 XtRealizeWidget (result);
1589 return result;
1592 static Widget
1593 make_project_p_sheet (widget_instance* instance)
1595 return make_one (instance, create_project_p_sheet);
1598 static Widget
1599 make_debugger_p_sheet (widget_instance* instance)
1601 return make_one (instance, create_debugger_p_sheet);
1604 static Widget
1605 make_breaklist_p_sheet (widget_instance* instance)
1607 return make_one (instance, create_breaklist_p_sheet);
1610 static Widget
1611 make_le_browser_p_sheet (widget_instance* instance)
1613 return make_one (instance, create_le_browser_p_sheet);
1616 static Widget
1617 make_class_browser_p_sheet (widget_instance* instance)
1619 return make_one (instance, create_class_browser_p_sheet);
1622 static Widget
1623 make_call_browser_p_sheet (widget_instance* instance)
1625 return make_one (instance, create_call_browser_p_sheet);
1628 static Widget
1629 make_build_dialog (widget_instance* instance)
1631 return make_one (instance, create_build_dialog);
1634 static Widget
1635 make_editmode_dialog (widget_instance* instance)
1637 return make_one (instance, create_editmode_dialog);
1640 static Widget
1641 make_search_dialog (widget_instance* instance)
1643 return make_one (instance, create_search_dialog);
1646 static Widget
1647 make_project_display_dialog (widget_instance* instance)
1649 return make_one (instance, create_project_display_dialog);
1652 #endif /* ENERGIZE */
1654 widget_creation_entry
1655 xm_creation_table [] =
1657 {"menubar", make_menubar},
1658 {"popup", make_popup_menu},
1659 {"main", make_main},
1660 #ifdef ENERGIZE
1661 {"project_p_sheet", make_project_p_sheet},
1662 {"debugger_p_sheet", make_debugger_p_sheet},
1663 {"breaklist_psheet", make_breaklist_p_sheet},
1664 {"leb_psheet", make_le_browser_p_sheet},
1665 {"class_browser_psheet", make_class_browser_p_sheet},
1666 {"ctree_browser_psheet", make_call_browser_p_sheet},
1667 {"build", make_build_dialog},
1668 {"editmode", make_editmode_dialog},
1669 {"search", make_search_dialog},
1670 {"project_display", make_project_display_dialog},
1671 #endif /* ENERGIZE */
1672 {NULL, NULL}
1675 \f/* Destruction of instances */
1676 void
1677 xm_destroy_instance ( widget_instance* instance)
1679 Widget widget = instance->widget;
1680 /* recycle the dialog boxes */
1681 /* Disable the recycling until we can find a way to have the dialog box
1682 get reasonable layout after we modify its contents. */
1683 if (0
1684 && XtClass (widget) == xmDialogShellWidgetClass)
1686 destroyed_instance* dead_instance =
1687 make_destroyed_instance (instance->info->name,
1688 instance->info->type,
1689 instance->widget,
1690 instance->parent,
1691 instance->pop_up_p);
1692 dead_instance->next = all_destroyed_instances;
1693 all_destroyed_instances = dead_instance;
1694 XtUnmanageChild (first_child (instance->widget));
1695 XFlush (XtDisplay (instance->widget));
1696 XtAddCallback (instance->parent, XtNdestroyCallback,
1697 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1699 else
1701 /* This might not be necessary now that the nosel is attached to
1702 popdown instead of destroy, but it can't hurt. */
1703 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1704 xm_nosel_callback, (XtPointer)instance);
1705 XtDestroyWidget (instance->widget);
1709 \f/* popup utility */
1710 void
1711 xm_popup_menu (Widget widget, 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 /* Setting the menuPost resource only required by Motif 1.1 and
1733 LessTif 0.84 and earlier. With later versions of LessTif,
1734 setting menuPost is unnecessary and may cause problems, so
1735 don't do it. */
1736 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1738 /* This is so totally ridiculous: there's NO WAY to tell Motif
1739 that *any* button can select a menu item. Only one button
1740 can have that honor. */
1742 char *trans = 0;
1743 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1744 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1745 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1746 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1747 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1748 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1750 #endif
1752 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1755 XtManageChild (widget);
1758 static void
1759 set_min_dialog_size (Widget w)
1761 short width;
1762 short height;
1763 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1764 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1767 void
1768 xm_pop_instance (widget_instance* instance, Boolean up)
1770 Widget widget = instance->widget;
1772 if (XtClass (widget) == xmDialogShellWidgetClass)
1774 Widget widget_to_manage = first_child (widget);
1775 if (up)
1777 XtManageChild (widget_to_manage);
1778 set_min_dialog_size (widget);
1779 XtSetKeyboardFocus (instance->parent, widget);
1781 else
1782 XtUnmanageChild (widget_to_manage);
1784 else
1786 if (up)
1787 XtManageChild (widget);
1788 else
1789 XtUnmanageChild (widget);
1794 /* motif callback */
1796 static void
1797 do_call (Widget widget,
1798 XtPointer closure,
1799 enum do_call_type type)
1801 Arg al [256];
1802 int ac;
1803 XtPointer user_data;
1804 widget_instance* instance = (widget_instance*)closure;
1805 Widget instance_widget;
1806 LWLIB_ID id;
1808 if (!instance)
1809 return;
1810 if (widget->core.being_destroyed)
1811 return;
1813 instance_widget = instance->widget;
1814 if (!instance_widget)
1815 return;
1817 id = instance->info->id;
1818 ac = 0;
1819 user_data = NULL;
1820 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1821 XtGetValues (widget, al, ac);
1823 switch (type)
1825 case pre_activate:
1826 if (instance->info->pre_activate_cb)
1827 instance->info->pre_activate_cb (widget, id, user_data);
1828 break;
1830 case selection:
1831 if (instance->info->selection_cb)
1832 instance->info->selection_cb (widget, id, user_data);
1833 break;
1835 case no_selection:
1836 if (instance->info->selection_cb)
1837 instance->info->selection_cb (widget, id, (XtPointer) -1);
1838 break;
1840 case post_activate:
1841 if (instance->info->post_activate_cb)
1842 instance->info->post_activate_cb (widget, id, user_data);
1843 break;
1845 default:
1846 abort ();
1850 /* Like lw_internal_update_other_instances except that it does not do
1851 anything if its shell parent is not managed. This is to protect
1852 lw_internal_update_other_instances to dereference freed memory
1853 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1854 list */
1855 static void
1856 xm_internal_update_other_instances (Widget widget,
1857 XtPointer closure,
1858 XtPointer call_data)
1860 Widget parent;
1861 for (parent = widget; parent; parent = XtParent (parent))
1862 if (XtIsShell (parent))
1863 break;
1864 else if (!XtIsManaged (parent))
1865 return;
1866 lw_internal_update_other_instances (widget, closure, call_data);
1869 static void
1870 xm_generic_callback (Widget widget,
1871 XtPointer closure,
1872 XtPointer call_data)
1874 lw_internal_update_other_instances (widget, closure, call_data);
1875 do_call (widget, closure, selection);
1878 static void
1879 xm_nosel_callback (Widget widget,
1880 XtPointer closure,
1881 XtPointer call_data)
1883 /* This callback is only called when a dialog box is dismissed with
1884 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1885 box to be destroyed in that case, not just unmapped, so that it
1886 releases its keyboard grabs. But there are problems with running
1887 our callbacks while the widget is in the process of being
1888 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1889 XmDESTROY and then destroy it ourself after having run the
1890 callback. */
1891 do_call (widget, closure, no_selection);
1892 XtDestroyWidget (widget);
1895 static void
1896 xm_pull_down_callback (Widget widget,
1897 XtPointer closure,
1898 XtPointer call_data)
1900 Widget parent = XtParent (widget);
1902 if (XmIsRowColumn (parent))
1904 unsigned char type = 0xff;
1905 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1906 if (type == XmMENU_BAR)
1907 do_call (widget, closure, pre_activate);
1912 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1913 CLOSURE is a pointer to the widget_instance of the shell,
1915 Note that this callback is called for each cascade button in a
1916 menu, whether or not its submenu is visible. */
1918 static void
1919 xm_pop_down_callback (Widget widget,
1920 XtPointer closure,
1921 XtPointer call_data)
1923 widget_instance *instance = (widget_instance *) closure;
1925 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1926 || XtParent (widget) == instance->parent)
1927 do_call (widget, closure, post_activate);
1931 /* set the keyboard focus */
1932 void
1933 xm_set_keyboard_focus (Widget parent, Widget w)
1935 XmProcessTraversal (w, 0);
1936 XtSetKeyboardFocus (parent, w);
1939 /* Motif hack to set the main window areas. */
1940 void
1941 xm_set_main_areas (Widget parent,
1942 Widget menubar,
1943 Widget work_area)
1945 XmMainWindowSetAreas (parent,
1946 menubar, /* menubar (maybe 0) */
1947 0, /* command area (psheets) */
1948 0, /* horizontal scroll */
1949 0, /* vertical scroll */
1950 work_area); /* work area */
1953 /* Motif hack to control resizing on the menubar. */
1954 void
1955 xm_manage_resizing (Widget w, Boolean flag)
1957 XtVaSetValues (w, XtNallowShellResize, flag, NULL);