Add `&' `dired-do-async-shell-command'.
[emacs.git] / lwlib / lwlib-Xm.c
blob7c91fe83e462cb64cc2a367dd8588e4909f09a63
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 Free Software Foundation, Inc.
4 Copyright (C) 1992 Lucid, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
11 any later version.
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <unistd.h>
28 #include <stdio.h>
30 #include <X11/StringDefs.h>
31 #include <X11/IntrinsicP.h>
32 #include <X11/ObjectP.h>
33 #include <X11/CoreP.h>
34 #include <X11/CompositeP.h>
36 #include "../src/lisp.h"
38 #include "lwlib-Xm.h"
39 #include "lwlib-utils.h"
41 #include <Xm/BulletinB.h>
42 #include <Xm/CascadeB.h>
43 #include <Xm/CascadeBG.h>
44 #include <Xm/DrawingA.h>
45 #include <Xm/FileSB.h>
46 #include <Xm/Label.h>
47 #include <Xm/List.h>
48 #include <Xm/MainW.h>
49 #include <Xm/MenuShell.h>
50 #include <Xm/MessageB.h>
51 #include <Xm/PanedW.h>
52 #include <Xm/PushB.h>
53 #include <Xm/PushBG.h>
54 #include <Xm/ArrowB.h>
55 #include <Xm/SelectioB.h>
56 #include <Xm/Text.h>
57 #include <Xm/TextF.h>
58 #include <Xm/ToggleB.h>
59 #include <Xm/ToggleBG.h>
60 #include <Xm/RowColumn.h>
61 #include <Xm/ScrolledW.h>
62 #include <Xm/Separator.h>
63 #include <Xm/DialogS.h>
64 #include <Xm/Form.h>
66 #undef P_
67 #if defined __STDC__ || defined PROTOTYPES
68 #define P_(X) X
69 #else
70 #define P_(X) ()
71 #endif
73 enum do_call_type { pre_activate, selection, no_selection, post_activate };
76 \f/* Structures to keep destroyed instances */
77 typedef struct _destroyed_instance
79 char* name;
80 char* type;
81 Widget widget;
82 Widget parent;
83 Boolean pop_up_p;
84 struct _destroyed_instance* next;
85 } destroyed_instance;
87 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
88 Widget, Widget,
89 Boolean));
90 static void free_destroyed_instance P_ ((destroyed_instance*));
91 Widget first_child P_ ((Widget));
92 Boolean lw_motif_widget_p P_ ((Widget));
93 static XmString resource_motif_string P_ ((Widget, char *));
94 static void destroy_all_children P_ ((Widget, int));
95 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
96 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
98 widget_value *));
99 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
100 widget_value *));
101 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
102 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
103 static void make_menu_in_widget P_ ((widget_instance *, Widget,
104 widget_value *, int));
105 static void update_one_menu_entry P_ ((widget_instance *, Widget,
106 widget_value *, Boolean));
107 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
108 Boolean));
109 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
110 static void xm_update_text_field P_ ((widget_instance *, Widget,
111 widget_value *));
112 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
113 static void activate_button P_ ((Widget, XtPointer, XtPointer));
114 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
115 Boolean, Boolean, Boolean, int, int));
116 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
117 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
118 static void recenter_widget P_ ((Widget));
119 static Widget recycle_instance P_ ((destroyed_instance*));
120 Widget xm_create_dialog P_ ((widget_instance*));
121 static Widget make_menubar P_ ((widget_instance*));
122 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
123 static Widget make_popup_menu P_ ((widget_instance*));
124 static Widget make_main P_ ((widget_instance*));
125 void xm_destroy_instance P_ ((widget_instance*));
126 void xm_popup_menu P_ ((Widget, XEvent *));
127 static void set_min_dialog_size P_ ((Widget));
128 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
129 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
130 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
131 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
132 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
133 void xm_set_keyboard_focus P_ ((Widget, Widget));
134 void xm_set_main_areas P_ ((Widget, Widget, Widget));
135 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
136 XtPointer));
137 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
139 #if 0
140 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
141 Boolean));
142 void xm_pop_instance P_ ((widget_instance*, Boolean));
143 void xm_manage_resizing P_ ((Widget, Boolean));
144 #endif
147 #if 0
149 /* Print the complete X resource name of widget WIDGET to stderr.
150 This is sometimes handy to have available. */
152 void
153 x_print_complete_resource_name (widget)
154 Widget widget;
156 int i;
157 String names[100];
159 for (i = 0; i < 100 && widget != NULL; ++i)
161 names[i] = XtName (widget);
162 widget = XtParent (widget);
165 for (--i; i >= 1; --i)
166 fprintf (stderr, "%s.", names[i]);
167 fprintf (stderr, "%s\n", names[0]);
170 #endif /* 0 */
173 static destroyed_instance *all_destroyed_instances = NULL;
175 static destroyed_instance*
176 make_destroyed_instance (name, type, widget, parent, pop_up_p)
177 char* name;
178 char* type;
179 Widget widget;
180 Widget parent;
181 Boolean pop_up_p;
183 destroyed_instance* instance =
184 (destroyed_instance*)malloc (sizeof (destroyed_instance));
185 instance->name = safe_strdup (name);
186 instance->type = safe_strdup (type);
187 instance->widget = widget;
188 instance->parent = parent;
189 instance->pop_up_p = pop_up_p;
190 instance->next = NULL;
191 return instance;
194 static void
195 free_destroyed_instance (instance)
196 destroyed_instance* instance;
198 free (instance->name);
199 free (instance->type);
200 free (instance);
203 \f/* motif utility functions */
204 Widget
205 first_child (widget)
206 Widget widget;
208 return ((CompositeWidget)widget)->composite.children [0];
211 Boolean
212 lw_motif_widget_p (widget)
213 Widget widget;
215 return
216 XtClass (widget) == xmDialogShellWidgetClass
217 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
220 static XmString
221 resource_motif_string (widget, name)
222 Widget widget;
223 char* name;
225 XtResource resource;
226 XmString result = 0;
228 resource.resource_name = name;
229 resource.resource_class = XmCXmString;
230 resource.resource_type = XmRXmString;
231 resource.resource_size = sizeof (XmString);
232 resource.resource_offset = 0;
233 resource.default_type = XtRImmediate;
234 resource.default_addr = 0;
236 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
237 "DialogString", &resource, 1, NULL, 0);
238 return result;
241 /* Destroy all of the children of WIDGET
242 starting with number FIRST_CHILD_TO_DESTROY. */
244 static void
245 destroy_all_children (widget, first_child_to_destroy)
246 Widget widget;
247 int first_child_to_destroy;
249 Widget* children;
250 unsigned int number;
251 int i;
253 children = XtCompositeChildren (widget, &number);
254 if (children)
256 XtUnmanageChildren (children + first_child_to_destroy,
257 number - first_child_to_destroy);
259 /* Unmanage all children and destroy them. They will only be
260 really destroyed when we get out of DispatchEvent. */
261 for (i = first_child_to_destroy; i < number; i++)
263 Arg al[2];
264 Widget submenu = 0;
265 /* Cascade buttons have submenus,and these submenus
266 need to be freed. But they are not included in
267 XtCompositeChildren. So get it out of the cascade button
268 and free it. If this child is not a cascade button,
269 then submenu should remain unchanged. */
270 XtSetArg (al[0], XmNsubMenuId, &submenu);
271 XtGetValues (children[i], al, 1);
272 if (submenu)
274 destroy_all_children (submenu, 0);
275 XtDestroyWidget (submenu);
277 XtDestroyWidget (children[i]);
280 XtFree ((char *) children);
286 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
287 menu. CLIENT_DATA contains a pointer to the widget_value
288 corresponding to widget W. CALL_DATA contains a
289 XmPushButtonCallbackStruct containing the reason why the callback
290 is called. */
292 static void
293 xm_arm_callback (w, client_data, call_data)
294 Widget w;
295 XtPointer client_data, call_data;
297 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
298 widget_value *wv = (widget_value *) client_data;
299 widget_instance *instance;
301 /* Get the id of the menu bar or popup menu this widget is in. */
302 while (w != NULL)
304 if (XmIsRowColumn (w))
306 unsigned char type = 0xff;
308 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
309 if (type == XmMENU_BAR || type == XmMENU_POPUP)
310 break;
313 w = XtParent (w);
316 if (w != NULL)
318 instance = lw_get_widget_instance (w);
319 if (instance && instance->info->highlight_cb)
321 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
322 instance->info->highlight_cb (w, instance->info->id, call_data);
329 /* Update the label of widget WIDGET. WIDGET must be a Label widget
330 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
331 the value to update.
333 Menus:
335 Emacs fills VAL->name with the text to display in the menu, and
336 sets VAL->value to null. Function make_menu_in_widget creates
337 widgets with VAL->name as resource name. This works because the
338 Label widget uses its resource name for display if no
339 XmNlabelString is set.
341 Dialogs:
343 VAL->name is again set to the resource name, but VAL->value is
344 not null, and contains the label string to display. */
346 static void
347 xm_update_label (instance, widget, val)
348 widget_instance* instance;
349 Widget widget;
350 widget_value* val;
352 XmString res_string = 0;
353 XmString built_string = 0;
354 XmString key_string = 0;
355 Arg al [256];
356 int ac;
358 ac = 0;
360 if (val->value)
362 /* A label string is specified, i.e. we are in a dialog. First
363 see if it is overridden by something from the resource file. */
364 res_string = resource_motif_string (widget, val->value);
366 if (res_string)
368 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
370 else
372 built_string =
373 XmStringCreateLocalized (val->value);
374 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
377 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
380 if (val->key)
382 key_string = XmStringCreateLocalized (val->key);
383 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
386 if (ac)
387 XtSetValues (widget, al, ac);
389 if (built_string)
390 XmStringFree (built_string);
392 if (key_string)
393 XmStringFree (key_string);
396 \f/* update of list */
397 static void
398 xm_update_list (instance, widget, val)
399 widget_instance* instance;
400 Widget widget;
401 widget_value* val;
403 widget_value* cur;
404 int i;
405 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
406 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
407 instance);
408 for (cur = val->contents, i = 0; cur; cur = cur->next)
409 if (cur->value)
411 XmString xmstr = XmStringCreateLocalized (cur->value);
412 i += 1;
413 XmListAddItem (widget, xmstr, 0);
414 if (cur->selected)
415 XmListSelectPos (widget, i, False);
416 XmStringFree (xmstr);
420 \f/* update of buttons */
421 static void
422 xm_update_pushbutton (instance, widget, val)
423 widget_instance* instance;
424 Widget widget;
425 widget_value* val;
427 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
428 XtRemoveAllCallbacks (widget, XmNactivateCallback);
429 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
432 static void
433 xm_update_cascadebutton (instance, widget, val)
434 widget_instance* instance;
435 Widget widget;
436 widget_value* val;
438 /* Should also rebuild the menu by calling ...update_menu... */
439 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
440 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
441 instance);
444 \f/* update toggle and radiobox */
445 static void
446 xm_update_toggle (instance, widget, val)
447 widget_instance* instance;
448 Widget widget;
449 widget_value* val;
451 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
452 XtAddCallback (widget, XmNvalueChangedCallback,
453 xm_generic_callback, instance);
454 XtVaSetValues (widget, XmNset, val->selected,
455 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
458 static void
459 xm_update_radiobox (instance, widget, val)
460 widget_instance* instance;
461 Widget widget;
462 widget_value* val;
465 Widget toggle;
466 widget_value* cur;
468 /* update the callback */
469 XtRemoveAllCallbacks (widget, XmNentryCallback);
470 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
472 /* first update all the toggles */
473 /* Energize kernel interface is currently bad. It sets the selected widget
474 with the selected flag but returns it by its name. So we currently
475 have to support both setting the selection with the selected slot
476 of val contents and setting it with the "value" slot of val. The latter
477 has a higher priority. This to be removed when the kernel is fixed. */
478 for (cur = val->contents; cur; cur = cur->next)
480 toggle = XtNameToWidget (widget, cur->value);
481 if (toggle)
483 XtSetSensitive (toggle, cur->enabled);
484 if (!val->value && cur->selected)
485 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
486 if (val->value && strcmp (val->value, cur->value))
487 XtVaSetValues (toggle, XmNset, False, NULL);
491 /* The selected was specified by the value slot */
492 if (val->value)
494 toggle = XtNameToWidget (widget, val->value);
495 if (toggle)
496 XtVaSetValues (toggle, XmNset, True, NULL);
501 /* update a popup menu, pulldown menu or a menubar */
503 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
505 static void
506 make_menu_in_widget (instance, widget, val, keep_first_children)
507 widget_instance* instance;
508 Widget widget;
509 widget_value* val;
510 int keep_first_children;
512 Widget* children = 0;
513 int num_children;
514 int child_index;
515 widget_value* cur;
516 Widget button = 0;
517 Widget title = 0;
518 Widget menu;
519 Arg al [256];
520 int ac;
521 Boolean menubar_p;
522 unsigned char type;
524 Widget* old_children;
525 unsigned int old_num_children;
527 /* Disable drag and drop for labels in menu bar. */
528 static char overrideTrans[] = "<Btn2Down>: Noop()";
529 XtTranslations override = XtParseTranslationTable (overrideTrans);
531 old_children = XtCompositeChildren (widget, &old_num_children);
533 /* Allocate the children array */
534 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
536 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
538 /* WIDGET should be a RowColumn. */
539 if (!XmIsRowColumn (widget))
540 abort ();
542 /* Determine whether WIDGET is a menu bar. */
543 type = -1;
544 XtSetArg (al[0], XmNrowColumnType, &type);
545 XtGetValues (widget, al, 1);
546 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
547 abort ();
548 menubar_p = type == XmMENU_BAR;
550 /* Add a callback to popups and pulldowns that is called when
551 it is made invisible again. */
552 if (!menubar_p)
553 XtAddCallback (XtParent (widget), XmNpopdownCallback,
554 xm_pop_down_callback, (XtPointer)instance);
556 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
557 for (child_index = 0, cur = val; child_index < keep_first_children;
558 child_index++, cur = cur->next)
559 children[child_index] = old_children[child_index];
561 /* Check that those are all we have
562 (the caller should have deleted the rest). */
563 if (old_num_children != keep_first_children)
564 abort ();
566 /* Create the rest. */
567 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
569 enum menu_separator separator;
571 ac = 0;
572 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
573 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
574 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
576 if (instance->pop_up_p && !cur->contents && !cur->call_data
577 && !lw_separator_p (cur->name, &separator, 1))
579 ac = 0;
580 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
581 title = button = XmCreateLabel (widget, cur->name, al, ac);
583 else if (lw_separator_p (cur->name, &separator, 1))
585 ac = 0;
586 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
587 button = XmCreateSeparator (widget, cur->name, al, ac);
589 else if (!cur->contents)
591 if (menubar_p)
592 button = XmCreateCascadeButton (widget, cur->name, al, ac);
593 else if (!cur->call_data)
594 button = XmCreateLabel (widget, cur->name, al, ac);
595 else if (cur->button_type == BUTTON_TYPE_TOGGLE
596 || cur->button_type == BUTTON_TYPE_RADIO)
598 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
599 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
600 XtSetArg (al[ac], XmNindicatorType,
601 (cur->button_type == BUTTON_TYPE_TOGGLE
602 ? XmN_OF_MANY : XmONE_OF_MANY));
603 ++ac;
604 button = XmCreateToggleButton (widget, cur->name, al, ac);
605 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
606 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
608 else
610 button = XmCreatePushButton (widget, cur->name, al, ac);
611 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
612 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
615 xm_update_label (instance, button, cur);
617 /* Add a callback that is called when the button is
618 selected. Toggle buttons don't support
619 XmNactivateCallback, we use XmNvalueChangedCallback in
620 that case. Don't add a callback to a simple label. */
621 if (cur->button_type)
622 xm_update_toggle (instance, button, cur);
623 else if (cur->call_data)
624 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
625 (XtPointer)instance);
627 else
629 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
631 make_menu_in_widget (instance, menu, cur->contents, 0);
632 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
633 button = XmCreateCascadeButton (widget, cur->name, al, ac);
635 xm_update_label (instance, button, cur);
637 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
638 (XtPointer)instance);
639 XtOverrideTranslations (button, override);
643 children[child_index] = button;
646 /* Last entry is the help button. The original comment read "Has to
647 be done after managing the buttons otherwise the menubar is only
648 4 pixels high." This is no longer true, and to make
649 XmNmenuHelpWidget work, we need to set it before managing the
650 children.. --gerd. */
651 if (button)
652 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
654 if (num_children)
655 XtManageChildren (children, num_children);
657 XtFree ((char *) children);
658 if (old_children)
659 XtFree ((char *) old_children);
662 static void
663 update_one_menu_entry (instance, widget, val, deep_p)
664 widget_instance* instance;
665 Widget widget;
666 widget_value* val;
667 Boolean deep_p;
669 Arg al [256];
670 int ac;
671 Widget menu;
672 widget_value* contents;
674 if (val->this_one_change == NO_CHANGE)
675 return;
677 /* update the sensitivity and userdata */
678 /* Common to all widget types */
679 XtSetSensitive (widget, val->enabled);
680 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
682 /* update the menu button as a label. */
683 if (val->this_one_change >= VISIBLE_CHANGE)
685 xm_update_label (instance, widget, val);
686 if (val->button_type)
687 xm_update_toggle (instance, widget, val);
690 /* update the pulldown/pullaside as needed */
691 ac = 0;
692 menu = NULL;
693 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
694 XtGetValues (widget, al, ac);
696 contents = val->contents;
698 if (!menu)
700 if (contents)
702 unsigned int old_num_children, i;
703 Widget parent;
704 Widget *widget_list;
706 parent = XtParent (widget);
707 widget_list = XtCompositeChildren (parent, &old_num_children);
709 /* Find the widget position within the parent's widget list. */
710 for (i = 0; i < old_num_children; i++)
711 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
712 break;
713 if (i == old_num_children)
714 abort ();
715 if (XmIsCascadeButton (widget_list[i]))
717 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
718 make_menu_in_widget (instance, menu, contents, 0);
719 ac = 0;
720 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
721 XtSetValues (widget, al, ac);
723 else
725 Widget button;
727 /* The current menuitem is a XmPushButtonGadget, it
728 needs to be replaced by a CascadeButtonGadget */
729 XtDestroyWidget (widget_list[i]);
730 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
731 make_menu_in_widget (instance, menu, contents, 0);
732 ac = 0;
733 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
734 /* Non-zero values don't work reliably in
735 conjunction with Emacs' event loop */
736 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
737 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
738 /* Tell Motif to put it in the right place */
739 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
740 #endif
741 button = XmCreateCascadeButton (parent, val->name, al, ac);
742 xm_update_label (instance, button, val);
744 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
745 (XtPointer)instance);
746 XtManageChild (button);
749 if (widget_list)
750 XtFree ((char*) widget_list);
753 else if (!contents)
755 ac = 0;
756 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
757 XtSetValues (widget, al, ac);
758 XtDestroyWidget (menu);
760 else if (deep_p && contents->change != NO_CHANGE)
761 xm_update_menu (instance, menu, val, 1);
764 static void
765 xm_update_menu (instance, widget, val, deep_p)
766 widget_instance* instance;
767 Widget widget;
768 widget_value* val;
769 Boolean deep_p;
771 Widget* children;
772 unsigned int num_children;
773 int num_children_to_keep = 0;
774 int i;
775 widget_value* cur;
777 children = XtCompositeChildren (widget, &num_children);
779 /* Widget is a RowColumn widget whose contents have to be updated
780 * to reflect the list of items in val->contents */
782 /* See how many buttons we can keep, and how many we
783 must completely replace. */
784 if (val->contents == 0)
785 num_children_to_keep = 0;
786 else if (val->contents->change == STRUCTURAL_CHANGE)
788 if (children)
790 for (i = 0, cur = val->contents;
791 (i < num_children
792 && cur); /* how else to ditch unwanted children ?? - mgd */
793 i++, cur = cur->next)
795 if (cur->this_one_change == STRUCTURAL_CHANGE)
796 break;
799 num_children_to_keep = i;
802 else
803 num_children_to_keep = num_children;
805 /* Update all the buttons of the RowColumn, in order,
806 except for those we are going to replace entirely. */
807 if (children)
809 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
811 if (!cur)
813 num_children_to_keep = i;
814 break;
816 if (children [i]->core.being_destroyed
817 || strcmp (XtName (children [i]), cur->name))
818 continue;
819 update_one_menu_entry (instance, children [i], cur, deep_p);
820 cur = cur->next;
824 /* Now replace from scratch all the buttons after the last
825 place that the top-level structure changed. */
826 if (val->contents->change == STRUCTURAL_CHANGE)
828 destroy_all_children (widget, num_children_to_keep);
829 make_menu_in_widget (instance, widget, val->contents,
830 num_children_to_keep);
833 XtFree ((char *) children);
837 /* update text widgets */
839 static void
840 xm_update_text (instance, widget, val)
841 widget_instance* instance;
842 Widget widget;
843 widget_value* val;
845 XmTextSetString (widget, val->value ? val->value : "");
846 XtRemoveAllCallbacks (widget, XmNactivateCallback);
847 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
848 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
849 XtAddCallback (widget, XmNvalueChangedCallback,
850 xm_internal_update_other_instances, instance);
853 static void
854 xm_update_text_field (instance, widget, val)
855 widget_instance* instance;
856 Widget widget;
857 widget_value* val;
859 XmTextFieldSetString (widget, val->value ? val->value : "");
860 XtRemoveAllCallbacks (widget, XmNactivateCallback);
861 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
862 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
863 XtAddCallback (widget, XmNvalueChangedCallback,
864 xm_internal_update_other_instances, instance);
868 /* update a motif widget */
870 void
871 xm_update_one_widget (instance, widget, val, deep_p)
872 widget_instance* instance;
873 Widget widget;
874 widget_value* val;
875 Boolean deep_p;
877 WidgetClass class;
879 /* Mark as not edited */
880 val->edited = False;
882 /* Common to all widget types */
883 XtSetSensitive (widget, val->enabled);
884 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
886 /* Common to all label like widgets */
887 if (XtIsSubclass (widget, xmLabelWidgetClass))
888 xm_update_label (instance, widget, val);
890 class = XtClass (widget);
891 /* Class specific things */
892 if (class == xmPushButtonWidgetClass ||
893 class == xmArrowButtonWidgetClass)
895 xm_update_pushbutton (instance, widget, val);
897 else if (class == xmCascadeButtonWidgetClass)
899 xm_update_cascadebutton (instance, widget, val);
901 else if (class == xmToggleButtonWidgetClass
902 || class == xmToggleButtonGadgetClass)
904 xm_update_toggle (instance, widget, val);
906 else if (class == xmRowColumnWidgetClass)
908 Boolean radiobox = 0;
909 int ac = 0;
910 Arg al [1];
912 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
913 XtGetValues (widget, al, ac);
915 if (radiobox)
916 xm_update_radiobox (instance, widget, val);
917 else
918 xm_update_menu (instance, widget, val, deep_p);
920 else if (class == xmTextWidgetClass)
922 xm_update_text (instance, widget, val);
924 else if (class == xmTextFieldWidgetClass)
926 xm_update_text_field (instance, widget, val);
928 else if (class == xmListWidgetClass)
930 xm_update_list (instance, widget, val);
934 \f/* getting the value back */
935 void
936 xm_update_one_value (instance, widget, val)
937 widget_instance* instance;
938 Widget widget;
939 widget_value* val;
941 WidgetClass class = XtClass (widget);
942 widget_value *old_wv;
944 /* copy the call_data slot into the "return" widget_value */
945 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
946 if (!strcmp (val->name, old_wv->name))
948 val->call_data = old_wv->call_data;
949 break;
952 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
954 XtVaGetValues (widget, XmNset, &val->selected, NULL);
955 val->edited = True;
957 else if (class == xmTextWidgetClass)
959 free (val->value);
960 val->value = XmTextGetString (widget);
961 val->edited = True;
963 else if (class == xmTextFieldWidgetClass)
965 free (val->value);
966 val->value = XmTextFieldGetString (widget);
967 val->edited = True;
969 else if (class == xmRowColumnWidgetClass)
971 Boolean radiobox = 0;
972 int ac = 0;
973 Arg al [1];
975 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
976 XtGetValues (widget, al, ac);
978 if (radiobox)
980 CompositeWidget radio = (CompositeWidget)widget;
981 int i;
982 for (i = 0; i < radio->composite.num_children; i++)
984 int set = False;
985 Widget toggle = radio->composite.children [i];
987 XtVaGetValues (toggle, XmNset, &set, NULL);
988 if (set)
990 free (val->value);
991 val->value = safe_strdup (XtName (toggle));
994 val->edited = True;
997 else if (class == xmListWidgetClass)
999 int pos_cnt;
1000 int* pos_list;
1001 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
1003 int i;
1004 widget_value* cur;
1005 for (cur = val->contents, i = 0; cur; cur = cur->next)
1006 if (cur->value)
1008 int j;
1009 cur->selected = False;
1010 i += 1;
1011 for (j = 0; j < pos_cnt; j++)
1012 if (pos_list [j] == i)
1014 cur->selected = True;
1015 val->value = safe_strdup (cur->name);
1018 val->edited = 1;
1019 XtFree ((char *) pos_list);
1025 /* This function is for activating a button from a program. It's wrong because
1026 we pass a NULL argument in the call_data which is not Motif compatible.
1027 This is used from the XmNdefaultAction callback of the List widgets to
1028 have a double-click put down a dialog box like the button would do.
1029 I could not find a way to do that with accelerators.
1031 static void
1032 activate_button (widget, closure, call_data)
1033 Widget widget;
1034 XtPointer closure;
1035 XtPointer call_data;
1037 Widget button = (Widget)closure;
1038 XtCallCallbacks (button, XmNactivateCallback, NULL);
1041 /* creation functions */
1043 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1044 static void
1045 dialog_key_cb (widget, closure, event, continue_to_dispatch)
1046 Widget widget;
1047 XtPointer closure;
1048 XEvent *event;
1049 Boolean *continue_to_dispatch;
1051 KeySym sym = 0;
1052 Modifiers modif_ret;
1054 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1055 &modif_ret, &sym);
1057 if (sym == osfXK_Cancel)
1059 Widget w = *((Widget *) closure);
1061 while (w && ! XtIsShell (w))
1062 w = XtParent (w);
1064 if (XtIsShell (w)) XtPopdown (w);
1067 *continue_to_dispatch = TRUE;
1070 /* dialogs */
1071 static Widget
1072 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1073 radio_box, list, left_buttons, right_buttons)
1074 char* name;
1075 Widget parent;
1076 Boolean pop_up_p;
1077 char* shell_title;
1078 char* icon_name;
1079 Boolean text_input_slot;
1080 Boolean radio_box;
1081 Boolean list;
1082 int left_buttons;
1083 int right_buttons;
1085 Widget result;
1086 Widget form;
1087 Widget row;
1088 Widget icon;
1089 Widget icon_separator;
1090 Widget message;
1091 Widget value = 0;
1092 Widget separator;
1093 Widget button = 0;
1094 Widget children [16]; /* for the final XtManageChildren */
1095 int n_children;
1096 Arg al[64]; /* Arg List */
1097 int ac; /* Arg Count */
1098 int i;
1100 if (pop_up_p)
1102 ac = 0;
1103 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1104 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1105 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1106 result = XmCreateDialogShell (parent, "dialog", al, ac);
1107 ac = 0;
1108 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1109 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1110 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1111 form = XmCreateForm (result, shell_title, al, ac);
1113 else
1115 ac = 0;
1116 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1117 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1118 form = XmCreateForm (parent, shell_title, al, ac);
1119 result = form;
1122 n_children = left_buttons + right_buttons + 1;
1123 ac = 0;
1124 XtSetArg(al[ac], XmNpacking, n_children == 3?
1125 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1126 XtSetArg(al[ac], XmNorientation, n_children == 3?
1127 XmVERTICAL: XmHORIZONTAL); ac++;
1128 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1129 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1130 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1131 XtSetArg(al[ac], XmNspacing, 13); ac++;
1132 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1133 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1134 XtSetArg(al[ac], XmNisAligned, True); ac++;
1135 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1136 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1137 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1138 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1139 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1140 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1141 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1142 row = XmCreateRowColumn (form, "row", al, ac);
1144 n_children = 0;
1145 for (i = 0; i < left_buttons; i++)
1147 char button_name [16];
1148 sprintf (button_name, "button%d", i + 1);
1149 ac = 0;
1150 if (i == 0)
1152 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1153 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1155 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1156 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1157 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1158 XtAddEventHandler (children [n_children],
1159 KeyPressMask, False, dialog_key_cb, result);
1161 if (i == 0)
1163 button = children [n_children];
1164 ac = 0;
1165 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1166 XtSetValues (row, al, ac);
1169 n_children++;
1172 /* invisible separator button */
1173 ac = 0;
1174 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1175 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1176 n_children++;
1178 for (i = 0; i < right_buttons; i++)
1180 char button_name [16];
1181 sprintf (button_name, "button%d", left_buttons + i + 1);
1182 ac = 0;
1183 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1184 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1185 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1186 XtAddEventHandler (children [n_children],
1187 KeyPressMask, False, dialog_key_cb, result);
1189 if (! button) button = children [n_children];
1190 n_children++;
1193 XtManageChildren (children, n_children);
1195 ac = 0;
1196 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1197 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1198 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1199 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1200 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1201 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1202 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1203 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1204 separator = XmCreateSeparator (form, "", al, ac);
1206 ac = 0;
1207 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1208 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1209 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1210 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1211 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1212 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1213 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1214 icon = XmCreateLabel (form, icon_name, al, ac);
1216 ac = 0;
1217 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1218 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1219 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1220 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1221 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1222 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1223 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1224 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1225 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1226 icon_separator = XmCreateLabel (form, "", al, ac);
1228 if (text_input_slot)
1230 ac = 0;
1231 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1232 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1233 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1234 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1235 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1236 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1237 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1238 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1239 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1240 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1241 value = XmCreateTextField (form, "value", al, ac);
1243 else if (radio_box)
1245 Widget radio_butt;
1246 ac = 0;
1247 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1248 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1249 XtSetArg(al[ac], XmNspacing, 13); ac++;
1250 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1251 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1252 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1253 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1254 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1255 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1256 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1257 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1258 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1259 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1260 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1261 ac = 0;
1262 i = 0;
1263 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1264 children [i++] = radio_butt;
1265 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1266 children [i++] = radio_butt;
1267 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1268 children [i++] = radio_butt;
1269 XtManageChildren (children, i);
1271 else if (list)
1273 ac = 0;
1274 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1275 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1276 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1277 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1278 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1279 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1280 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1281 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1282 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1283 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1284 value = XmCreateScrolledList (form, "list", al, ac);
1286 /* this is the easiest way I found to have the dble click in the
1287 list activate the default button */
1288 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1291 ac = 0;
1292 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1293 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1294 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1295 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1296 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1297 XtSetArg(al[ac], XmNbottomWidget,
1298 text_input_slot || radio_box || list ? value : separator); ac++;
1299 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1300 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1301 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1302 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1303 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1304 message = XmCreateLabel (form, "message", al, ac);
1306 if (list)
1307 XtManageChild (value);
1309 i = 0;
1310 children [i] = row; i++;
1311 children [i] = separator; i++;
1312 if (text_input_slot || radio_box)
1314 children [i] = value; i++;
1316 children [i] = message; i++;
1317 children [i] = icon; i++;
1318 children [i] = icon_separator; i++;
1319 XtManageChildren (children, i);
1321 if (text_input_slot || list)
1323 XtInstallAccelerators (value, button);
1324 XtSetKeyboardFocus (result, value);
1326 else
1328 XtInstallAccelerators (form, button);
1329 XtSetKeyboardFocus (result, button);
1332 return result;
1335 static destroyed_instance*
1336 find_matching_instance (instance)
1337 widget_instance* instance;
1339 destroyed_instance* cur;
1340 destroyed_instance* prev;
1341 char* type = instance->info->type;
1342 char* name = instance->info->name;
1344 for (prev = NULL, cur = all_destroyed_instances;
1345 cur;
1346 prev = cur, cur = cur->next)
1348 if (!strcmp (cur->name, name)
1349 && !strcmp (cur->type, type)
1350 && cur->parent == instance->parent
1351 && cur->pop_up_p == instance->pop_up_p)
1353 if (prev)
1354 prev->next = cur->next;
1355 else
1356 all_destroyed_instances = cur->next;
1357 return cur;
1359 /* do some cleanup */
1360 else if (!cur->widget)
1362 if (prev)
1363 prev->next = cur->next;
1364 else
1365 all_destroyed_instances = cur->next;
1366 free_destroyed_instance (cur);
1367 cur = prev ? prev : all_destroyed_instances;
1370 return NULL;
1373 static void
1374 mark_dead_instance_destroyed (widget, closure, call_data)
1375 Widget widget;
1376 XtPointer closure;
1377 XtPointer call_data;
1379 destroyed_instance* instance = (destroyed_instance*)closure;
1380 instance->widget = NULL;
1383 static void
1384 recenter_widget (widget)
1385 Widget widget;
1387 Widget parent = XtParent (widget);
1388 Screen* screen = XtScreen (widget);
1389 Dimension screen_width = WidthOfScreen (screen);
1390 Dimension screen_height = HeightOfScreen (screen);
1391 Dimension parent_width = 0;
1392 Dimension parent_height = 0;
1393 Dimension child_width = 0;
1394 Dimension child_height = 0;
1395 Position x;
1396 Position y;
1398 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1399 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1400 NULL);
1402 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1403 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1405 XtTranslateCoords (parent, x, y, &x, &y);
1407 if (x + child_width > screen_width)
1408 x = screen_width - child_width;
1409 if (x < 0)
1410 x = 0;
1412 if (y + child_height > screen_height)
1413 y = screen_height - child_height;
1414 if (y < 0)
1415 y = 0;
1417 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1420 static Widget
1421 recycle_instance (instance)
1422 destroyed_instance* instance;
1424 Widget widget = instance->widget;
1426 /* widget is NULL if the parent was destroyed. */
1427 if (widget)
1429 Widget focus;
1430 Widget separator;
1432 /* Remove the destroy callback as the instance is not in the list
1433 anymore */
1434 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1435 mark_dead_instance_destroyed,
1436 (XtPointer)instance);
1438 /* Give the focus to the initial item */
1439 focus = XtNameToWidget (widget, "*value");
1440 if (!focus)
1441 focus = XtNameToWidget (widget, "*button1");
1442 if (focus)
1443 XtSetKeyboardFocus (widget, focus);
1445 /* shrink the separator label back to their original size */
1446 separator = XtNameToWidget (widget, "*separator_button");
1447 if (separator)
1448 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1450 /* Center the dialog in its parent */
1451 recenter_widget (widget);
1453 free_destroyed_instance (instance);
1454 return widget;
1457 Widget
1458 xm_create_dialog (instance)
1459 widget_instance* instance;
1461 char* name = instance->info->type;
1462 Widget parent = instance->parent;
1463 Widget widget;
1464 Boolean pop_up_p = instance->pop_up_p;
1465 char* shell_name = 0;
1466 char* icon_name = 0;
1467 Boolean text_input_slot = False;
1468 Boolean radio_box = False;
1469 Boolean list = False;
1470 int total_buttons;
1471 int left_buttons = 0;
1472 int right_buttons = 1;
1473 destroyed_instance* dead_one;
1475 /* try to find a widget to recycle */
1476 dead_one = find_matching_instance (instance);
1477 if (dead_one)
1479 Widget recycled_widget = recycle_instance (dead_one);
1480 if (recycled_widget)
1481 return recycled_widget;
1484 switch (name [0]){
1485 case 'E': case 'e':
1486 icon_name = "dbox-error";
1487 shell_name = "Error";
1488 break;
1490 case 'I': case 'i':
1491 icon_name = "dbox-info";
1492 shell_name = "Information";
1493 break;
1495 case 'L': case 'l':
1496 list = True;
1497 icon_name = "dbox-question";
1498 shell_name = "Prompt";
1499 break;
1501 case 'P': case 'p':
1502 text_input_slot = True;
1503 icon_name = "dbox-question";
1504 shell_name = "Prompt";
1505 break;
1507 case 'Q': case 'q':
1508 icon_name = "dbox-question";
1509 shell_name = "Question";
1510 break;
1513 total_buttons = name [1] - '0';
1515 if (name [3] == 'T' || name [3] == 't')
1517 text_input_slot = False;
1518 radio_box = True;
1520 else if (name [3])
1521 right_buttons = name [4] - '0';
1523 left_buttons = total_buttons - right_buttons;
1525 widget = make_dialog (name, parent, pop_up_p,
1526 shell_name, icon_name, text_input_slot, radio_box,
1527 list, left_buttons, right_buttons);
1529 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1530 (XtPointer) instance);
1532 return widget;
1535 /* Create a menu bar. We turn off the f10 key
1536 because we have not yet managed to make it work right in Motif. */
1538 static Widget
1539 make_menubar (instance)
1540 widget_instance* instance;
1542 Arg al[3];
1543 int ac;
1545 ac = 0;
1546 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1547 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1550 static void
1551 remove_grabs (shell, closure, call_data)
1552 Widget shell;
1553 XtPointer closure;
1554 XtPointer call_data;
1556 Widget menu = (Widget) closure;
1557 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1560 static Widget
1561 make_popup_menu (instance)
1562 widget_instance* instance;
1564 Widget parent = instance->parent;
1565 Window parent_window = parent->core.window;
1566 Widget result;
1568 /* sets the parent window to 0 to fool Motif into not generating a grab */
1569 parent->core.window = 0;
1570 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1571 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1572 (XtPointer)result);
1573 parent->core.window = parent_window;
1574 return result;
1577 static Widget
1578 make_main (instance)
1579 widget_instance* instance;
1581 Widget parent = instance->parent;
1582 Widget result;
1583 Arg al[2];
1584 int ac;
1586 ac = 0;
1587 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1588 XtSetArg (al[ac], XmNspacing, 0); ac++;
1589 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1590 return result;
1593 \f/* Table of functions to create widgets */
1595 #ifdef ENERGIZE
1597 /* interface with the XDesigner generated functions */
1598 typedef Widget (*widget_maker) (Widget);
1599 extern Widget create_project_p_sheet (Widget parent);
1600 extern Widget create_debugger_p_sheet (Widget parent);
1601 extern Widget create_breaklist_p_sheet (Widget parent);
1602 extern Widget create_le_browser_p_sheet (Widget parent);
1603 extern Widget create_class_browser_p_sheet (Widget parent);
1604 extern Widget create_call_browser_p_sheet (Widget parent);
1605 extern Widget create_build_dialog (Widget parent);
1606 extern Widget create_editmode_dialog (Widget parent);
1607 extern Widget create_search_dialog (Widget parent);
1608 extern Widget create_project_display_dialog (Widget parent);
1610 static Widget
1611 make_one (widget_instance* instance, widget_maker fn)
1613 Widget result;
1614 Arg al [64];
1615 int ac = 0;
1617 if (instance->pop_up_p)
1619 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1620 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1621 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1622 (XtPointer) instance);
1623 (*fn) (result);
1625 else
1627 result = (*fn) (instance->parent);
1628 XtRealizeWidget (result);
1630 return result;
1633 static Widget
1634 make_project_p_sheet (widget_instance* instance)
1636 return make_one (instance, create_project_p_sheet);
1639 static Widget
1640 make_debugger_p_sheet (widget_instance* instance)
1642 return make_one (instance, create_debugger_p_sheet);
1645 static Widget
1646 make_breaklist_p_sheet (widget_instance* instance)
1648 return make_one (instance, create_breaklist_p_sheet);
1651 static Widget
1652 make_le_browser_p_sheet (widget_instance* instance)
1654 return make_one (instance, create_le_browser_p_sheet);
1657 static Widget
1658 make_class_browser_p_sheet (widget_instance* instance)
1660 return make_one (instance, create_class_browser_p_sheet);
1663 static Widget
1664 make_call_browser_p_sheet (widget_instance* instance)
1666 return make_one (instance, create_call_browser_p_sheet);
1669 static Widget
1670 make_build_dialog (widget_instance* instance)
1672 return make_one (instance, create_build_dialog);
1675 static Widget
1676 make_editmode_dialog (widget_instance* instance)
1678 return make_one (instance, create_editmode_dialog);
1681 static Widget
1682 make_search_dialog (widget_instance* instance)
1684 return make_one (instance, create_search_dialog);
1687 static Widget
1688 make_project_display_dialog (widget_instance* instance)
1690 return make_one (instance, create_project_display_dialog);
1693 #endif /* ENERGIZE */
1695 widget_creation_entry
1696 xm_creation_table [] =
1698 {"menubar", make_menubar},
1699 {"popup", make_popup_menu},
1700 {"main", make_main},
1701 #ifdef ENERGIZE
1702 {"project_p_sheet", make_project_p_sheet},
1703 {"debugger_p_sheet", make_debugger_p_sheet},
1704 {"breaklist_psheet", make_breaklist_p_sheet},
1705 {"leb_psheet", make_le_browser_p_sheet},
1706 {"class_browser_psheet", make_class_browser_p_sheet},
1707 {"ctree_browser_psheet", make_call_browser_p_sheet},
1708 {"build", make_build_dialog},
1709 {"editmode", make_editmode_dialog},
1710 {"search", make_search_dialog},
1711 {"project_display", make_project_display_dialog},
1712 #endif /* ENERGIZE */
1713 {NULL, NULL}
1716 \f/* Destruction of instances */
1717 void
1718 xm_destroy_instance (instance)
1719 widget_instance* instance;
1721 Widget widget = instance->widget;
1722 /* recycle the dialog boxes */
1723 /* Disable the recycling until we can find a way to have the dialog box
1724 get reasonable layout after we modify its contents. */
1725 if (0
1726 && XtClass (widget) == xmDialogShellWidgetClass)
1728 destroyed_instance* dead_instance =
1729 make_destroyed_instance (instance->info->name,
1730 instance->info->type,
1731 instance->widget,
1732 instance->parent,
1733 instance->pop_up_p);
1734 dead_instance->next = all_destroyed_instances;
1735 all_destroyed_instances = dead_instance;
1736 XtUnmanageChild (first_child (instance->widget));
1737 XFlush (XtDisplay (instance->widget));
1738 XtAddCallback (instance->parent, XtNdestroyCallback,
1739 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1741 else
1743 /* This might not be necessary now that the nosel is attached to
1744 popdown instead of destroy, but it can't hurt. */
1745 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1746 xm_nosel_callback, (XtPointer)instance);
1747 XtDestroyWidget (instance->widget);
1751 \f/* popup utility */
1752 void
1753 xm_popup_menu (widget, event)
1754 Widget widget;
1755 XEvent *event;
1757 XButtonPressedEvent dummy;
1759 if (event == 0)
1761 dummy.type = ButtonPress;
1762 dummy.serial = 0;
1763 dummy.send_event = 0;
1764 dummy.display = XtDisplay (widget);
1765 dummy.window = XtWindow (XtParent (widget));
1766 dummy.time = 0;
1767 dummy.button = 0;
1768 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1769 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1770 &dummy.x, &dummy.y, &dummy.state);
1771 event = (XEvent *) &dummy;
1774 if (event->type == ButtonPress || event->type == ButtonRelease)
1776 /* Setting the menuPost resource only required by Motif 1.1 and
1777 LessTif 0.84 and earlier. With later versions of LessTif,
1778 setting menuPost is unnecessary and may cause problems, so
1779 don't do it. */
1780 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1782 /* This is so totally ridiculous: there's NO WAY to tell Motif
1783 that *any* button can select a menu item. Only one button
1784 can have that honor. */
1786 char *trans = 0;
1787 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1788 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1789 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1790 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1791 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1792 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1794 #endif
1796 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1799 XtManageChild (widget);
1802 static void
1803 set_min_dialog_size (w)
1804 Widget w;
1806 short width;
1807 short height;
1808 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1809 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1812 void
1813 xm_pop_instance (instance, up)
1814 widget_instance* instance;
1815 Boolean up;
1817 Widget widget = instance->widget;
1819 if (XtClass (widget) == xmDialogShellWidgetClass)
1821 Widget widget_to_manage = first_child (widget);
1822 if (up)
1824 XtManageChild (widget_to_manage);
1825 set_min_dialog_size (widget);
1826 XtSetKeyboardFocus (instance->parent, widget);
1828 else
1829 XtUnmanageChild (widget_to_manage);
1831 else
1833 if (up)
1834 XtManageChild (widget);
1835 else
1836 XtUnmanageChild (widget);
1841 /* motif callback */
1843 static void
1844 do_call (widget, closure, type)
1845 Widget widget;
1846 XtPointer closure;
1847 enum do_call_type type;
1849 Arg al [256];
1850 int ac;
1851 XtPointer user_data;
1852 widget_instance* instance = (widget_instance*)closure;
1853 Widget instance_widget;
1854 LWLIB_ID id;
1856 if (!instance)
1857 return;
1858 if (widget->core.being_destroyed)
1859 return;
1861 instance_widget = instance->widget;
1862 if (!instance_widget)
1863 return;
1865 id = instance->info->id;
1866 ac = 0;
1867 user_data = NULL;
1868 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1869 XtGetValues (widget, al, ac);
1871 switch (type)
1873 case pre_activate:
1874 if (instance->info->pre_activate_cb)
1875 instance->info->pre_activate_cb (widget, id, user_data);
1876 break;
1878 case selection:
1879 if (instance->info->selection_cb)
1880 instance->info->selection_cb (widget, id, user_data);
1881 break;
1883 case no_selection:
1884 if (instance->info->selection_cb)
1885 instance->info->selection_cb (widget, id, (XtPointer) -1);
1886 break;
1888 case post_activate:
1889 if (instance->info->post_activate_cb)
1890 instance->info->post_activate_cb (widget, id, user_data);
1891 break;
1893 default:
1894 abort ();
1898 /* Like lw_internal_update_other_instances except that it does not do
1899 anything if its shell parent is not managed. This is to protect
1900 lw_internal_update_other_instances to dereference freed memory
1901 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1902 list */
1903 static void
1904 xm_internal_update_other_instances (widget, closure, call_data)
1905 Widget widget;
1906 XtPointer closure;
1907 XtPointer call_data;
1909 Widget parent;
1910 for (parent = widget; parent; parent = XtParent (parent))
1911 if (XtIsShell (parent))
1912 break;
1913 else if (!XtIsManaged (parent))
1914 return;
1915 lw_internal_update_other_instances (widget, closure, call_data);
1918 static void
1919 xm_generic_callback (widget, closure, call_data)
1920 Widget widget;
1921 XtPointer closure;
1922 XtPointer call_data;
1924 lw_internal_update_other_instances (widget, closure, call_data);
1925 do_call (widget, closure, selection);
1928 static void
1929 xm_nosel_callback (widget, closure, call_data)
1930 Widget widget;
1931 XtPointer closure;
1932 XtPointer call_data;
1934 /* This callback is only called when a dialog box is dismissed with
1935 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1936 box to be destroyed in that case, not just unmapped, so that it
1937 releases its keyboard grabs. But there are problems with running
1938 our callbacks while the widget is in the process of being
1939 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1940 XmDESTROY and then destroy it ourself after having run the
1941 callback. */
1942 do_call (widget, closure, no_selection);
1943 XtDestroyWidget (widget);
1946 static void
1947 xm_pull_down_callback (widget, closure, call_data)
1948 Widget widget;
1949 XtPointer closure;
1950 XtPointer call_data;
1952 Widget parent = XtParent (widget);
1954 if (XmIsRowColumn (parent))
1956 unsigned char type = 0xff;
1957 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1958 if (type == XmMENU_BAR)
1959 do_call (widget, closure, pre_activate);
1964 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1965 CLOSURE is a pointer to the widget_instance of the shell,
1967 Note that this callback is called for each cascade button in a
1968 menu, whether or not its submenu is visible. */
1970 static void
1971 xm_pop_down_callback (widget, closure, call_data)
1972 Widget widget;
1973 XtPointer closure;
1974 XtPointer call_data;
1976 widget_instance *instance = (widget_instance *) closure;
1978 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1979 || XtParent (widget) == instance->parent)
1980 do_call (widget, closure, post_activate);
1984 /* set the keyboard focus */
1985 void
1986 xm_set_keyboard_focus (parent, w)
1987 Widget parent;
1988 Widget w;
1990 XmProcessTraversal (w, 0);
1991 XtSetKeyboardFocus (parent, w);
1994 /* Motif hack to set the main window areas. */
1995 void
1996 xm_set_main_areas (parent, menubar, work_area)
1997 Widget parent;
1998 Widget menubar;
1999 Widget work_area;
2001 XmMainWindowSetAreas (parent,
2002 menubar, /* menubar (maybe 0) */
2003 0, /* command area (psheets) */
2004 0, /* horizontal scroll */
2005 0, /* vertical scroll */
2006 work_area); /* work area */
2009 /* Motif hack to control resizing on the menubar. */
2010 void
2011 xm_manage_resizing (w, flag)
2012 Widget w;
2013 Boolean flag;
2015 XtVaSetValues (w, XtNallowShellResize, flag, NULL);
2018 /* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965
2019 (do not change this comment) */