(xm_arm_callback): Don't compare widgets with `None',
[emacs.git] / lwlib / lwlib-Xm.c
blob38142d79387e73e997aef019599c8e1ee1a3f0c5
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
34 #include "lwlib-Xm.h"
35 #include "lwlib-utils.h"
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Label.h>
43 #include <Xm/List.h>
44 #include <Xm/MainW.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
48 #include <Xm/PushB.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
52 #include <Xm/Text.h>
53 #include <Xm/TextF.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
60 #include <Xm/Form.h>
62 #if defined __STDC__ || defined PROTOTYPES
63 #define P_(X) X
64 #else
65 #define P_(X) ()
66 #endif
68 enum do_call_type { pre_activate, selection, no_selection, post_activate };
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
83 Widget, Widget,
84 Boolean));
85 static void free_destroyed_instance P_ ((destroyed_instance*));
86 Widget first_child P_ ((Widget));
87 Boolean lw_motif_widget_p P_ ((Widget));
88 static XmString resource_motif_string P_ ((Widget, char *));
89 static void destroy_all_children P_ ((Widget, int));
90 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
91 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
92 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
93 widget_value *));
94 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
95 widget_value *));
96 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
98 static void make_menu_in_widget P_ ((widget_instance *, Widget,
99 widget_value *, int));
100 static void update_one_menu_entry P_ ((widget_instance *, Widget,
101 widget_value *, Boolean));
102 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
103 Boolean));
104 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
105 static void xm_update_text_field P_ ((widget_instance *, Widget,
106 widget_value *));
107 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
108 static void activate_button P_ ((Widget, XtPointer, XtPointer));
109 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
110 Boolean, Boolean, Boolean, int, int));
111 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
112 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
113 static void recenter_widget P_ ((Widget));
114 static Widget recycle_instance P_ ((destroyed_instance*));
115 Widget xm_create_dialog P_ ((widget_instance*));
116 static Widget make_menubar P_ ((widget_instance*));
117 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
118 static Widget make_popup_menu P_ ((widget_instance*));
119 static Widget make_main P_ ((widget_instance*));
120 void xm_destroy_instance P_ ((widget_instance*));
121 void xm_popup_menu P_ ((Widget, XEvent *));
122 static void set_min_dialog_size P_ ((Widget));
123 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
124 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
125 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
126 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_unmap_callback P_ ((Widget, XtPointer, XtPointer));
129 void xm_set_keyboard_focus P_ ((Widget, Widget));
130 void xm_set_main_areas P_ ((Widget, Widget, Widget));
131 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
132 XtPointer));
133 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
135 #if 0
136 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
137 Boolean));
138 void xm_pop_instance P_ ((widget_instance*, Boolean));
139 void xm_manage_resizing P_ ((Widget, Boolean));
140 #endif
143 static destroyed_instance *all_destroyed_instances = NULL;
145 static destroyed_instance*
146 make_destroyed_instance (name, type, widget, parent, pop_up_p)
147 char* name;
148 char* type;
149 Widget widget;
150 Widget parent;
151 Boolean pop_up_p;
153 destroyed_instance* instance =
154 (destroyed_instance*)malloc (sizeof (destroyed_instance));
155 instance->name = safe_strdup (name);
156 instance->type = safe_strdup (type);
157 instance->widget = widget;
158 instance->parent = parent;
159 instance->pop_up_p = pop_up_p;
160 instance->next = NULL;
161 return instance;
164 static void
165 free_destroyed_instance (instance)
166 destroyed_instance* instance;
168 free (instance->name);
169 free (instance->type);
170 free (instance);
173 \f/* motif utility functions */
174 Widget
175 first_child (widget)
176 Widget widget;
178 return ((CompositeWidget)widget)->composite.children [0];
181 Boolean
182 lw_motif_widget_p (widget)
183 Widget widget;
185 return
186 XtClass (widget) == xmDialogShellWidgetClass
187 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
190 static XmString
191 resource_motif_string (widget, name)
192 Widget widget;
193 char* name;
195 XtResource resource;
196 XmString result = 0;
198 resource.resource_name = name;
199 resource.resource_class = XmCXmString;
200 resource.resource_type = XmRXmString;
201 resource.resource_size = sizeof (XmString);
202 resource.resource_offset = 0;
203 resource.default_type = XtRImmediate;
204 resource.default_addr = 0;
206 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
207 "DialogString", &resource, 1, NULL, 0);
208 return result;
211 /* Destroy all of the children of WIDGET
212 starting with number FIRST_CHILD_TO_DESTROY. */
214 static void
215 destroy_all_children (widget, first_child_to_destroy)
216 Widget widget;
217 int first_child_to_destroy;
219 Widget* children;
220 unsigned int number;
221 int i;
223 children = XtCompositeChildren (widget, &number);
224 if (children)
226 XtUnmanageChildren (children + first_child_to_destroy,
227 number - first_child_to_destroy);
229 /* Unmanage all children and destroy them. They will only be
230 really destroyed when we get out of DispatchEvent. */
231 for (i = first_child_to_destroy; i < number; i++)
233 Arg al[2];
234 Widget submenu = 0;
235 /* Cascade buttons have submenus,and these submenus
236 need to be freed. But they are not included in
237 XtCompositeChildren. So get it out of the cascade button
238 and free it. If this child is not a cascade button,
239 then submenu should remain unchanged. */
240 XtSetArg (al[0], XmNsubMenuId, &submenu);
241 XtGetValues (children[i], al, 1);
242 if (submenu)
243 XtDestroyWidget (submenu);
244 XtDestroyWidget (children[i]);
247 XtFree ((char *) children);
253 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
254 menu. CLIENT_DATA contains a pointer to the widget_value
255 corresponding to widget W. CALL_DATA contains a
256 XmPushButtonCallbackStruct containing the reason why the callback
257 is called. */
259 static void
260 xm_arm_callback (w, client_data, call_data)
261 Widget w;
262 XtPointer client_data, call_data;
264 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
265 widget_value *wv = (widget_value *) client_data;
266 widget_instance *instance;
268 /* Get the id of the menu bar or popup menu this widget is in. */
269 while (w != NULL)
271 if (XmIsRowColumn (w))
273 unsigned char type = 0xff;
275 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
276 if (type == XmMENU_BAR || type == XmMENU_POPUP)
277 break;
280 w = XtParent (w);
283 if (w != NULL)
285 instance = lw_get_widget_instance (w);
286 if (instance && instance->info->highlight_cb)
288 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
289 instance->info->highlight_cb (w, instance->info->id, call_data);
296 /* Update the label of widget WIDGET. WIDGET must be a Label widget
297 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
298 the value to update.
300 Menus:
302 Emacs fills VAL->name with the text to display in the menu, and
303 sets VAL->value to null. Function make_menu_in_widget creates
304 widgets with VAL->name as resource name. This works because the
305 Label widget uses its resource name for display if no
306 XmNlabelString is set.
308 Dialogs:
310 VAL->name is again set to the resource name, but VAL->value is
311 not null, and contains the label string to display. */
313 static void
314 xm_update_label (instance, widget, val)
315 widget_instance* instance;
316 Widget widget;
317 widget_value* val;
319 XmString res_string = 0;
320 XmString built_string = 0;
321 XmString key_string = 0;
322 Arg al [256];
323 int ac;
325 ac = 0;
327 if (val->value)
329 /* A label string is specified, i.e. we are in a dialog. First
330 see if it is overridden by something from the resource file. */
331 res_string = resource_motif_string (widget, val->value);
333 if (res_string)
335 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
337 else
339 built_string =
340 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
341 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
344 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
347 if (val->key)
349 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
350 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
353 if (ac)
354 XtSetValues (widget, al, ac);
356 if (built_string)
357 XmStringFree (built_string);
359 if (key_string)
360 XmStringFree (key_string);
363 \f/* update of list */
364 static void
365 xm_update_list (instance, widget, val)
366 widget_instance* instance;
367 Widget widget;
368 widget_value* val;
370 widget_value* cur;
371 int i;
372 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
373 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
374 instance);
375 for (cur = val->contents, i = 0; cur; cur = cur->next)
376 if (cur->value)
378 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
379 i += 1;
380 XmListAddItem (widget, xmstr, 0);
381 if (cur->selected)
382 XmListSelectPos (widget, i, False);
383 XmStringFree (xmstr);
387 \f/* update of buttons */
388 static void
389 xm_update_pushbutton (instance, widget, val)
390 widget_instance* instance;
391 Widget widget;
392 widget_value* val;
394 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
395 XtRemoveAllCallbacks (widget, XmNactivateCallback);
396 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
399 static void
400 xm_update_cascadebutton (instance, widget, val)
401 widget_instance* instance;
402 Widget widget;
403 widget_value* val;
405 /* Should also rebuild the menu by calling ...update_menu... */
406 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
407 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
408 instance);
411 \f/* update toggle and radiobox */
412 static void
413 xm_update_toggle (instance, widget, val)
414 widget_instance* instance;
415 Widget widget;
416 widget_value* val;
418 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
419 XtAddCallback (widget, XmNvalueChangedCallback,
420 xm_generic_callback, instance);
421 XtVaSetValues (widget, XmNset, val->selected,
422 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
425 static void
426 xm_update_radiobox (instance, widget, val)
427 widget_instance* instance;
428 Widget widget;
429 widget_value* val;
432 Widget toggle;
433 widget_value* cur;
435 /* update the callback */
436 XtRemoveAllCallbacks (widget, XmNentryCallback);
437 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
439 /* first update all the toggles */
440 /* Energize kernel interface is currently bad. It sets the selected widget
441 with the selected flag but returns it by its name. So we currently
442 have to support both setting the selection with the selected slot
443 of val contents and setting it with the "value" slot of val. The latter
444 has a higher priority. This to be removed when the kernel is fixed. */
445 for (cur = val->contents; cur; cur = cur->next)
447 toggle = XtNameToWidget (widget, cur->value);
448 if (toggle)
450 XtSetSensitive (toggle, cur->enabled);
451 if (!val->value && cur->selected)
452 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
453 if (val->value && strcmp (val->value, cur->value))
454 XtVaSetValues (toggle, XmNset, False, NULL);
458 /* The selected was specified by the value slot */
459 if (val->value)
461 toggle = XtNameToWidget (widget, val->value);
462 if (toggle)
463 XtVaSetValues (toggle, XmNset, True, NULL);
468 /* update a popup menu, pulldown menu or a menubar */
470 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
472 static void
473 make_menu_in_widget (instance, widget, val, keep_first_children)
474 widget_instance* instance;
475 Widget widget;
476 widget_value* val;
477 int keep_first_children;
479 Widget* children = 0;
480 int num_children;
481 int child_index;
482 widget_value* cur;
483 Widget button = 0;
484 Widget title = 0;
485 Widget menu;
486 Arg al [256];
487 int ac;
488 Boolean menubar_p;
489 unsigned char type;
491 Widget* old_children;
492 unsigned int old_num_children;
494 old_children = XtCompositeChildren (widget, &old_num_children);
496 /* Allocate the children array */
497 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
498 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
500 /* WIDGET should be a RowColumn. */
501 if (!XmIsRowColumn (widget))
502 abort ();
504 /* Determine whether WIDGET is a menu bar. */
505 type = -1;
506 XtSetArg (al[0], XmNrowColumnType, &type);
507 XtGetValues (widget, al, 1);
508 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
509 abort ();
510 menubar_p = type == XmMENU_BAR;
512 #if 0 /* This can't be used in LessTif as of 2000-01-24 because it's
513 impossible to decide from this plus the cascading callback if a
514 popup is still posted or not. When selecting cascade button A,
515 then B, then clicking on the frame, the sequence of callbacks is
516 `cascading A', cascading B', `popdown for all cascade buttons in
517 the menu bar. */
518 /* Add a callback to popups and pulldowns that is called when
519 it is made invisible again. */
520 if (!menubar_p)
521 XtAddCallback (XtParent (widget), XmNpopdownCallback,
522 xm_pop_down_callback, (XtPointer)instance);
523 #endif
525 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
526 for (child_index = 0, cur = val; child_index < keep_first_children;
527 child_index++, cur = cur->next)
528 children[child_index] = old_children[child_index];
530 /* Check that those are all we have
531 (the caller should have deleted the rest). */
532 if (old_num_children != keep_first_children)
533 abort ();
535 /* Create the rest. */
536 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
538 enum menu_separator separator;
540 ac = 0;
541 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
542 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
543 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
545 if (instance->pop_up_p && !cur->contents && !cur->call_data
546 && !lw_separator_p (cur->name, &separator, 1))
548 ac = 0;
549 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
550 title = button = XmCreateLabel (widget, cur->name, al, ac);
552 else if (lw_separator_p (cur->name, &separator, 1))
554 ac = 0;
555 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
556 button = XmCreateSeparator (widget, cur->name, al, ac);
558 else if (!cur->contents)
560 if (menubar_p)
561 button = XmCreateCascadeButton (widget, cur->name, al, ac);
562 else if (!cur->call_data)
563 button = XmCreateLabel (widget, cur->name, al, ac);
564 else if (cur->button_type == BUTTON_TYPE_TOGGLE
565 || cur->button_type == BUTTON_TYPE_RADIO)
567 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
568 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
569 XtSetArg (al[ac], XmNindicatorType,
570 (cur->button_type == BUTTON_TYPE_TOGGLE
571 ? XmN_OF_MANY : XmONE_OF_MANY));
572 ++ac;
573 button = XmCreateToggleButton (widget, cur->name, al, ac);
574 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
575 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
577 else
579 button = XmCreatePushButton (widget, cur->name, al, ac);
580 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
581 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
584 xm_update_label (instance, button, cur);
586 /* Add a callback that is called when the button is
587 selected. Toggle buttons don't support
588 XmNactivateCallback, we use XmNvalueChangedCallback in
589 that case. Don't add a callback to a simple label. */
590 if (cur->button_type)
591 xm_update_toggle (instance, button, cur);
592 else if (cur->call_data)
593 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
594 (XtPointer)instance);
596 else
598 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
600 /* XmNpopdownCallback is working strangely under LessTif.
601 Using XmNunmapCallback is the only way to go there. */
602 if (menubar_p)
603 XtAddCallback (menu, XmNunmapCallback, xm_unmap_callback,
604 (XtPointer) instance);
606 make_menu_in_widget (instance, menu, cur->contents, 0);
607 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
608 button = XmCreateCascadeButton (widget, cur->name, al, ac);
610 xm_update_label (instance, button, cur);
612 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
613 (XtPointer)instance);
616 children[child_index] = button;
619 /* Last entry is the help button. The original comment read "Has to
620 be done after managing the buttons otherwise the menubar is only
621 4 pixels high." This is no longer true, and to make
622 XmNmenuHelpWidget work, we need to set it before managing the
623 children.. --gerd. */
624 if (button)
625 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
627 /* LessTif apparently doesn't recompute centered text when more
628 widgets are added. So, do it after all widgets have been
629 created. */
630 if (title)
631 XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, 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 (instance, widget, val, deep_p)
643 widget_instance* instance;
644 Widget widget;
645 widget_value* val;
646 Boolean deep_p;
648 Arg al [256];
649 int ac;
650 Widget menu;
651 widget_value* contents;
653 if (val->this_one_change == NO_CHANGE)
654 return;
656 /* update the sensitivity and userdata */
657 /* Common to all widget types */
658 XtSetSensitive (widget, val->enabled);
659 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
661 /* update the menu button as a label. */
662 if (val->this_one_change >= VISIBLE_CHANGE)
664 xm_update_label (instance, widget, val);
665 if (val->button_type)
666 xm_update_toggle (instance, widget, val);
669 /* update the pulldown/pullaside as needed */
670 ac = 0;
671 menu = NULL;
672 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
673 XtGetValues (widget, al, ac);
675 contents = val->contents;
677 if (!menu)
679 if (contents)
681 unsigned int old_num_children, i;
682 Widget parent;
683 Widget *widget_list;
685 parent = XtParent (widget);
686 widget_list = XtCompositeChildren (parent, &old_num_children);
688 /* Find the widget position within the parent's widget list. */
689 for (i = 0; i < old_num_children; i++)
690 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
691 break;
692 if (i == old_num_children)
693 abort ();
694 if (XmIsCascadeButton (widget_list[i]))
696 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
697 make_menu_in_widget (instance, menu, contents, 0);
698 ac = 0;
699 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
700 XtSetValues (widget, al, ac);
702 else
704 Widget button;
706 /* The current menuitem is a XmPushButtonGadget, it
707 needs to be replaced by a CascadeButtonGadget */
708 XtDestroyWidget (widget_list[i]);
709 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
710 make_menu_in_widget (instance, menu, contents, 0);
711 ac = 0;
712 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
713 /* Non-zero values don't work reliably in
714 conjunction with Emacs' event loop */
715 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
716 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
717 /* Tell Motif to put it in the right place */
718 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
719 #endif
720 button = XmCreateCascadeButton (parent, val->name, al, ac);
721 xm_update_label (instance, button, val);
723 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
724 (XtPointer)instance);
725 XtManageChild (button);
729 else if (!contents)
731 ac = 0;
732 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
733 XtSetValues (widget, al, ac);
734 XtDestroyWidget (menu);
736 else if (deep_p && contents->change != NO_CHANGE)
737 xm_update_menu (instance, menu, val, 1);
740 static void
741 xm_update_menu (instance, widget, val, deep_p)
742 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->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 (instance, widget, val)
817 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 (instance, widget, val)
831 widget_instance* instance;
832 Widget widget;
833 widget_value* val;
835 XmTextFieldSetString (widget, val->value ? val->value : "");
836 XtRemoveAllCallbacks (widget, XmNactivateCallback);
837 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
838 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
839 XtAddCallback (widget, XmNvalueChangedCallback,
840 xm_internal_update_other_instances, instance);
844 /* update a motif widget */
846 void
847 xm_update_one_widget (instance, widget, val, deep_p)
848 widget_instance* instance;
849 Widget widget;
850 widget_value* val;
851 Boolean deep_p;
853 WidgetClass class;
855 /* Mark as not edited */
856 val->edited = False;
858 /* Common to all widget types */
859 XtSetSensitive (widget, val->enabled);
860 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
862 /* Common to all label like widgets */
863 if (XtIsSubclass (widget, xmLabelWidgetClass))
864 xm_update_label (instance, widget, val);
866 class = XtClass (widget);
867 /* Class specific things */
868 if (class == xmPushButtonWidgetClass ||
869 class == xmArrowButtonWidgetClass)
871 xm_update_pushbutton (instance, widget, val);
873 else if (class == xmCascadeButtonWidgetClass)
875 xm_update_cascadebutton (instance, widget, val);
877 else if (class == xmToggleButtonWidgetClass
878 || class == xmToggleButtonGadgetClass)
880 xm_update_toggle (instance, widget, val);
882 else if (class == xmRowColumnWidgetClass)
884 Boolean radiobox = 0;
885 int ac = 0;
886 Arg al [1];
888 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
889 XtGetValues (widget, al, ac);
891 if (radiobox)
892 xm_update_radiobox (instance, widget, val);
893 else
894 xm_update_menu (instance, widget, val, deep_p);
896 else if (class == xmTextWidgetClass)
898 xm_update_text (instance, widget, val);
900 else if (class == xmTextFieldWidgetClass)
902 xm_update_text_field (instance, widget, val);
904 else if (class == xmListWidgetClass)
906 xm_update_list (instance, widget, val);
910 \f/* getting the value back */
911 void
912 xm_update_one_value (instance, widget, val)
913 widget_instance* instance;
914 Widget widget;
915 widget_value* val;
917 WidgetClass class = XtClass (widget);
918 widget_value *old_wv;
920 /* copy the call_data slot into the "return" widget_value */
921 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
922 if (!strcmp (val->name, old_wv->name))
924 val->call_data = old_wv->call_data;
925 break;
928 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
930 XtVaGetValues (widget, XmNset, &val->selected, NULL);
931 val->edited = True;
933 else if (class == xmTextWidgetClass)
935 if (val->value)
936 free (val->value);
937 val->value = XmTextGetString (widget);
938 val->edited = True;
940 else if (class == xmTextFieldWidgetClass)
942 if (val->value)
943 free (val->value);
944 val->value = XmTextFieldGetString (widget);
945 val->edited = True;
947 else if (class == xmRowColumnWidgetClass)
949 Boolean radiobox = 0;
950 int ac = 0;
951 Arg al [1];
953 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
954 XtGetValues (widget, al, ac);
956 if (radiobox)
958 CompositeWidget radio = (CompositeWidget)widget;
959 int i;
960 for (i = 0; i < radio->composite.num_children; i++)
962 int set = False;
963 Widget toggle = radio->composite.children [i];
965 XtVaGetValues (toggle, XmNset, &set, NULL);
966 if (set)
968 if (val->value)
969 free (val->value);
970 val->value = safe_strdup (XtName (toggle));
973 val->edited = True;
976 else if (class == xmListWidgetClass)
978 int pos_cnt;
979 int* pos_list;
980 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
982 int i;
983 widget_value* cur;
984 for (cur = val->contents, i = 0; cur; cur = cur->next)
985 if (cur->value)
987 int j;
988 cur->selected = False;
989 i += 1;
990 for (j = 0; j < pos_cnt; j++)
991 if (pos_list [j] == i)
993 cur->selected = True;
994 val->value = safe_strdup (cur->name);
997 val->edited = 1;
998 XtFree ((char *) pos_list);
1004 /* This function is for activating a button from a program. It's wrong because
1005 we pass a NULL argument in the call_data which is not Motif compatible.
1006 This is used from the XmNdefaultAction callback of the List widgets to
1007 have a double-click put down a dialog box like the button would do.
1008 I could not find a way to do that with accelerators.
1010 static void
1011 activate_button (widget, closure, call_data)
1012 Widget widget;
1013 XtPointer closure;
1014 XtPointer call_data;
1016 Widget button = (Widget)closure;
1017 XtCallCallbacks (button, XmNactivateCallback, NULL);
1020 /* creation functions */
1022 /* dialogs */
1023 static Widget
1024 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1025 radio_box, list, left_buttons, right_buttons)
1026 char* name;
1027 Widget parent;
1028 Boolean pop_up_p;
1029 char* shell_title;
1030 char* icon_name;
1031 Boolean text_input_slot;
1032 Boolean radio_box;
1033 Boolean list;
1034 int left_buttons;
1035 int right_buttons;
1037 Widget result;
1038 Widget form;
1039 Widget row;
1040 Widget icon;
1041 Widget icon_separator;
1042 Widget message;
1043 Widget value = 0;
1044 Widget separator;
1045 Widget button = 0;
1046 Widget children [16]; /* for the final XtManageChildren */
1047 int n_children;
1048 Arg al[64]; /* Arg List */
1049 int ac; /* Arg Count */
1050 int i;
1052 if (pop_up_p)
1054 ac = 0;
1055 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1056 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1057 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1058 result = XmCreateDialogShell (parent, "dialog", al, ac);
1059 ac = 0;
1060 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1061 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1062 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1063 form = XmCreateForm (result, shell_title, al, ac);
1065 else
1067 ac = 0;
1068 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1069 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1070 form = XmCreateForm (parent, shell_title, al, ac);
1071 result = form;
1074 n_children = left_buttons + right_buttons + 1;
1075 ac = 0;
1076 XtSetArg(al[ac], XmNpacking, n_children == 3?
1077 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1078 XtSetArg(al[ac], XmNorientation, n_children == 3?
1079 XmVERTICAL: XmHORIZONTAL); ac++;
1080 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1081 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1082 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1083 XtSetArg(al[ac], XmNspacing, 13); ac++;
1084 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1085 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1086 XtSetArg(al[ac], XmNisAligned, True); ac++;
1087 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1088 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1089 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1090 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1091 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1092 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1093 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1094 row = XmCreateRowColumn (form, "row", al, ac);
1096 n_children = 0;
1097 for (i = 0; i < left_buttons; i++)
1099 char button_name [16];
1100 sprintf (button_name, "button%d", i + 1);
1101 ac = 0;
1102 if (i == 0)
1104 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1105 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1107 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1108 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1109 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1111 if (i == 0)
1113 button = children [n_children];
1114 ac = 0;
1115 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1116 XtSetValues (row, al, ac);
1119 n_children++;
1122 /* invisible separator button */
1123 ac = 0;
1124 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1125 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1126 n_children++;
1128 for (i = 0; i < right_buttons; i++)
1130 char button_name [16];
1131 sprintf (button_name, "button%d", left_buttons + i + 1);
1132 ac = 0;
1133 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1134 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1135 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1136 if (! button) button = children [n_children];
1137 n_children++;
1140 XtManageChildren (children, n_children);
1142 ac = 0;
1143 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1144 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1145 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1146 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1147 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1148 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1149 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1150 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1151 separator = XmCreateSeparator (form, "", al, ac);
1153 ac = 0;
1154 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1155 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1156 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1157 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1158 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1159 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1160 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1161 icon = XmCreateLabel (form, icon_name, al, ac);
1163 ac = 0;
1164 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1165 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1166 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1167 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1168 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1169 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1170 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1171 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1172 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1173 icon_separator = XmCreateLabel (form, "", al, ac);
1175 if (text_input_slot)
1177 ac = 0;
1178 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1179 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1180 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1181 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1182 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1183 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1184 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1185 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1186 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1187 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1188 value = XmCreateTextField (form, "value", al, ac);
1190 else if (radio_box)
1192 Widget radio_butt;
1193 ac = 0;
1194 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1195 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1196 XtSetArg(al[ac], XmNspacing, 13); ac++;
1197 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1198 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1199 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1200 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1201 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1202 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1203 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1204 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1205 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1206 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1207 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1208 ac = 0;
1209 i = 0;
1210 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1211 children [i++] = radio_butt;
1212 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1213 children [i++] = radio_butt;
1214 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1215 children [i++] = radio_butt;
1216 XtManageChildren (children, i);
1218 else if (list)
1220 ac = 0;
1221 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1222 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1223 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1224 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1225 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1226 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1227 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1228 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1229 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1230 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1231 value = XmCreateScrolledList (form, "list", al, ac);
1233 /* this is the easiest way I found to have the dble click in the
1234 list activate the default button */
1235 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1238 ac = 0;
1239 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1240 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1241 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1242 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1243 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1244 XtSetArg(al[ac], XmNbottomWidget,
1245 text_input_slot || radio_box || list ? value : separator); ac++;
1246 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1247 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1248 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1249 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1250 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1251 message = XmCreateLabel (form, "message", al, ac);
1253 if (list)
1254 XtManageChild (value);
1256 i = 0;
1257 children [i] = row; i++;
1258 children [i] = separator; i++;
1259 if (text_input_slot || radio_box)
1261 children [i] = value; i++;
1263 children [i] = message; i++;
1264 children [i] = icon; i++;
1265 children [i] = icon_separator; i++;
1266 XtManageChildren (children, i);
1268 if (text_input_slot || list)
1270 XtInstallAccelerators (value, button);
1271 XtSetKeyboardFocus (result, value);
1273 else
1275 XtInstallAccelerators (form, button);
1276 XtSetKeyboardFocus (result, button);
1279 return result;
1282 static destroyed_instance*
1283 find_matching_instance (instance)
1284 widget_instance* instance;
1286 destroyed_instance* cur;
1287 destroyed_instance* prev;
1288 char* type = instance->info->type;
1289 char* name = instance->info->name;
1291 for (prev = NULL, cur = all_destroyed_instances;
1292 cur;
1293 prev = cur, cur = cur->next)
1295 if (!strcmp (cur->name, name)
1296 && !strcmp (cur->type, type)
1297 && cur->parent == instance->parent
1298 && cur->pop_up_p == instance->pop_up_p)
1300 if (prev)
1301 prev->next = cur->next;
1302 else
1303 all_destroyed_instances = cur->next;
1304 return cur;
1306 /* do some cleanup */
1307 else if (!cur->widget)
1309 if (prev)
1310 prev->next = cur->next;
1311 else
1312 all_destroyed_instances = cur->next;
1313 free_destroyed_instance (cur);
1314 cur = prev ? prev : all_destroyed_instances;
1317 return NULL;
1320 static void
1321 mark_dead_instance_destroyed (widget, closure, call_data)
1322 Widget widget;
1323 XtPointer closure;
1324 XtPointer call_data;
1326 destroyed_instance* instance = (destroyed_instance*)closure;
1327 instance->widget = NULL;
1330 static void
1331 recenter_widget (widget)
1332 Widget widget;
1334 Widget parent = XtParent (widget);
1335 Screen* screen = XtScreen (widget);
1336 Dimension screen_width = WidthOfScreen (screen);
1337 Dimension screen_height = HeightOfScreen (screen);
1338 Dimension parent_width = 0;
1339 Dimension parent_height = 0;
1340 Dimension child_width = 0;
1341 Dimension child_height = 0;
1342 Position x;
1343 Position y;
1345 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1346 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1347 NULL);
1349 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1350 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1352 XtTranslateCoords (parent, x, y, &x, &y);
1354 if (x + child_width > screen_width)
1355 x = screen_width - child_width;
1356 if (x < 0)
1357 x = 0;
1359 if (y + child_height > screen_height)
1360 y = screen_height - child_height;
1361 if (y < 0)
1362 y = 0;
1364 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1367 static Widget
1368 recycle_instance (instance)
1369 destroyed_instance* instance;
1371 Widget widget = instance->widget;
1373 /* widget is NULL if the parent was destroyed. */
1374 if (widget)
1376 Widget focus;
1377 Widget separator;
1379 /* Remove the destroy callback as the instance is not in the list
1380 anymore */
1381 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1382 mark_dead_instance_destroyed,
1383 (XtPointer)instance);
1385 /* Give the focus to the initial item */
1386 focus = XtNameToWidget (widget, "*value");
1387 if (!focus)
1388 focus = XtNameToWidget (widget, "*button1");
1389 if (focus)
1390 XtSetKeyboardFocus (widget, focus);
1392 /* shrink the separator label back to their original size */
1393 separator = XtNameToWidget (widget, "*separator_button");
1394 if (separator)
1395 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1397 /* Center the dialog in its parent */
1398 recenter_widget (widget);
1400 free_destroyed_instance (instance);
1401 return widget;
1404 Widget
1405 xm_create_dialog (instance)
1406 widget_instance* instance;
1408 char* name = instance->info->type;
1409 Widget parent = instance->parent;
1410 Widget widget;
1411 Boolean pop_up_p = instance->pop_up_p;
1412 char* shell_name = 0;
1413 char* icon_name = 0;
1414 Boolean text_input_slot = False;
1415 Boolean radio_box = False;
1416 Boolean list = False;
1417 int total_buttons;
1418 int left_buttons = 0;
1419 int right_buttons = 1;
1420 destroyed_instance* dead_one;
1422 /* try to find a widget to recycle */
1423 dead_one = find_matching_instance (instance);
1424 if (dead_one)
1426 Widget recycled_widget = recycle_instance (dead_one);
1427 if (recycled_widget)
1428 return recycled_widget;
1431 switch (name [0]){
1432 case 'E': case 'e':
1433 icon_name = "dbox-error";
1434 shell_name = "Error";
1435 break;
1437 case 'I': case 'i':
1438 icon_name = "dbox-info";
1439 shell_name = "Information";
1440 break;
1442 case 'L': case 'l':
1443 list = True;
1444 icon_name = "dbox-question";
1445 shell_name = "Prompt";
1446 break;
1448 case 'P': case 'p':
1449 text_input_slot = True;
1450 icon_name = "dbox-question";
1451 shell_name = "Prompt";
1452 break;
1454 case 'Q': case 'q':
1455 icon_name = "dbox-question";
1456 shell_name = "Question";
1457 break;
1460 total_buttons = name [1] - '0';
1462 if (name [3] == 'T' || name [3] == 't')
1464 text_input_slot = False;
1465 radio_box = True;
1467 else if (name [3])
1468 right_buttons = name [4] - '0';
1470 left_buttons = total_buttons - right_buttons;
1472 widget = make_dialog (name, parent, pop_up_p,
1473 shell_name, icon_name, text_input_slot, radio_box,
1474 list, left_buttons, right_buttons);
1476 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1477 (XtPointer) instance);
1478 return widget;
1481 /* Create a menu bar. We turn off the f10 key
1482 because we have not yet managed to make it work right in Motif. */
1484 static Widget
1485 make_menubar (instance)
1486 widget_instance* instance;
1488 Arg al[3];
1489 int ac;
1491 ac = 0;
1492 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1494 #if 0
1495 /* As of 2000-01-17, the LessTif menu bar resizes to height 0 when
1496 all its children are removed, causing an annoying flickering
1497 behavior. Prevent that by not allowing resizing. */
1498 XtSetArg(al[ac], XmNresizeHeight, False); ++ac;
1499 XtSetArg(al[ac], XmNresizeWidth, False); ++ac;
1500 #endif
1502 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1505 static void
1506 remove_grabs (shell, closure, call_data)
1507 Widget shell;
1508 XtPointer closure;
1509 XtPointer call_data;
1511 Widget menu = (Widget) closure;
1512 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1515 static Widget
1516 make_popup_menu (instance)
1517 widget_instance* instance;
1519 Widget parent = instance->parent;
1520 Window parent_window = parent->core.window;
1521 Widget result;
1523 /* sets the parent window to 0 to fool Motif into not generating a grab */
1524 parent->core.window = 0;
1525 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1526 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1527 (XtPointer)result);
1528 parent->core.window = parent_window;
1529 return result;
1532 static Widget
1533 make_main (instance)
1534 widget_instance* instance;
1536 Widget parent = instance->parent;
1537 Widget result;
1538 Arg al[2];
1539 int ac;
1541 ac = 0;
1542 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1543 XtSetArg (al[ac], XmNspacing, 0); ac++;
1544 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1545 return result;
1548 \f/* Table of functions to create widgets */
1550 #ifdef ENERGIZE
1552 /* interface with the XDesigner generated functions */
1553 typedef Widget (*widget_maker) (Widget);
1554 extern Widget create_project_p_sheet (Widget parent);
1555 extern Widget create_debugger_p_sheet (Widget parent);
1556 extern Widget create_breaklist_p_sheet (Widget parent);
1557 extern Widget create_le_browser_p_sheet (Widget parent);
1558 extern Widget create_class_browser_p_sheet (Widget parent);
1559 extern Widget create_call_browser_p_sheet (Widget parent);
1560 extern Widget create_build_dialog (Widget parent);
1561 extern Widget create_editmode_dialog (Widget parent);
1562 extern Widget create_search_dialog (Widget parent);
1563 extern Widget create_project_display_dialog (Widget parent);
1565 static Widget
1566 make_one (widget_instance* instance, widget_maker fn)
1568 Widget result;
1569 Arg al [64];
1570 int ac = 0;
1572 if (instance->pop_up_p)
1574 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1575 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1576 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1577 (XtPointer) instance);
1578 (*fn) (result);
1580 else
1582 result = (*fn) (instance->parent);
1583 XtRealizeWidget (result);
1585 return result;
1588 static Widget
1589 make_project_p_sheet (widget_instance* instance)
1591 return make_one (instance, create_project_p_sheet);
1594 static Widget
1595 make_debugger_p_sheet (widget_instance* instance)
1597 return make_one (instance, create_debugger_p_sheet);
1600 static Widget
1601 make_breaklist_p_sheet (widget_instance* instance)
1603 return make_one (instance, create_breaklist_p_sheet);
1606 static Widget
1607 make_le_browser_p_sheet (widget_instance* instance)
1609 return make_one (instance, create_le_browser_p_sheet);
1612 static Widget
1613 make_class_browser_p_sheet (widget_instance* instance)
1615 return make_one (instance, create_class_browser_p_sheet);
1618 static Widget
1619 make_call_browser_p_sheet (widget_instance* instance)
1621 return make_one (instance, create_call_browser_p_sheet);
1624 static Widget
1625 make_build_dialog (widget_instance* instance)
1627 return make_one (instance, create_build_dialog);
1630 static Widget
1631 make_editmode_dialog (widget_instance* instance)
1633 return make_one (instance, create_editmode_dialog);
1636 static Widget
1637 make_search_dialog (widget_instance* instance)
1639 return make_one (instance, create_search_dialog);
1642 static Widget
1643 make_project_display_dialog (widget_instance* instance)
1645 return make_one (instance, create_project_display_dialog);
1648 #endif /* ENERGIZE */
1650 widget_creation_entry
1651 xm_creation_table [] =
1653 {"menubar", make_menubar},
1654 {"popup", make_popup_menu},
1655 {"main", make_main},
1656 #ifdef ENERGIZE
1657 {"project_p_sheet", make_project_p_sheet},
1658 {"debugger_p_sheet", make_debugger_p_sheet},
1659 {"breaklist_psheet", make_breaklist_p_sheet},
1660 {"leb_psheet", make_le_browser_p_sheet},
1661 {"class_browser_psheet", make_class_browser_p_sheet},
1662 {"ctree_browser_psheet", make_call_browser_p_sheet},
1663 {"build", make_build_dialog},
1664 {"editmode", make_editmode_dialog},
1665 {"search", make_search_dialog},
1666 {"project_display", make_project_display_dialog},
1667 #endif /* ENERGIZE */
1668 {NULL, NULL}
1671 \f/* Destruction of instances */
1672 void
1673 xm_destroy_instance (instance)
1674 widget_instance* instance;
1676 Widget widget = instance->widget;
1677 /* recycle the dialog boxes */
1678 /* Disable the recycling until we can find a way to have the dialog box
1679 get reasonable layout after we modify its contents. */
1680 if (0
1681 && XtClass (widget) == xmDialogShellWidgetClass)
1683 destroyed_instance* dead_instance =
1684 make_destroyed_instance (instance->info->name,
1685 instance->info->type,
1686 instance->widget,
1687 instance->parent,
1688 instance->pop_up_p);
1689 dead_instance->next = all_destroyed_instances;
1690 all_destroyed_instances = dead_instance;
1691 XtUnmanageChild (first_child (instance->widget));
1692 XFlush (XtDisplay (instance->widget));
1693 XtAddCallback (instance->parent, XtNdestroyCallback,
1694 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1696 else
1698 /* This might not be necessary now that the nosel is attached to
1699 popdown instead of destroy, but it can't hurt. */
1700 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1701 xm_nosel_callback, (XtPointer)instance);
1702 XtDestroyWidget (instance->widget);
1706 \f/* popup utility */
1707 void
1708 xm_popup_menu (widget, event)
1709 Widget widget;
1710 XEvent *event;
1712 XButtonPressedEvent dummy;
1714 if (event == 0)
1716 dummy.type = ButtonPress;
1717 dummy.serial = 0;
1718 dummy.send_event = 0;
1719 dummy.display = XtDisplay (widget);
1720 dummy.window = XtWindow (XtParent (widget));
1721 dummy.time = 0;
1722 dummy.button = 0;
1723 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1724 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1725 &dummy.x, &dummy.y, &dummy.state);
1726 event = (XEvent *) &dummy;
1729 if (event->type == ButtonPress || event->type == ButtonRelease)
1731 /* This is so totally ridiculous: there's NO WAY to tell Motif
1732 that *any* button can select a menu item. Only one button
1733 can have that honor.
1735 char *trans = 0;
1736 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1737 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1738 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1739 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1740 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1741 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1742 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1744 XtManageChild (widget);
1747 static void
1748 set_min_dialog_size (w)
1749 Widget w;
1751 short width;
1752 short height;
1753 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1754 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1757 void
1758 xm_pop_instance (instance, up)
1759 widget_instance* instance;
1760 Boolean up;
1762 Widget widget = instance->widget;
1764 if (XtClass (widget) == xmDialogShellWidgetClass)
1766 Widget widget_to_manage = first_child (widget);
1767 if (up)
1769 XtManageChild (widget_to_manage);
1770 set_min_dialog_size (widget);
1771 XtSetKeyboardFocus (instance->parent, widget);
1773 else
1774 XtUnmanageChild (widget_to_manage);
1776 else
1778 if (up)
1779 XtManageChild (widget);
1780 else
1781 XtUnmanageChild (widget);
1786 /* motif callback */
1788 static void
1789 do_call (widget, closure, type)
1790 Widget widget;
1791 XtPointer closure;
1792 enum do_call_type type;
1794 Arg al [256];
1795 int ac;
1796 XtPointer user_data;
1797 widget_instance* instance = (widget_instance*)closure;
1798 Widget instance_widget;
1799 LWLIB_ID id;
1801 if (!instance)
1802 return;
1803 if (widget->core.being_destroyed)
1804 return;
1806 instance_widget = instance->widget;
1807 if (!instance_widget)
1808 return;
1810 id = instance->info->id;
1811 ac = 0;
1812 user_data = NULL;
1813 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1814 XtGetValues (widget, al, ac);
1815 switch (type)
1817 case pre_activate:
1818 if (instance->info->pre_activate_cb)
1819 instance->info->pre_activate_cb (widget, id, user_data);
1820 break;
1821 case selection:
1822 if (instance->info->selection_cb)
1823 instance->info->selection_cb (widget, id, user_data);
1824 break;
1825 case no_selection:
1826 if (instance->info->selection_cb)
1827 instance->info->selection_cb (widget, id, (XtPointer) -1);
1828 break;
1829 case post_activate:
1830 if (instance->info->post_activate_cb)
1831 instance->info->post_activate_cb (widget, id, user_data);
1832 break;
1833 default:
1834 abort ();
1838 /* Like lw_internal_update_other_instances except that it does not do
1839 anything if its shell parent is not managed. This is to protect
1840 lw_internal_update_other_instances to dereference freed memory
1841 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1842 list */
1843 static void
1844 xm_internal_update_other_instances (widget, closure, call_data)
1845 Widget widget;
1846 XtPointer closure;
1847 XtPointer call_data;
1849 Widget parent;
1850 for (parent = widget; parent; parent = XtParent (parent))
1851 if (XtIsShell (parent))
1852 break;
1853 else if (!XtIsManaged (parent))
1854 return;
1855 lw_internal_update_other_instances (widget, closure, call_data);
1858 static void
1859 xm_generic_callback (widget, closure, call_data)
1860 Widget widget;
1861 XtPointer closure;
1862 XtPointer call_data;
1864 lw_internal_update_other_instances (widget, closure, call_data);
1865 do_call (widget, closure, selection);
1868 static void
1869 xm_nosel_callback (widget, closure, call_data)
1870 Widget widget;
1871 XtPointer closure;
1872 XtPointer call_data;
1874 /* This callback is only called when a dialog box is dismissed with the wm's
1875 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1876 in that case, not just unmapped, so that it releases its keyboard grabs.
1877 But there are problems with running our callbacks while the widget is in
1878 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1879 instead of XmDESTROY and then destroy it ourself after having run the
1880 callback.
1882 do_call (widget, closure, no_selection);
1883 XtDestroyWidget (widget);
1886 static void
1887 xm_pull_down_callback (widget, closure, call_data)
1888 Widget widget;
1889 XtPointer closure;
1890 XtPointer call_data;
1892 Widget parent = XtParent (widget);
1894 if (XmIsRowColumn (parent))
1896 unsigned char type = 0xff;
1897 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1898 if (type == XmMENU_BAR)
1899 do_call (widget, closure, pre_activate);
1904 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1905 CLOSURE is a pointer to the widget_instance of the shell, CALL_DATA
1906 is always null under LessTif.
1908 2000-01-23: This callback is called for each cascade button in
1909 a menu, whether or not its submenu is visible. */
1911 static void
1912 xm_pop_down_callback (widget, closure, call_data)
1913 Widget widget;
1914 XtPointer closure;
1915 XtPointer call_data;
1917 widget_instance *instance = (widget_instance *) closure;
1919 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1920 || (XtParent (widget) == instance->parent))
1921 do_call (widget, closure, post_activate);
1924 static void
1925 xm_unmap_callback (widget, closure, call_data)
1926 Widget widget;
1927 XtPointer closure;
1928 XtPointer call_data;
1930 widget_instance *instance = (widget_instance *) closure;
1931 if (!instance->pop_up_p)
1932 do_call (widget, closure, post_activate);
1936 /* set the keyboard focus */
1937 void
1938 xm_set_keyboard_focus (parent, w)
1939 Widget parent;
1940 Widget w;
1942 XmProcessTraversal (w, 0);
1943 XtSetKeyboardFocus (parent, w);
1946 /* Motif hack to set the main window areas. */
1947 void
1948 xm_set_main_areas (parent, menubar, work_area)
1949 Widget parent;
1950 Widget menubar;
1951 Widget work_area;
1953 XmMainWindowSetAreas (parent,
1954 menubar, /* menubar (maybe 0) */
1955 0, /* command area (psheets) */
1956 0, /* horizontal scroll */
1957 0, /* vertical scroll */
1958 work_area); /* work area */
1961 /* Motif hack to control resizing on the menubar. */
1962 void
1963 xm_manage_resizing (w, flag)
1964 Widget w;
1965 Boolean flag;
1967 XtVaSetValues (w, XtNallowShellResize, flag, NULL);