Merge from emacs-23.
[emacs.git] / lwlib / lwlib-Xm.c
blobb6c2ef1b3233ecb5519b7431846004b74effe1ff
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
4 Free Software Foundation, Inc.
5 Copyright (C) 1992 Lucid, Inc.
7 This file is part of the Lucid Widget Library.
9 The Lucid Widget Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 1, or (at your option)
12 any later version.
14 The Lucid Widget Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <setjmp.h>
32 #include <X11/StringDefs.h>
33 #include <X11/IntrinsicP.h>
34 #include <X11/ObjectP.h>
35 #include <X11/CoreP.h>
36 #include <X11/CompositeP.h>
38 #include "../src/lisp.h"
40 #include "lwlib-Xm.h"
41 #include "lwlib-utils.h"
43 #include <Xm/BulletinB.h>
44 #include <Xm/CascadeB.h>
45 #include <Xm/CascadeBG.h>
46 #include <Xm/DrawingA.h>
47 #include <Xm/FileSB.h>
48 #include <Xm/Label.h>
49 #include <Xm/List.h>
50 #include <Xm/MainW.h>
51 #include <Xm/MenuShell.h>
52 #include <Xm/MessageB.h>
53 #include <Xm/PanedW.h>
54 #include <Xm/PushB.h>
55 #include <Xm/PushBG.h>
56 #include <Xm/ArrowB.h>
57 #include <Xm/SelectioB.h>
58 #include <Xm/Text.h>
59 #include <Xm/TextF.h>
60 #include <Xm/ToggleB.h>
61 #include <Xm/ToggleBG.h>
62 #include <Xm/RowColumn.h>
63 #include <Xm/ScrolledW.h>
64 #include <Xm/Separator.h>
65 #include <Xm/DialogS.h>
66 #include <Xm/Form.h>
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 (char *, char *,
83 Widget, Widget,
84 Boolean);
85 static void free_destroyed_instance (destroyed_instance*);
86 Widget first_child (Widget);
87 Boolean lw_motif_widget_p (Widget);
88 static XmString resource_motif_string (Widget, char *);
89 static void destroy_all_children (Widget, int);
90 static void xm_update_label (widget_instance *, Widget, widget_value *);
91 static void xm_update_list (widget_instance *, Widget, widget_value *);
92 static void xm_update_pushbutton (widget_instance *, Widget,
93 widget_value *);
94 static void xm_update_cascadebutton (widget_instance *, Widget,
95 widget_value *);
96 static void xm_update_toggle (widget_instance *, Widget, widget_value *);
97 static void xm_update_radiobox (widget_instance *, Widget, widget_value *);
98 static void make_menu_in_widget (widget_instance *, Widget,
99 widget_value *, int);
100 static void update_one_menu_entry (widget_instance *, Widget,
101 widget_value *, Boolean);
102 static void xm_update_menu (widget_instance *, Widget, widget_value *,
103 Boolean);
104 static void xm_update_text (widget_instance *, Widget, widget_value *);
105 static void xm_update_text_field (widget_instance *, Widget,
106 widget_value *);
107 void xm_update_one_value (widget_instance *, Widget, widget_value *);
108 static void activate_button (Widget, XtPointer, XtPointer);
109 static Widget make_dialog (char *, Widget, Boolean, char *, char *,
110 Boolean, Boolean, Boolean, int, int);
111 static destroyed_instance* find_matching_instance (widget_instance*);
112 static void mark_dead_instance_destroyed (Widget, XtPointer, XtPointer);
113 static void recenter_widget (Widget);
114 static Widget recycle_instance (destroyed_instance*);
115 Widget xm_create_dialog (widget_instance*);
116 static Widget make_menubar (widget_instance*);
117 static void remove_grabs (Widget, XtPointer, XtPointer);
118 static Widget make_popup_menu (widget_instance*);
119 static Widget make_main (widget_instance*);
120 void xm_destroy_instance (widget_instance*);
121 void xm_popup_menu (Widget, XEvent *);
122 static void set_min_dialog_size (Widget);
123 static void do_call (Widget, XtPointer, enum do_call_type);
124 static void xm_generic_callback (Widget, XtPointer, XtPointer);
125 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
126 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
127 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
128 void xm_set_keyboard_focus (Widget, Widget);
129 void xm_set_main_areas (Widget, Widget, Widget);
130 static void xm_internal_update_other_instances (Widget, XtPointer,
131 XtPointer);
132 static void xm_arm_callback (Widget, XtPointer, XtPointer);
134 #if 0
135 void xm_update_one_widget (widget_instance *, Widget, widget_value *,
136 Boolean);
137 void xm_pop_instance (widget_instance*, Boolean);
138 void xm_manage_resizing (Widget, Boolean);
139 #endif
142 #if 0
144 /* Print the complete X resource name of widget WIDGET to stderr.
145 This is sometimes handy to have available. */
147 void
148 x_print_complete_resource_name (Widget widget)
150 int i;
151 String names[100];
153 for (i = 0; i < 100 && widget != NULL; ++i)
155 names[i] = XtName (widget);
156 widget = XtParent (widget);
159 for (--i; i >= 1; --i)
160 fprintf (stderr, "%s.", names[i]);
161 fprintf (stderr, "%s\n", names[0]);
164 #endif /* 0 */
167 static destroyed_instance *all_destroyed_instances = NULL;
169 static destroyed_instance*
170 make_destroyed_instance (char* name,
171 char* type,
172 Widget widget,
173 Widget parent,
174 Boolean pop_up_p)
176 destroyed_instance* instance =
177 (destroyed_instance*)malloc (sizeof (destroyed_instance));
178 instance->name = safe_strdup (name);
179 instance->type = safe_strdup (type);
180 instance->widget = widget;
181 instance->parent = parent;
182 instance->pop_up_p = pop_up_p;
183 instance->next = NULL;
184 return instance;
187 static void
188 free_destroyed_instance (destroyed_instance* instance)
190 free (instance->name);
191 free (instance->type);
192 free (instance);
195 \f/* motif utility functions */
196 Widget
197 first_child (Widget widget)
199 return ((CompositeWidget)widget)->composite.children [0];
202 Boolean
203 lw_motif_widget_p (Widget widget)
205 return
206 XtClass (widget) == xmDialogShellWidgetClass
207 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
210 static XmString
211 resource_motif_string (Widget widget,
212 char* name)
214 XtResource resource;
215 XmString result = 0;
217 resource.resource_name = name;
218 resource.resource_class = XmCXmString;
219 resource.resource_type = XmRXmString;
220 resource.resource_size = sizeof (XmString);
221 resource.resource_offset = 0;
222 resource.default_type = XtRImmediate;
223 resource.default_addr = 0;
225 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
226 "DialogString", &resource, 1, NULL, 0);
227 return result;
230 /* Destroy all of the children of WIDGET
231 starting with number FIRST_CHILD_TO_DESTROY. */
233 static void
234 destroy_all_children (Widget widget,
235 int first_child_to_destroy)
237 Widget* children;
238 unsigned int number;
239 int i;
241 children = XtCompositeChildren (widget, &number);
242 if (children)
244 XtUnmanageChildren (children + first_child_to_destroy,
245 number - first_child_to_destroy);
247 /* Unmanage all children and destroy them. They will only be
248 really destroyed when we get out of DispatchEvent. */
249 for (i = first_child_to_destroy; i < number; i++)
251 Arg al[2];
252 Widget submenu = 0;
253 /* Cascade buttons have submenus,and these submenus
254 need to be freed. But they are not included in
255 XtCompositeChildren. So get it out of the cascade button
256 and free it. If this child is not a cascade button,
257 then submenu should remain unchanged. */
258 XtSetArg (al[0], XmNsubMenuId, &submenu);
259 XtGetValues (children[i], al, 1);
260 if (submenu)
262 destroy_all_children (submenu, 0);
263 XtDestroyWidget (submenu);
265 XtDestroyWidget (children[i]);
268 XtFree ((char *) children);
274 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
275 menu. CLIENT_DATA contains a pointer to the widget_value
276 corresponding to widget W. CALL_DATA contains a
277 XmPushButtonCallbackStruct containing the reason why the callback
278 is called. */
280 static void
281 xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
283 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
284 widget_value *wv = (widget_value *) client_data;
285 widget_instance *instance;
287 /* Get the id of the menu bar or popup menu this widget is in. */
288 while (w != NULL)
290 if (XmIsRowColumn (w))
292 unsigned char type = 0xff;
294 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
295 if (type == XmMENU_BAR || type == XmMENU_POPUP)
296 break;
299 w = XtParent (w);
302 if (w != NULL)
304 instance = lw_get_widget_instance (w);
305 if (instance && instance->info->highlight_cb)
307 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
308 instance->info->highlight_cb (w, instance->info->id, call_data);
315 /* Update the label of widget WIDGET. WIDGET must be a Label widget
316 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
317 the value to update.
319 Menus:
321 Emacs fills VAL->name with the text to display in the menu, and
322 sets VAL->value to null. Function make_menu_in_widget creates
323 widgets with VAL->name as resource name. This works because the
324 Label widget uses its resource name for display if no
325 XmNlabelString is set.
327 Dialogs:
329 VAL->name is again set to the resource name, but VAL->value is
330 not null, and contains the label string to display. */
332 static void
333 xm_update_label (widget_instance* instance,
334 Widget widget,
335 widget_value* val)
337 XmString res_string = 0;
338 XmString built_string = 0;
339 XmString key_string = 0;
340 Arg al [256];
341 int ac;
343 ac = 0;
345 if (val->value)
347 /* A label string is specified, i.e. we are in a dialog. First
348 see if it is overridden by something from the resource file. */
349 res_string = resource_motif_string (widget, val->value);
351 if (res_string)
353 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
355 else
357 built_string =
358 XmStringCreateLocalized (val->value);
359 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
362 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
365 if (val->key)
367 key_string = XmStringCreateLocalized (val->key);
368 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
371 if (ac)
372 XtSetValues (widget, al, ac);
374 if (built_string)
375 XmStringFree (built_string);
377 if (key_string)
378 XmStringFree (key_string);
381 \f/* update of list */
382 static void
383 xm_update_list (widget_instance* instance,
384 Widget widget,
385 widget_value* val)
387 widget_value* cur;
388 int i;
389 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
390 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
391 instance);
392 for (cur = val->contents, i = 0; cur; cur = cur->next)
393 if (cur->value)
395 XmString xmstr = XmStringCreateLocalized (cur->value);
396 i += 1;
397 XmListAddItem (widget, xmstr, 0);
398 if (cur->selected)
399 XmListSelectPos (widget, i, False);
400 XmStringFree (xmstr);
404 \f/* update of buttons */
405 static void
406 xm_update_pushbutton (widget_instance* instance,
407 Widget widget,
408 widget_value* val)
410 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
411 XtRemoveAllCallbacks (widget, XmNactivateCallback);
412 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
415 static void
416 xm_update_cascadebutton (widget_instance* instance,
417 Widget widget,
418 widget_value* val)
420 /* Should also rebuild the menu by calling ...update_menu... */
421 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
422 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
423 instance);
426 \f/* update toggle and radiobox */
427 static void
428 xm_update_toggle (widget_instance* instance,
429 Widget widget,
430 widget_value* val)
432 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
433 XtAddCallback (widget, XmNvalueChangedCallback,
434 xm_generic_callback, instance);
435 XtVaSetValues (widget, XmNset, val->selected,
436 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
439 static void
440 xm_update_radiobox (widget_instance* instance,
441 Widget widget,
442 widget_value* val)
445 Widget toggle;
446 widget_value* cur;
448 /* update the callback */
449 XtRemoveAllCallbacks (widget, XmNentryCallback);
450 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
452 /* first update all the toggles */
453 /* Energize kernel interface is currently bad. It sets the selected widget
454 with the selected flag but returns it by its name. So we currently
455 have to support both setting the selection with the selected slot
456 of val contents and setting it with the "value" slot of val. The latter
457 has a higher priority. This to be removed when the kernel is fixed. */
458 for (cur = val->contents; cur; cur = cur->next)
460 toggle = XtNameToWidget (widget, cur->value);
461 if (toggle)
463 XtSetSensitive (toggle, cur->enabled);
464 if (!val->value && cur->selected)
465 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
466 if (val->value && strcmp (val->value, cur->value))
467 XtVaSetValues (toggle, XmNset, False, NULL);
471 /* The selected was specified by the value slot */
472 if (val->value)
474 toggle = XtNameToWidget (widget, val->value);
475 if (toggle)
476 XtVaSetValues (toggle, XmNset, True, NULL);
481 /* update a popup menu, pulldown menu or a menubar */
483 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
485 static void
486 make_menu_in_widget (widget_instance* instance,
487 Widget widget,
488 widget_value* val,
489 int keep_first_children)
491 Widget* children = 0;
492 int num_children;
493 int child_index;
494 widget_value* cur;
495 Widget button = 0;
496 Widget title = 0;
497 Widget menu;
498 Arg al [256];
499 int ac;
500 Boolean menubar_p;
501 unsigned char type;
503 Widget* old_children;
504 unsigned int old_num_children;
506 /* Disable drag and drop for labels in menu bar. */
507 static char overrideTrans[] = "<Btn2Down>: Noop()";
508 XtTranslations override = XtParseTranslationTable (overrideTrans);
510 old_children = XtCompositeChildren (widget, &old_num_children);
512 /* Allocate the children array */
513 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
515 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
517 /* WIDGET should be a RowColumn. */
518 if (!XmIsRowColumn (widget))
519 abort ();
521 /* Determine whether WIDGET is a menu bar. */
522 type = -1;
523 XtSetArg (al[0], XmNrowColumnType, &type);
524 XtGetValues (widget, al, 1);
525 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
526 abort ();
527 menubar_p = type == XmMENU_BAR;
529 /* Add a callback to popups and pulldowns that is called when
530 it is made invisible again. */
531 if (!menubar_p)
532 XtAddCallback (XtParent (widget), XmNpopdownCallback,
533 xm_pop_down_callback, (XtPointer)instance);
535 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
536 for (child_index = 0, cur = val; child_index < keep_first_children;
537 child_index++, cur = cur->next)
538 children[child_index] = old_children[child_index];
540 /* Check that those are all we have
541 (the caller should have deleted the rest). */
542 if (old_num_children != keep_first_children)
543 abort ();
545 /* Create the rest. */
546 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
548 enum menu_separator separator;
550 ac = 0;
551 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
552 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
553 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
555 if (instance->pop_up_p && !cur->contents && !cur->call_data
556 && !lw_separator_p (cur->name, &separator, 1))
558 ac = 0;
559 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
560 title = button = XmCreateLabel (widget, cur->name, al, ac);
562 else if (lw_separator_p (cur->name, &separator, 1))
564 ac = 0;
565 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
566 button = XmCreateSeparator (widget, cur->name, al, ac);
568 else if (!cur->contents)
570 if (menubar_p)
571 button = XmCreateCascadeButton (widget, cur->name, al, ac);
572 else if (!cur->call_data)
573 button = XmCreateLabel (widget, cur->name, al, ac);
574 else if (cur->button_type == BUTTON_TYPE_TOGGLE
575 || cur->button_type == BUTTON_TYPE_RADIO)
577 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
578 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
579 XtSetArg (al[ac], XmNindicatorType,
580 (cur->button_type == BUTTON_TYPE_TOGGLE
581 ? XmN_OF_MANY : XmONE_OF_MANY));
582 ++ac;
583 button = XmCreateToggleButton (widget, cur->name, al, ac);
584 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
585 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
587 else
589 button = XmCreatePushButton (widget, cur->name, al, ac);
590 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
591 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
594 xm_update_label (instance, button, cur);
596 /* Add a callback that is called when the button is
597 selected. Toggle buttons don't support
598 XmNactivateCallback, we use XmNvalueChangedCallback in
599 that case. Don't add a callback to a simple label. */
600 if (cur->button_type)
601 xm_update_toggle (instance, button, cur);
602 else if (cur->call_data)
603 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
604 (XtPointer)instance);
606 else
608 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
610 make_menu_in_widget (instance, menu, cur->contents, 0);
611 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
612 button = XmCreateCascadeButton (widget, cur->name, al, ac);
614 xm_update_label (instance, button, cur);
616 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
617 (XtPointer)instance);
618 XtOverrideTranslations (button, override);
622 children[child_index] = button;
625 /* Last entry is the help button. The original comment read "Has to
626 be done after managing the buttons otherwise the menubar is only
627 4 pixels high." This is no longer true, and to make
628 XmNmenuHelpWidget work, we need to set it before managing the
629 children.. --gerd. */
630 if (button)
631 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
633 if (num_children)
634 XtManageChildren (children, num_children);
636 XtFree ((char *) children);
637 if (old_children)
638 XtFree ((char *) old_children);
641 static void
642 update_one_menu_entry (widget_instance* instance,
643 Widget widget,
644 widget_value* val,
645 Boolean deep_p)
647 Arg al [256];
648 int ac;
649 Widget menu;
650 widget_value* contents;
652 if (val->this_one_change == NO_CHANGE)
653 return;
655 /* update the sensitivity and userdata */
656 /* Common to all widget types */
657 XtSetSensitive (widget, val->enabled);
658 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
660 /* update the menu button as a label. */
661 if (val->this_one_change >= VISIBLE_CHANGE)
663 xm_update_label (instance, widget, val);
664 if (val->button_type)
665 xm_update_toggle (instance, widget, val);
668 /* update the pulldown/pullaside as needed */
669 ac = 0;
670 menu = NULL;
671 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
672 XtGetValues (widget, al, ac);
674 contents = val->contents;
676 if (!menu)
678 if (contents)
680 unsigned int old_num_children, i;
681 Widget parent;
682 Widget *widget_list;
684 parent = XtParent (widget);
685 widget_list = XtCompositeChildren (parent, &old_num_children);
687 /* Find the widget position within the parent's widget list. */
688 for (i = 0; i < old_num_children; i++)
689 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
690 break;
691 if (i == old_num_children)
692 abort ();
693 if (XmIsCascadeButton (widget_list[i]))
695 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
696 make_menu_in_widget (instance, menu, contents, 0);
697 ac = 0;
698 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
699 XtSetValues (widget, al, ac);
701 else
703 Widget button;
705 /* The current menuitem is a XmPushButtonGadget, it
706 needs to be replaced by a CascadeButtonGadget */
707 XtDestroyWidget (widget_list[i]);
708 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
709 make_menu_in_widget (instance, menu, contents, 0);
710 ac = 0;
711 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
712 /* Non-zero values don't work reliably in
713 conjunction with Emacs' event loop */
714 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
715 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
716 /* Tell Motif to put it in the right place */
717 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
718 #endif
719 button = XmCreateCascadeButton (parent, val->name, al, ac);
720 xm_update_label (instance, button, val);
722 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
723 (XtPointer)instance);
724 XtManageChild (button);
727 if (widget_list)
728 XtFree ((char*) widget_list);
731 else if (!contents)
733 ac = 0;
734 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
735 XtSetValues (widget, al, ac);
736 XtDestroyWidget (menu);
738 else if (deep_p && contents->change != NO_CHANGE)
739 xm_update_menu (instance, menu, val, 1);
742 static void
743 xm_update_menu (widget_instance* instance,
744 Widget widget,
745 widget_value* val,
746 Boolean deep_p)
748 Widget* children;
749 unsigned int num_children;
750 int num_children_to_keep = 0;
751 int i;
752 widget_value* cur;
754 children = XtCompositeChildren (widget, &num_children);
756 /* Widget is a RowColumn widget whose contents have to be updated
757 * to reflect the list of items in val->contents */
759 /* See how many buttons we can keep, and how many we
760 must completely replace. */
761 if (val->contents == 0)
762 num_children_to_keep = 0;
763 else if (val->contents->change == STRUCTURAL_CHANGE)
765 if (children)
767 for (i = 0, cur = val->contents;
768 (i < num_children
769 && cur); /* how else to ditch unwanted children ?? - mgd */
770 i++, cur = cur->next)
772 if (cur->this_one_change == STRUCTURAL_CHANGE)
773 break;
776 num_children_to_keep = i;
779 else
780 num_children_to_keep = num_children;
782 /* Update all the buttons of the RowColumn, in order,
783 except for those we are going to replace entirely. */
784 if (children)
786 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
788 if (!cur)
790 num_children_to_keep = i;
791 break;
793 if (children [i]->core.being_destroyed
794 || strcmp (XtName (children [i]), cur->name))
795 continue;
796 update_one_menu_entry (instance, children [i], cur, deep_p);
797 cur = cur->next;
801 /* Now replace from scratch all the buttons after the last
802 place that the top-level structure changed. */
803 if (val->contents && val->contents->change == STRUCTURAL_CHANGE)
805 destroy_all_children (widget, num_children_to_keep);
806 make_menu_in_widget (instance, widget, val->contents,
807 num_children_to_keep);
810 XtFree ((char *) children);
814 /* update text widgets */
816 static void
817 xm_update_text (widget_instance* instance,
818 Widget widget,
819 widget_value* val)
821 XmTextSetString (widget, val->value ? val->value : "");
822 XtRemoveAllCallbacks (widget, XmNactivateCallback);
823 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
824 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
825 XtAddCallback (widget, XmNvalueChangedCallback,
826 xm_internal_update_other_instances, instance);
829 static void
830 xm_update_text_field (widget_instance* instance,
831 Widget widget,
832 widget_value* val)
834 XmTextFieldSetString (widget, val->value ? val->value : "");
835 XtRemoveAllCallbacks (widget, XmNactivateCallback);
836 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
837 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
838 XtAddCallback (widget, XmNvalueChangedCallback,
839 xm_internal_update_other_instances, instance);
843 /* update a motif widget */
845 void
846 xm_update_one_widget (widget_instance* instance,
847 Widget widget,
848 widget_value* val,
849 Boolean deep_p)
851 WidgetClass class;
853 /* Mark as not edited */
854 val->edited = False;
856 /* Common to all widget types */
857 XtSetSensitive (widget, val->enabled);
858 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
860 /* Common to all label like widgets */
861 if (XtIsSubclass (widget, xmLabelWidgetClass))
862 xm_update_label (instance, widget, val);
864 class = XtClass (widget);
865 /* Class specific things */
866 if (class == xmPushButtonWidgetClass ||
867 class == xmArrowButtonWidgetClass)
869 xm_update_pushbutton (instance, widget, val);
871 else if (class == xmCascadeButtonWidgetClass)
873 xm_update_cascadebutton (instance, widget, val);
875 else if (class == xmToggleButtonWidgetClass
876 || class == xmToggleButtonGadgetClass)
878 xm_update_toggle (instance, widget, val);
880 else if (class == xmRowColumnWidgetClass)
882 Boolean radiobox = 0;
883 int ac = 0;
884 Arg al [1];
886 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
887 XtGetValues (widget, al, ac);
889 if (radiobox)
890 xm_update_radiobox (instance, widget, val);
891 else
892 xm_update_menu (instance, widget, val, deep_p);
894 else if (class == xmTextWidgetClass)
896 xm_update_text (instance, widget, val);
898 else if (class == xmTextFieldWidgetClass)
900 xm_update_text_field (instance, widget, val);
902 else if (class == xmListWidgetClass)
904 xm_update_list (instance, widget, val);
908 \f/* getting the value back */
909 void
910 xm_update_one_value (widget_instance* instance,
911 Widget widget,
912 widget_value* val)
914 WidgetClass class = XtClass (widget);
915 widget_value *old_wv;
917 /* copy the call_data slot into the "return" widget_value */
918 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
919 if (!strcmp (val->name, old_wv->name))
921 val->call_data = old_wv->call_data;
922 break;
925 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
927 XtVaGetValues (widget, XmNset, &val->selected, NULL);
928 val->edited = True;
930 else if (class == xmTextWidgetClass)
932 free (val->value);
933 val->value = XmTextGetString (widget);
934 val->edited = True;
936 else if (class == xmTextFieldWidgetClass)
938 free (val->value);
939 val->value = XmTextFieldGetString (widget);
940 val->edited = True;
942 else if (class == xmRowColumnWidgetClass)
944 Boolean radiobox = 0;
945 int ac = 0;
946 Arg al [1];
948 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
949 XtGetValues (widget, al, ac);
951 if (radiobox)
953 CompositeWidget radio = (CompositeWidget)widget;
954 int i;
955 for (i = 0; i < radio->composite.num_children; i++)
957 int set = False;
958 Widget toggle = radio->composite.children [i];
960 XtVaGetValues (toggle, XmNset, &set, NULL);
961 if (set)
963 free (val->value);
964 val->value = safe_strdup (XtName (toggle));
967 val->edited = True;
970 else if (class == xmListWidgetClass)
972 int pos_cnt;
973 int* pos_list;
974 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
976 int i;
977 widget_value* cur;
978 for (cur = val->contents, i = 0; cur; cur = cur->next)
979 if (cur->value)
981 int j;
982 cur->selected = False;
983 i += 1;
984 for (j = 0; j < pos_cnt; j++)
985 if (pos_list [j] == i)
987 cur->selected = True;
988 val->value = safe_strdup (cur->name);
991 val->edited = 1;
992 XtFree ((char *) pos_list);
998 /* This function is for activating a button from a program. It's wrong because
999 we pass a NULL argument in the call_data which is not Motif compatible.
1000 This is used from the XmNdefaultAction callback of the List widgets to
1001 have a double-click put down a dialog box like the button would do.
1002 I could not find a way to do that with accelerators.
1004 static void
1005 activate_button (Widget widget,
1006 XtPointer closure,
1007 XtPointer call_data)
1009 Widget button = (Widget)closure;
1010 XtCallCallbacks (button, XmNactivateCallback, NULL);
1013 /* creation functions */
1015 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1016 static void
1017 dialog_key_cb (Widget widget,
1018 XtPointer closure,
1019 XEvent *event,
1020 Boolean *continue_to_dispatch)
1022 KeySym sym = 0;
1023 Modifiers modif_ret;
1025 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1026 &modif_ret, &sym);
1028 if (sym == osfXK_Cancel)
1030 Widget w = *((Widget *) closure);
1032 while (w && ! XtIsShell (w))
1033 w = XtParent (w);
1035 if (XtIsShell (w)) XtPopdown (w);
1038 *continue_to_dispatch = TRUE;
1041 /* dialogs */
1042 static Widget
1043 make_dialog (char* name,
1044 Widget parent,
1045 Boolean pop_up_p,
1046 char* shell_title,
1047 char* icon_name,
1048 Boolean text_input_slot,
1049 Boolean radio_box,
1050 Boolean list,
1051 int left_buttons,
1052 int right_buttons)
1054 Widget result;
1055 Widget form;
1056 Widget row;
1057 Widget icon;
1058 Widget icon_separator;
1059 Widget message;
1060 Widget value = 0;
1061 Widget separator;
1062 Widget button = 0;
1063 Widget children [16]; /* for the final XtManageChildren */
1064 int n_children;
1065 Arg al[64]; /* Arg List */
1066 int ac; /* Arg Count */
1067 int i;
1069 if (pop_up_p)
1071 ac = 0;
1072 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1073 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1074 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1075 result = XmCreateDialogShell (parent, "dialog", al, ac);
1076 ac = 0;
1077 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1078 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1079 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1080 form = XmCreateForm (result, shell_title, al, ac);
1082 else
1084 ac = 0;
1085 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1086 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1087 form = XmCreateForm (parent, shell_title, al, ac);
1088 result = form;
1091 n_children = left_buttons + right_buttons + 1;
1092 ac = 0;
1093 XtSetArg(al[ac], XmNpacking, n_children == 3?
1094 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1095 XtSetArg(al[ac], XmNorientation, n_children == 3?
1096 XmVERTICAL: XmHORIZONTAL); ac++;
1097 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1098 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1099 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1100 XtSetArg(al[ac], XmNspacing, 13); ac++;
1101 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1102 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1103 XtSetArg(al[ac], XmNisAligned, True); ac++;
1104 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1105 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1106 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1107 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1108 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1109 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1110 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1111 row = XmCreateRowColumn (form, "row", al, ac);
1113 n_children = 0;
1114 for (i = 0; i < left_buttons; i++)
1116 char button_name [16];
1117 sprintf (button_name, "button%d", i + 1);
1118 ac = 0;
1119 if (i == 0)
1121 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1122 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1124 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1125 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1126 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1127 XtAddEventHandler (children [n_children],
1128 KeyPressMask, False, dialog_key_cb, result);
1130 if (i == 0)
1132 button = children [n_children];
1133 ac = 0;
1134 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1135 XtSetValues (row, al, ac);
1138 n_children++;
1141 /* invisible separator button */
1142 ac = 0;
1143 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1144 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1145 n_children++;
1147 for (i = 0; i < right_buttons; i++)
1149 char button_name [16];
1150 sprintf (button_name, "button%d", left_buttons + i + 1);
1151 ac = 0;
1152 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1153 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1154 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1155 XtAddEventHandler (children [n_children],
1156 KeyPressMask, False, dialog_key_cb, result);
1158 if (! button) button = children [n_children];
1159 n_children++;
1162 XtManageChildren (children, n_children);
1164 ac = 0;
1165 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1166 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1167 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1168 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1169 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1170 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1171 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1172 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1173 separator = XmCreateSeparator (form, "", al, ac);
1175 ac = 0;
1176 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1177 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1178 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1179 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1180 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1181 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1182 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1183 icon = XmCreateLabel (form, icon_name, al, ac);
1185 ac = 0;
1186 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1187 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1188 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1189 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1190 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1191 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1192 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1193 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1194 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1195 icon_separator = XmCreateLabel (form, "", al, ac);
1197 if (text_input_slot)
1199 ac = 0;
1200 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1201 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1202 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1203 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1204 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1205 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1206 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1207 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1208 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1209 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1210 value = XmCreateTextField (form, "value", al, ac);
1212 else if (radio_box)
1214 Widget radio_butt;
1215 ac = 0;
1216 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1217 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1218 XtSetArg(al[ac], XmNspacing, 13); ac++;
1219 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1220 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1221 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1222 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1223 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1224 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1225 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1226 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1227 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1228 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1229 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1230 ac = 0;
1231 i = 0;
1232 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1233 children [i++] = radio_butt;
1234 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1235 children [i++] = radio_butt;
1236 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1237 children [i++] = radio_butt;
1238 XtManageChildren (children, i);
1240 else if (list)
1242 ac = 0;
1243 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1244 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1245 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1246 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1247 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1248 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1249 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1250 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1251 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1252 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1253 value = XmCreateScrolledList (form, "list", al, ac);
1255 /* this is the easiest way I found to have the dble click in the
1256 list activate the default button */
1257 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1260 ac = 0;
1261 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1262 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1263 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1264 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1265 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1266 XtSetArg(al[ac], XmNbottomWidget,
1267 text_input_slot || radio_box || list ? value : separator); ac++;
1268 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1269 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1270 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1271 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1272 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1273 message = XmCreateLabel (form, "message", al, ac);
1275 if (list)
1276 XtManageChild (value);
1278 i = 0;
1279 children [i] = row; i++;
1280 children [i] = separator; i++;
1281 if (text_input_slot || radio_box)
1283 children [i] = value; i++;
1285 children [i] = message; i++;
1286 children [i] = icon; i++;
1287 children [i] = icon_separator; i++;
1288 XtManageChildren (children, i);
1290 if (text_input_slot || list)
1292 XtInstallAccelerators (value, button);
1293 XtSetKeyboardFocus (result, value);
1295 else
1297 XtInstallAccelerators (form, button);
1298 XtSetKeyboardFocus (result, button);
1301 return result;
1304 static destroyed_instance*
1305 find_matching_instance (widget_instance* instance)
1307 destroyed_instance* cur;
1308 destroyed_instance* prev;
1309 char* type = instance->info->type;
1310 char* name = instance->info->name;
1312 for (prev = NULL, cur = all_destroyed_instances;
1313 cur;
1314 prev = cur, cur = cur->next)
1316 if (!strcmp (cur->name, name)
1317 && !strcmp (cur->type, type)
1318 && cur->parent == instance->parent
1319 && cur->pop_up_p == instance->pop_up_p)
1321 if (prev)
1322 prev->next = cur->next;
1323 else
1324 all_destroyed_instances = cur->next;
1325 return cur;
1327 /* do some cleanup */
1328 else if (!cur->widget)
1330 if (prev)
1331 prev->next = cur->next;
1332 else
1333 all_destroyed_instances = cur->next;
1334 free_destroyed_instance (cur);
1335 cur = prev ? prev : all_destroyed_instances;
1338 return NULL;
1341 static void
1342 mark_dead_instance_destroyed (Widget widget,
1343 XtPointer closure,
1344 XtPointer call_data)
1346 destroyed_instance* instance = (destroyed_instance*)closure;
1347 instance->widget = NULL;
1350 static void
1351 recenter_widget (Widget widget)
1353 Widget parent = XtParent (widget);
1354 Screen* screen = XtScreen (widget);
1355 Dimension screen_width = WidthOfScreen (screen);
1356 Dimension screen_height = HeightOfScreen (screen);
1357 Dimension parent_width = 0;
1358 Dimension parent_height = 0;
1359 Dimension child_width = 0;
1360 Dimension child_height = 0;
1361 Position x;
1362 Position y;
1364 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1365 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1366 NULL);
1368 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1369 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1371 XtTranslateCoords (parent, x, y, &x, &y);
1373 if (x + child_width > screen_width)
1374 x = screen_width - child_width;
1375 if (x < 0)
1376 x = 0;
1378 if (y + child_height > screen_height)
1379 y = screen_height - child_height;
1380 if (y < 0)
1381 y = 0;
1383 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1386 static Widget
1387 recycle_instance (destroyed_instance* instance)
1389 Widget widget = instance->widget;
1391 /* widget is NULL if the parent was destroyed. */
1392 if (widget)
1394 Widget focus;
1395 Widget separator;
1397 /* Remove the destroy callback as the instance is not in the list
1398 anymore */
1399 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1400 mark_dead_instance_destroyed,
1401 (XtPointer)instance);
1403 /* Give the focus to the initial item */
1404 focus = XtNameToWidget (widget, "*value");
1405 if (!focus)
1406 focus = XtNameToWidget (widget, "*button1");
1407 if (focus)
1408 XtSetKeyboardFocus (widget, focus);
1410 /* shrink the separator label back to their original size */
1411 separator = XtNameToWidget (widget, "*separator_button");
1412 if (separator)
1413 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1415 /* Center the dialog in its parent */
1416 recenter_widget (widget);
1418 free_destroyed_instance (instance);
1419 return widget;
1422 Widget
1423 xm_create_dialog (widget_instance* instance)
1425 char* name = instance->info->type;
1426 Widget parent = instance->parent;
1427 Widget widget;
1428 Boolean pop_up_p = instance->pop_up_p;
1429 char* shell_name = 0;
1430 char* icon_name = 0;
1431 Boolean text_input_slot = False;
1432 Boolean radio_box = False;
1433 Boolean list = False;
1434 int total_buttons;
1435 int left_buttons = 0;
1436 int right_buttons = 1;
1437 destroyed_instance* dead_one;
1439 /* try to find a widget to recycle */
1440 dead_one = find_matching_instance (instance);
1441 if (dead_one)
1443 Widget recycled_widget = recycle_instance (dead_one);
1444 if (recycled_widget)
1445 return recycled_widget;
1448 switch (name [0]){
1449 case 'E': case 'e':
1450 icon_name = "dbox-error";
1451 shell_name = "Error";
1452 break;
1454 case 'I': case 'i':
1455 icon_name = "dbox-info";
1456 shell_name = "Information";
1457 break;
1459 case 'L': case 'l':
1460 list = True;
1461 icon_name = "dbox-question";
1462 shell_name = "Prompt";
1463 break;
1465 case 'P': case 'p':
1466 text_input_slot = True;
1467 icon_name = "dbox-question";
1468 shell_name = "Prompt";
1469 break;
1471 case 'Q': case 'q':
1472 icon_name = "dbox-question";
1473 shell_name = "Question";
1474 break;
1477 total_buttons = name [1] - '0';
1479 if (name [3] == 'T' || name [3] == 't')
1481 text_input_slot = False;
1482 radio_box = True;
1484 else if (name [3])
1485 right_buttons = name [4] - '0';
1487 left_buttons = total_buttons - right_buttons;
1489 widget = make_dialog (name, parent, pop_up_p,
1490 shell_name, icon_name, text_input_slot, radio_box,
1491 list, left_buttons, right_buttons);
1493 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1494 (XtPointer) instance);
1496 return widget;
1499 /* Create a menu bar. We turn off the f10 key
1500 because we have not yet managed to make it work right in Motif. */
1502 static Widget
1503 make_menubar (widget_instance* instance)
1505 Arg al[3];
1506 int ac;
1508 ac = 0;
1509 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1510 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1513 static void
1514 remove_grabs (Widget shell,
1515 XtPointer closure,
1516 XtPointer call_data)
1518 Widget menu = (Widget) closure;
1519 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1522 static Widget
1523 make_popup_menu (widget_instance* instance)
1525 Widget parent = instance->parent;
1526 Window parent_window = parent->core.window;
1527 Widget result;
1529 /* sets the parent window to 0 to fool Motif into not generating a grab */
1530 parent->core.window = 0;
1531 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1532 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1533 (XtPointer)result);
1534 parent->core.window = parent_window;
1535 return result;
1538 static Widget
1539 make_main (widget_instance* instance)
1541 Widget parent = instance->parent;
1542 Widget result;
1543 Arg al[2];
1544 int ac;
1546 ac = 0;
1547 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1548 XtSetArg (al[ac], XmNspacing, 0); ac++;
1549 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1550 return result;
1553 \f/* Table of functions to create widgets */
1555 #ifdef ENERGIZE
1557 /* interface with the XDesigner generated functions */
1558 typedef Widget (*widget_maker) (Widget);
1559 extern Widget create_project_p_sheet (Widget parent);
1560 extern Widget create_debugger_p_sheet (Widget parent);
1561 extern Widget create_breaklist_p_sheet (Widget parent);
1562 extern Widget create_le_browser_p_sheet (Widget parent);
1563 extern Widget create_class_browser_p_sheet (Widget parent);
1564 extern Widget create_call_browser_p_sheet (Widget parent);
1565 extern Widget create_build_dialog (Widget parent);
1566 extern Widget create_editmode_dialog (Widget parent);
1567 extern Widget create_search_dialog (Widget parent);
1568 extern Widget create_project_display_dialog (Widget parent);
1570 static Widget
1571 make_one (widget_instance* instance, widget_maker fn)
1573 Widget result;
1574 Arg al [64];
1575 int ac = 0;
1577 if (instance->pop_up_p)
1579 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1580 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1581 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1582 (XtPointer) instance);
1583 (*fn) (result);
1585 else
1587 result = (*fn) (instance->parent);
1588 XtRealizeWidget (result);
1590 return result;
1593 static Widget
1594 make_project_p_sheet (widget_instance* instance)
1596 return make_one (instance, create_project_p_sheet);
1599 static Widget
1600 make_debugger_p_sheet (widget_instance* instance)
1602 return make_one (instance, create_debugger_p_sheet);
1605 static Widget
1606 make_breaklist_p_sheet (widget_instance* instance)
1608 return make_one (instance, create_breaklist_p_sheet);
1611 static Widget
1612 make_le_browser_p_sheet (widget_instance* instance)
1614 return make_one (instance, create_le_browser_p_sheet);
1617 static Widget
1618 make_class_browser_p_sheet (widget_instance* instance)
1620 return make_one (instance, create_class_browser_p_sheet);
1623 static Widget
1624 make_call_browser_p_sheet (widget_instance* instance)
1626 return make_one (instance, create_call_browser_p_sheet);
1629 static Widget
1630 make_build_dialog (widget_instance* instance)
1632 return make_one (instance, create_build_dialog);
1635 static Widget
1636 make_editmode_dialog (widget_instance* instance)
1638 return make_one (instance, create_editmode_dialog);
1641 static Widget
1642 make_search_dialog (widget_instance* instance)
1644 return make_one (instance, create_search_dialog);
1647 static Widget
1648 make_project_display_dialog (widget_instance* instance)
1650 return make_one (instance, create_project_display_dialog);
1653 #endif /* ENERGIZE */
1655 widget_creation_entry
1656 xm_creation_table [] =
1658 {"menubar", make_menubar},
1659 {"popup", make_popup_menu},
1660 {"main", make_main},
1661 #ifdef ENERGIZE
1662 {"project_p_sheet", make_project_p_sheet},
1663 {"debugger_p_sheet", make_debugger_p_sheet},
1664 {"breaklist_psheet", make_breaklist_p_sheet},
1665 {"leb_psheet", make_le_browser_p_sheet},
1666 {"class_browser_psheet", make_class_browser_p_sheet},
1667 {"ctree_browser_psheet", make_call_browser_p_sheet},
1668 {"build", make_build_dialog},
1669 {"editmode", make_editmode_dialog},
1670 {"search", make_search_dialog},
1671 {"project_display", make_project_display_dialog},
1672 #endif /* ENERGIZE */
1673 {NULL, NULL}
1676 \f/* Destruction of instances */
1677 void
1678 xm_destroy_instance ( widget_instance* instance)
1680 Widget widget = instance->widget;
1681 /* recycle the dialog boxes */
1682 /* Disable the recycling until we can find a way to have the dialog box
1683 get reasonable layout after we modify its contents. */
1684 if (0
1685 && XtClass (widget) == xmDialogShellWidgetClass)
1687 destroyed_instance* dead_instance =
1688 make_destroyed_instance (instance->info->name,
1689 instance->info->type,
1690 instance->widget,
1691 instance->parent,
1692 instance->pop_up_p);
1693 dead_instance->next = all_destroyed_instances;
1694 all_destroyed_instances = dead_instance;
1695 XtUnmanageChild (first_child (instance->widget));
1696 XFlush (XtDisplay (instance->widget));
1697 XtAddCallback (instance->parent, XtNdestroyCallback,
1698 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1700 else
1702 /* This might not be necessary now that the nosel is attached to
1703 popdown instead of destroy, but it can't hurt. */
1704 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1705 xm_nosel_callback, (XtPointer)instance);
1706 XtDestroyWidget (instance->widget);
1710 \f/* popup utility */
1711 void
1712 xm_popup_menu (Widget widget, XEvent *event)
1714 XButtonPressedEvent dummy;
1716 if (event == 0)
1718 dummy.type = ButtonPress;
1719 dummy.serial = 0;
1720 dummy.send_event = 0;
1721 dummy.display = XtDisplay (widget);
1722 dummy.window = XtWindow (XtParent (widget));
1723 dummy.time = 0;
1724 dummy.button = 0;
1725 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1726 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1727 &dummy.x, &dummy.y, &dummy.state);
1728 event = (XEvent *) &dummy;
1731 if (event->type == ButtonPress || event->type == ButtonRelease)
1733 /* Setting the menuPost resource only required by Motif 1.1 and
1734 LessTif 0.84 and earlier. With later versions of LessTif,
1735 setting menuPost is unnecessary and may cause problems, so
1736 don't do it. */
1737 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1739 /* This is so totally ridiculous: there's NO WAY to tell Motif
1740 that *any* button can select a menu item. Only one button
1741 can have that honor. */
1743 char *trans = 0;
1744 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1745 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1746 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1747 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1748 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1749 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1751 #endif
1753 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1756 XtManageChild (widget);
1759 static void
1760 set_min_dialog_size (Widget w)
1762 short width;
1763 short height;
1764 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1765 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1768 void
1769 xm_pop_instance (widget_instance* instance, Boolean up)
1771 Widget widget = instance->widget;
1773 if (XtClass (widget) == xmDialogShellWidgetClass)
1775 Widget widget_to_manage = first_child (widget);
1776 if (up)
1778 XtManageChild (widget_to_manage);
1779 set_min_dialog_size (widget);
1780 XtSetKeyboardFocus (instance->parent, widget);
1782 else
1783 XtUnmanageChild (widget_to_manage);
1785 else
1787 if (up)
1788 XtManageChild (widget);
1789 else
1790 XtUnmanageChild (widget);
1795 /* motif callback */
1797 static void
1798 do_call (Widget widget,
1799 XtPointer closure,
1800 enum do_call_type type)
1802 Arg al [256];
1803 int ac;
1804 XtPointer user_data;
1805 widget_instance* instance = (widget_instance*)closure;
1806 Widget instance_widget;
1807 LWLIB_ID id;
1809 if (!instance)
1810 return;
1811 if (widget->core.being_destroyed)
1812 return;
1814 instance_widget = instance->widget;
1815 if (!instance_widget)
1816 return;
1818 id = instance->info->id;
1819 ac = 0;
1820 user_data = NULL;
1821 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1822 XtGetValues (widget, al, ac);
1824 switch (type)
1826 case pre_activate:
1827 if (instance->info->pre_activate_cb)
1828 instance->info->pre_activate_cb (widget, id, user_data);
1829 break;
1831 case selection:
1832 if (instance->info->selection_cb)
1833 instance->info->selection_cb (widget, id, user_data);
1834 break;
1836 case no_selection:
1837 if (instance->info->selection_cb)
1838 instance->info->selection_cb (widget, id, (XtPointer) -1);
1839 break;
1841 case post_activate:
1842 if (instance->info->post_activate_cb)
1843 instance->info->post_activate_cb (widget, id, user_data);
1844 break;
1846 default:
1847 abort ();
1851 /* Like lw_internal_update_other_instances except that it does not do
1852 anything if its shell parent is not managed. This is to protect
1853 lw_internal_update_other_instances to dereference freed memory
1854 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1855 list */
1856 static void
1857 xm_internal_update_other_instances (Widget widget,
1858 XtPointer closure,
1859 XtPointer call_data)
1861 Widget parent;
1862 for (parent = widget; parent; parent = XtParent (parent))
1863 if (XtIsShell (parent))
1864 break;
1865 else if (!XtIsManaged (parent))
1866 return;
1867 lw_internal_update_other_instances (widget, closure, call_data);
1870 static void
1871 xm_generic_callback (Widget widget,
1872 XtPointer closure,
1873 XtPointer call_data)
1875 lw_internal_update_other_instances (widget, closure, call_data);
1876 do_call (widget, closure, selection);
1879 static void
1880 xm_nosel_callback (Widget widget,
1881 XtPointer closure,
1882 XtPointer call_data)
1884 /* This callback is only called when a dialog box is dismissed with
1885 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1886 box to be destroyed in that case, not just unmapped, so that it
1887 releases its keyboard grabs. But there are problems with running
1888 our callbacks while the widget is in the process of being
1889 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1890 XmDESTROY and then destroy it ourself after having run the
1891 callback. */
1892 do_call (widget, closure, no_selection);
1893 XtDestroyWidget (widget);
1896 static void
1897 xm_pull_down_callback (Widget widget,
1898 XtPointer closure,
1899 XtPointer call_data)
1901 Widget parent = XtParent (widget);
1903 if (XmIsRowColumn (parent))
1905 unsigned char type = 0xff;
1906 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1907 if (type == XmMENU_BAR)
1908 do_call (widget, closure, pre_activate);
1913 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1914 CLOSURE is a pointer to the widget_instance of the shell,
1916 Note that this callback is called for each cascade button in a
1917 menu, whether or not its submenu is visible. */
1919 static void
1920 xm_pop_down_callback (Widget widget,
1921 XtPointer closure,
1922 XtPointer call_data)
1924 widget_instance *instance = (widget_instance *) closure;
1926 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1927 || XtParent (widget) == instance->parent)
1928 do_call (widget, closure, post_activate);
1932 /* set the keyboard focus */
1933 void
1934 xm_set_keyboard_focus (Widget parent, Widget w)
1936 XmProcessTraversal (w, 0);
1937 XtSetKeyboardFocus (parent, w);
1940 /* Motif hack to set the main window areas. */
1941 void
1942 xm_set_main_areas (Widget parent,
1943 Widget menubar,
1944 Widget work_area)
1946 XmMainWindowSetAreas (parent,
1947 menubar, /* menubar (maybe 0) */
1948 0, /* command area (psheets) */
1949 0, /* horizontal scroll */
1950 0, /* vertical scroll */
1951 work_area); /* work area */
1954 /* Motif hack to control resizing on the menubar. */
1955 void
1956 xm_manage_resizing (Widget w, Boolean flag)
1958 XtVaSetValues (w, XtNallowShellResize, flag, NULL);