Update maintainer.
[emacs.git] / lwlib / lwlib-Xm.c
blobe57fa57f93918f6123e79a78adc9cee372e9c54d
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 "../src/lisp.h"
36 #include "lwlib-Xm.h"
37 #include "lwlib-utils.h"
39 #include <Xm/BulletinB.h>
40 #include <Xm/CascadeB.h>
41 #include <Xm/CascadeBG.h>
42 #include <Xm/DrawingA.h>
43 #include <Xm/FileSB.h>
44 #include <Xm/Label.h>
45 #include <Xm/List.h>
46 #include <Xm/MainW.h>
47 #include <Xm/MenuShell.h>
48 #include <Xm/MessageB.h>
49 #include <Xm/PanedW.h>
50 #include <Xm/PushB.h>
51 #include <Xm/PushBG.h>
52 #include <Xm/ArrowB.h>
53 #include <Xm/SelectioB.h>
54 #include <Xm/Text.h>
55 #include <Xm/TextF.h>
56 #include <Xm/ToggleB.h>
57 #include <Xm/ToggleBG.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/ScrolledW.h>
60 #include <Xm/Separator.h>
61 #include <Xm/DialogS.h>
62 #include <Xm/Form.h>
64 #undef P_
65 #if defined __STDC__ || defined PROTOTYPES
66 #define P_(X) X
67 #else
68 #define P_(X) ()
69 #endif
71 enum do_call_type { pre_activate, selection, no_selection, post_activate };
74 \f/* Structures to keep destroyed instances */
75 typedef struct _destroyed_instance
77 char* name;
78 char* type;
79 Widget widget;
80 Widget parent;
81 Boolean pop_up_p;
82 struct _destroyed_instance* next;
83 } destroyed_instance;
85 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
86 Widget, Widget,
87 Boolean));
88 static void free_destroyed_instance P_ ((destroyed_instance*));
89 Widget first_child P_ ((Widget));
90 Boolean lw_motif_widget_p P_ ((Widget));
91 static XmString resource_motif_string P_ ((Widget, char *));
92 static void destroy_all_children P_ ((Widget, int));
93 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
94 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
95 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
96 widget_value *));
97 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
98 widget_value *));
99 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
100 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
101 static void make_menu_in_widget P_ ((widget_instance *, Widget,
102 widget_value *, int));
103 static void update_one_menu_entry P_ ((widget_instance *, Widget,
104 widget_value *, Boolean));
105 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
106 Boolean));
107 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
108 static void xm_update_text_field P_ ((widget_instance *, Widget,
109 widget_value *));
110 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
111 static void activate_button P_ ((Widget, XtPointer, XtPointer));
112 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
113 Boolean, Boolean, Boolean, int, int));
114 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
115 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
116 static void recenter_widget P_ ((Widget));
117 static Widget recycle_instance P_ ((destroyed_instance*));
118 Widget xm_create_dialog P_ ((widget_instance*));
119 static Widget make_menubar P_ ((widget_instance*));
120 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
121 static Widget make_popup_menu P_ ((widget_instance*));
122 static Widget make_main P_ ((widget_instance*));
123 void xm_destroy_instance P_ ((widget_instance*));
124 void xm_popup_menu P_ ((Widget, XEvent *));
125 static void set_min_dialog_size P_ ((Widget));
126 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
127 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
128 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
129 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
130 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
131 void xm_set_keyboard_focus P_ ((Widget, Widget));
132 void xm_set_main_areas P_ ((Widget, Widget, Widget));
133 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
134 XtPointer));
135 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
137 #if 0
138 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
139 Boolean));
140 void xm_pop_instance P_ ((widget_instance*, Boolean));
141 void xm_manage_resizing P_ ((Widget, Boolean));
142 #endif
145 #if 0
147 /* Print the complete X resource name of widget WIDGET to stderr.
148 This is sometimes handy to have available. */
150 void
151 x_print_complete_resource_name (widget)
152 Widget widget;
154 int i;
155 String names[100];
157 for (i = 0; i < 100 && widget != NULL; ++i)
159 names[i] = XtName (widget);
160 widget = XtParent (widget);
163 for (--i; i >= 1; --i)
164 fprintf (stderr, "%s.", names[i]);
165 fprintf (stderr, "%s\n", names[0]);
168 #endif /* 0 */
171 static destroyed_instance *all_destroyed_instances = NULL;
173 static destroyed_instance*
174 make_destroyed_instance (name, type, widget, parent, pop_up_p)
175 char* name;
176 char* type;
177 Widget widget;
178 Widget parent;
179 Boolean pop_up_p;
181 destroyed_instance* instance =
182 (destroyed_instance*)malloc (sizeof (destroyed_instance));
183 instance->name = safe_strdup (name);
184 instance->type = safe_strdup (type);
185 instance->widget = widget;
186 instance->parent = parent;
187 instance->pop_up_p = pop_up_p;
188 instance->next = NULL;
189 return instance;
192 static void
193 free_destroyed_instance (instance)
194 destroyed_instance* instance;
196 free (instance->name);
197 free (instance->type);
198 free (instance);
201 \f/* motif utility functions */
202 Widget
203 first_child (widget)
204 Widget widget;
206 return ((CompositeWidget)widget)->composite.children [0];
209 Boolean
210 lw_motif_widget_p (widget)
211 Widget widget;
213 return
214 XtClass (widget) == xmDialogShellWidgetClass
215 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
218 static XmString
219 resource_motif_string (widget, name)
220 Widget widget;
221 char* name;
223 XtResource resource;
224 XmString result = 0;
226 resource.resource_name = name;
227 resource.resource_class = XmCXmString;
228 resource.resource_type = XmRXmString;
229 resource.resource_size = sizeof (XmString);
230 resource.resource_offset = 0;
231 resource.default_type = XtRImmediate;
232 resource.default_addr = 0;
234 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
235 "DialogString", &resource, 1, NULL, 0);
236 return result;
239 /* Destroy all of the children of WIDGET
240 starting with number FIRST_CHILD_TO_DESTROY. */
242 static void
243 destroy_all_children (widget, first_child_to_destroy)
244 Widget widget;
245 int first_child_to_destroy;
247 Widget* children;
248 unsigned int number;
249 int i;
251 children = XtCompositeChildren (widget, &number);
252 if (children)
254 XtUnmanageChildren (children + first_child_to_destroy,
255 number - first_child_to_destroy);
257 /* Unmanage all children and destroy them. They will only be
258 really destroyed when we get out of DispatchEvent. */
259 for (i = first_child_to_destroy; i < number; i++)
261 Arg al[2];
262 Widget submenu = 0;
263 /* Cascade buttons have submenus,and these submenus
264 need to be freed. But they are not included in
265 XtCompositeChildren. So get it out of the cascade button
266 and free it. If this child is not a cascade button,
267 then submenu should remain unchanged. */
268 XtSetArg (al[0], XmNsubMenuId, &submenu);
269 XtGetValues (children[i], al, 1);
270 if (submenu)
272 destroy_all_children (submenu, 0);
273 XtDestroyWidget (submenu);
275 XtDestroyWidget (children[i]);
278 XtFree ((char *) children);
284 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
285 menu. CLIENT_DATA contains a pointer to the widget_value
286 corresponding to widget W. CALL_DATA contains a
287 XmPushButtonCallbackStruct containing the reason why the callback
288 is called. */
290 static void
291 xm_arm_callback (w, client_data, call_data)
292 Widget w;
293 XtPointer client_data, call_data;
295 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
296 widget_value *wv = (widget_value *) client_data;
297 widget_instance *instance;
299 /* Get the id of the menu bar or popup menu this widget is in. */
300 while (w != NULL)
302 if (XmIsRowColumn (w))
304 unsigned char type = 0xff;
306 XtVaGetValues (w, XmNrowColumnType, &type, NULL);
307 if (type == XmMENU_BAR || type == XmMENU_POPUP)
308 break;
311 w = XtParent (w);
314 if (w != NULL)
316 instance = lw_get_widget_instance (w);
317 if (instance && instance->info->highlight_cb)
319 call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
320 instance->info->highlight_cb (w, instance->info->id, call_data);
327 /* Update the label of widget WIDGET. WIDGET must be a Label widget
328 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
329 the value to update.
331 Menus:
333 Emacs fills VAL->name with the text to display in the menu, and
334 sets VAL->value to null. Function make_menu_in_widget creates
335 widgets with VAL->name as resource name. This works because the
336 Label widget uses its resource name for display if no
337 XmNlabelString is set.
339 Dialogs:
341 VAL->name is again set to the resource name, but VAL->value is
342 not null, and contains the label string to display. */
344 static void
345 xm_update_label (instance, widget, val)
346 widget_instance* instance;
347 Widget widget;
348 widget_value* val;
350 XmString res_string = 0;
351 XmString built_string = 0;
352 XmString key_string = 0;
353 Arg al [256];
354 int ac;
356 ac = 0;
358 if (val->value)
360 /* A label string is specified, i.e. we are in a dialog. First
361 see if it is overridden by something from the resource file. */
362 res_string = resource_motif_string (widget, val->value);
364 if (res_string)
366 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
368 else
370 built_string =
371 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
372 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
375 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
378 if (val->key)
380 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
381 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
384 if (ac)
385 XtSetValues (widget, al, ac);
387 if (built_string)
388 XmStringFree (built_string);
390 if (key_string)
391 XmStringFree (key_string);
394 \f/* update of list */
395 static void
396 xm_update_list (instance, widget, val)
397 widget_instance* instance;
398 Widget widget;
399 widget_value* val;
401 widget_value* cur;
402 int i;
403 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
404 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
405 instance);
406 for (cur = val->contents, i = 0; cur; cur = cur->next)
407 if (cur->value)
409 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
410 i += 1;
411 XmListAddItem (widget, xmstr, 0);
412 if (cur->selected)
413 XmListSelectPos (widget, i, False);
414 XmStringFree (xmstr);
418 \f/* update of buttons */
419 static void
420 xm_update_pushbutton (instance, widget, val)
421 widget_instance* instance;
422 Widget widget;
423 widget_value* val;
425 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
426 XtRemoveAllCallbacks (widget, XmNactivateCallback);
427 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
430 static void
431 xm_update_cascadebutton (instance, widget, val)
432 widget_instance* instance;
433 Widget widget;
434 widget_value* val;
436 /* Should also rebuild the menu by calling ...update_menu... */
437 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
438 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
439 instance);
442 \f/* update toggle and radiobox */
443 static void
444 xm_update_toggle (instance, widget, val)
445 widget_instance* instance;
446 Widget widget;
447 widget_value* val;
449 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
450 XtAddCallback (widget, XmNvalueChangedCallback,
451 xm_generic_callback, instance);
452 XtVaSetValues (widget, XmNset, val->selected,
453 XmNalignment, XmALIGNMENT_BEGINNING, NULL);
456 static void
457 xm_update_radiobox (instance, widget, val)
458 widget_instance* instance;
459 Widget widget;
460 widget_value* val;
463 Widget toggle;
464 widget_value* cur;
466 /* update the callback */
467 XtRemoveAllCallbacks (widget, XmNentryCallback);
468 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
470 /* first update all the toggles */
471 /* Energize kernel interface is currently bad. It sets the selected widget
472 with the selected flag but returns it by its name. So we currently
473 have to support both setting the selection with the selected slot
474 of val contents and setting it with the "value" slot of val. The latter
475 has a higher priority. This to be removed when the kernel is fixed. */
476 for (cur = val->contents; cur; cur = cur->next)
478 toggle = XtNameToWidget (widget, cur->value);
479 if (toggle)
481 XtSetSensitive (toggle, cur->enabled);
482 if (!val->value && cur->selected)
483 XtVaSetValues (toggle, XmNset, cur->selected, NULL);
484 if (val->value && strcmp (val->value, cur->value))
485 XtVaSetValues (toggle, XmNset, False, NULL);
489 /* The selected was specified by the value slot */
490 if (val->value)
492 toggle = XtNameToWidget (widget, val->value);
493 if (toggle)
494 XtVaSetValues (toggle, XmNset, True, NULL);
499 /* update a popup menu, pulldown menu or a menubar */
501 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
503 static void
504 make_menu_in_widget (instance, widget, val, keep_first_children)
505 widget_instance* instance;
506 Widget widget;
507 widget_value* val;
508 int keep_first_children;
510 Widget* children = 0;
511 int num_children;
512 int child_index;
513 widget_value* cur;
514 Widget button = 0;
515 Widget title = 0;
516 Widget menu;
517 Arg al [256];
518 int ac;
519 Boolean menubar_p;
520 unsigned char type;
522 Widget* old_children;
523 unsigned int old_num_children;
525 old_children = XtCompositeChildren (widget, &old_num_children);
527 /* Allocate the children array */
528 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
530 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
532 /* WIDGET should be a RowColumn. */
533 if (!XmIsRowColumn (widget))
534 abort ();
536 /* Determine whether WIDGET is a menu bar. */
537 type = -1;
538 XtSetArg (al[0], XmNrowColumnType, &type);
539 XtGetValues (widget, al, 1);
540 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
541 abort ();
542 menubar_p = type == XmMENU_BAR;
544 /* Add a callback to popups and pulldowns that is called when
545 it is made invisible again. */
546 if (!menubar_p)
547 XtAddCallback (XtParent (widget), XmNpopdownCallback,
548 xm_pop_down_callback, (XtPointer)instance);
550 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
551 for (child_index = 0, cur = val; child_index < keep_first_children;
552 child_index++, cur = cur->next)
553 children[child_index] = old_children[child_index];
555 /* Check that those are all we have
556 (the caller should have deleted the rest). */
557 if (old_num_children != keep_first_children)
558 abort ();
560 /* Create the rest. */
561 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
563 enum menu_separator separator;
565 ac = 0;
566 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
567 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
568 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
570 if (instance->pop_up_p && !cur->contents && !cur->call_data
571 && !lw_separator_p (cur->name, &separator, 1))
573 ac = 0;
574 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
575 title = button = XmCreateLabel (widget, cur->name, al, ac);
577 else if (lw_separator_p (cur->name, &separator, 1))
579 ac = 0;
580 XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
581 button = XmCreateSeparator (widget, cur->name, al, ac);
583 else if (!cur->contents)
585 if (menubar_p)
586 button = XmCreateCascadeButton (widget, cur->name, al, ac);
587 else if (!cur->call_data)
588 button = XmCreateLabel (widget, cur->name, al, ac);
589 else if (cur->button_type == BUTTON_TYPE_TOGGLE
590 || cur->button_type == BUTTON_TYPE_RADIO)
592 XtSetArg (al[ac], XmNset, cur->selected); ++ac;
593 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
594 XtSetArg (al[ac], XmNindicatorType,
595 (cur->button_type == BUTTON_TYPE_TOGGLE
596 ? XmN_OF_MANY : XmONE_OF_MANY));
597 ++ac;
598 button = XmCreateToggleButton (widget, cur->name, al, ac);
599 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
600 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
602 else
604 button = XmCreatePushButton (widget, cur->name, al, ac);
605 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
606 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
609 xm_update_label (instance, button, cur);
611 /* Add a callback that is called when the button is
612 selected. Toggle buttons don't support
613 XmNactivateCallback, we use XmNvalueChangedCallback in
614 that case. Don't add a callback to a simple label. */
615 if (cur->button_type)
616 xm_update_toggle (instance, button, cur);
617 else if (cur->call_data)
618 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
619 (XtPointer)instance);
621 else
623 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
625 make_menu_in_widget (instance, menu, cur->contents, 0);
626 XtSetArg (al[ac], XmNsubMenuId, menu); ac++;
627 button = XmCreateCascadeButton (widget, cur->name, al, ac);
629 xm_update_label (instance, button, cur);
631 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
632 (XtPointer)instance);
635 children[child_index] = button;
638 /* Last entry is the help button. The original comment read "Has to
639 be done after managing the buttons otherwise the menubar is only
640 4 pixels high." This is no longer true, and to make
641 XmNmenuHelpWidget work, we need to set it before managing the
642 children.. --gerd. */
643 if (button)
644 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL);
646 if (num_children)
647 XtManageChildren (children, num_children);
649 XtFree ((char *) children);
650 if (old_children)
651 XtFree ((char *) old_children);
654 static void
655 update_one_menu_entry (instance, widget, val, deep_p)
656 widget_instance* instance;
657 Widget widget;
658 widget_value* val;
659 Boolean deep_p;
661 Arg al [256];
662 int ac;
663 Widget menu;
664 widget_value* contents;
666 if (val->this_one_change == NO_CHANGE)
667 return;
669 /* update the sensitivity and userdata */
670 /* Common to all widget types */
671 XtSetSensitive (widget, val->enabled);
672 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
674 /* update the menu button as a label. */
675 if (val->this_one_change >= VISIBLE_CHANGE)
677 xm_update_label (instance, widget, val);
678 if (val->button_type)
679 xm_update_toggle (instance, widget, val);
682 /* update the pulldown/pullaside as needed */
683 ac = 0;
684 menu = NULL;
685 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
686 XtGetValues (widget, al, ac);
688 contents = val->contents;
690 if (!menu)
692 if (contents)
694 unsigned int old_num_children, i;
695 Widget parent;
696 Widget *widget_list;
698 parent = XtParent (widget);
699 widget_list = XtCompositeChildren (parent, &old_num_children);
701 /* Find the widget position within the parent's widget list. */
702 for (i = 0; i < old_num_children; i++)
703 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
704 break;
705 if (i == old_num_children)
706 abort ();
707 if (XmIsCascadeButton (widget_list[i]))
709 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
710 make_menu_in_widget (instance, menu, contents, 0);
711 ac = 0;
712 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
713 XtSetValues (widget, al, ac);
715 else
717 Widget button;
719 /* The current menuitem is a XmPushButtonGadget, it
720 needs to be replaced by a CascadeButtonGadget */
721 XtDestroyWidget (widget_list[i]);
722 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
723 make_menu_in_widget (instance, menu, contents, 0);
724 ac = 0;
725 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
726 /* Non-zero values don't work reliably in
727 conjunction with Emacs' event loop */
728 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
729 #ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
730 /* Tell Motif to put it in the right place */
731 XtSetArg (al [ac], XmNpositionIndex , i); ac++;
732 #endif
733 button = XmCreateCascadeButton (parent, val->name, al, ac);
734 xm_update_label (instance, button, val);
736 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
737 (XtPointer)instance);
738 XtManageChild (button);
741 if (widget_list)
742 XtFree ((char*) widget_list);
745 else if (!contents)
747 ac = 0;
748 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
749 XtSetValues (widget, al, ac);
750 XtDestroyWidget (menu);
752 else if (deep_p && contents->change != NO_CHANGE)
753 xm_update_menu (instance, menu, val, 1);
756 static void
757 xm_update_menu (instance, widget, val, deep_p)
758 widget_instance* instance;
759 Widget widget;
760 widget_value* val;
761 Boolean deep_p;
763 Widget* children;
764 unsigned int num_children;
765 int num_children_to_keep = 0;
766 int i;
767 widget_value* cur;
769 children = XtCompositeChildren (widget, &num_children);
771 /* Widget is a RowColumn widget whose contents have to be updated
772 * to reflect the list of items in val->contents */
774 /* See how many buttons we can keep, and how many we
775 must completely replace. */
776 if (val->contents == 0)
777 num_children_to_keep = 0;
778 else if (val->contents->change == STRUCTURAL_CHANGE)
780 if (children)
782 for (i = 0, cur = val->contents;
783 (i < num_children
784 && cur); /* how else to ditch unwanted children ?? - mgd */
785 i++, cur = cur->next)
787 if (cur->this_one_change == STRUCTURAL_CHANGE)
788 break;
791 num_children_to_keep = i;
794 else
795 num_children_to_keep = num_children;
797 /* Update all the buttons of the RowColumn, in order,
798 except for those we are going to replace entirely. */
799 if (children)
801 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
803 if (!cur)
805 num_children_to_keep = i;
806 break;
808 if (children [i]->core.being_destroyed
809 || strcmp (XtName (children [i]), cur->name))
810 continue;
811 update_one_menu_entry (instance, children [i], cur, deep_p);
812 cur = cur->next;
816 /* Now replace from scratch all the buttons after the last
817 place that the top-level structure changed. */
818 if (val->contents->change == STRUCTURAL_CHANGE)
820 destroy_all_children (widget, num_children_to_keep);
821 make_menu_in_widget (instance, widget, val->contents,
822 num_children_to_keep);
825 XtFree ((char *) children);
829 /* update text widgets */
831 static void
832 xm_update_text (instance, widget, val)
833 widget_instance* instance;
834 Widget widget;
835 widget_value* val;
837 XmTextSetString (widget, val->value ? val->value : "");
838 XtRemoveAllCallbacks (widget, XmNactivateCallback);
839 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
840 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
841 XtAddCallback (widget, XmNvalueChangedCallback,
842 xm_internal_update_other_instances, instance);
845 static void
846 xm_update_text_field (instance, widget, val)
847 widget_instance* instance;
848 Widget widget;
849 widget_value* val;
851 XmTextFieldSetString (widget, val->value ? val->value : "");
852 XtRemoveAllCallbacks (widget, XmNactivateCallback);
853 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
854 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
855 XtAddCallback (widget, XmNvalueChangedCallback,
856 xm_internal_update_other_instances, instance);
860 /* update a motif widget */
862 void
863 xm_update_one_widget (instance, widget, val, deep_p)
864 widget_instance* instance;
865 Widget widget;
866 widget_value* val;
867 Boolean deep_p;
869 WidgetClass class;
871 /* Mark as not edited */
872 val->edited = False;
874 /* Common to all widget types */
875 XtSetSensitive (widget, val->enabled);
876 XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
878 /* Common to all label like widgets */
879 if (XtIsSubclass (widget, xmLabelWidgetClass))
880 xm_update_label (instance, widget, val);
882 class = XtClass (widget);
883 /* Class specific things */
884 if (class == xmPushButtonWidgetClass ||
885 class == xmArrowButtonWidgetClass)
887 xm_update_pushbutton (instance, widget, val);
889 else if (class == xmCascadeButtonWidgetClass)
891 xm_update_cascadebutton (instance, widget, val);
893 else if (class == xmToggleButtonWidgetClass
894 || class == xmToggleButtonGadgetClass)
896 xm_update_toggle (instance, widget, val);
898 else if (class == xmRowColumnWidgetClass)
900 Boolean radiobox = 0;
901 int ac = 0;
902 Arg al [1];
904 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
905 XtGetValues (widget, al, ac);
907 if (radiobox)
908 xm_update_radiobox (instance, widget, val);
909 else
910 xm_update_menu (instance, widget, val, deep_p);
912 else if (class == xmTextWidgetClass)
914 xm_update_text (instance, widget, val);
916 else if (class == xmTextFieldWidgetClass)
918 xm_update_text_field (instance, widget, val);
920 else if (class == xmListWidgetClass)
922 xm_update_list (instance, widget, val);
926 \f/* getting the value back */
927 void
928 xm_update_one_value (instance, widget, val)
929 widget_instance* instance;
930 Widget widget;
931 widget_value* val;
933 WidgetClass class = XtClass (widget);
934 widget_value *old_wv;
936 /* copy the call_data slot into the "return" widget_value */
937 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
938 if (!strcmp (val->name, old_wv->name))
940 val->call_data = old_wv->call_data;
941 break;
944 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
946 XtVaGetValues (widget, XmNset, &val->selected, NULL);
947 val->edited = True;
949 else if (class == xmTextWidgetClass)
951 if (val->value)
952 free (val->value);
953 val->value = XmTextGetString (widget);
954 val->edited = True;
956 else if (class == xmTextFieldWidgetClass)
958 if (val->value)
959 free (val->value);
960 val->value = XmTextFieldGetString (widget);
961 val->edited = True;
963 else if (class == xmRowColumnWidgetClass)
965 Boolean radiobox = 0;
966 int ac = 0;
967 Arg al [1];
969 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
970 XtGetValues (widget, al, ac);
972 if (radiobox)
974 CompositeWidget radio = (CompositeWidget)widget;
975 int i;
976 for (i = 0; i < radio->composite.num_children; i++)
978 int set = False;
979 Widget toggle = radio->composite.children [i];
981 XtVaGetValues (toggle, XmNset, &set, NULL);
982 if (set)
984 if (val->value)
985 free (val->value);
986 val->value = safe_strdup (XtName (toggle));
989 val->edited = True;
992 else if (class == xmListWidgetClass)
994 int pos_cnt;
995 int* pos_list;
996 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
998 int i;
999 widget_value* cur;
1000 for (cur = val->contents, i = 0; cur; cur = cur->next)
1001 if (cur->value)
1003 int j;
1004 cur->selected = False;
1005 i += 1;
1006 for (j = 0; j < pos_cnt; j++)
1007 if (pos_list [j] == i)
1009 cur->selected = True;
1010 val->value = safe_strdup (cur->name);
1013 val->edited = 1;
1014 XtFree ((char *) pos_list);
1020 /* This function is for activating a button from a program. It's wrong because
1021 we pass a NULL argument in the call_data which is not Motif compatible.
1022 This is used from the XmNdefaultAction callback of the List widgets to
1023 have a double-click put down a dialog box like the button would do.
1024 I could not find a way to do that with accelerators.
1026 static void
1027 activate_button (widget, closure, call_data)
1028 Widget widget;
1029 XtPointer closure;
1030 XtPointer call_data;
1032 Widget button = (Widget)closure;
1033 XtCallCallbacks (button, XmNactivateCallback, NULL);
1036 /* creation functions */
1038 /* Called for key press in dialogs. Used to pop down dialog on ESC. */
1039 static void
1040 dialog_key_cb (widget, closure, event, continue_to_dispatch)
1041 Widget widget;
1042 XtPointer closure;
1043 XEvent *event;
1044 Boolean *continue_to_dispatch;
1046 KeySym sym = 0;
1047 Modifiers modif_ret;
1049 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0,
1050 &modif_ret, &sym);
1052 if (sym == osfXK_Cancel)
1054 Widget w = *((Widget *) closure);
1056 while (w && ! XtIsShell (w))
1057 w = XtParent (w);
1059 if (XtIsShell (w)) XtPopdown (w);
1062 *continue_to_dispatch = TRUE;
1065 /* dialogs */
1066 static Widget
1067 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1068 radio_box, list, left_buttons, right_buttons)
1069 char* name;
1070 Widget parent;
1071 Boolean pop_up_p;
1072 char* shell_title;
1073 char* icon_name;
1074 Boolean text_input_slot;
1075 Boolean radio_box;
1076 Boolean list;
1077 int left_buttons;
1078 int right_buttons;
1080 Widget result;
1081 Widget form;
1082 Widget row;
1083 Widget icon;
1084 Widget icon_separator;
1085 Widget message;
1086 Widget value = 0;
1087 Widget separator;
1088 Widget button = 0;
1089 Widget children [16]; /* for the final XtManageChildren */
1090 int n_children;
1091 Arg al[64]; /* Arg List */
1092 int ac; /* Arg Count */
1093 int i;
1095 if (pop_up_p)
1097 ac = 0;
1098 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1099 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1100 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1101 result = XmCreateDialogShell (parent, "dialog", al, ac);
1102 ac = 0;
1103 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1104 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1105 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1106 form = XmCreateForm (result, shell_title, al, ac);
1108 else
1110 ac = 0;
1111 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1112 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1113 form = XmCreateForm (parent, shell_title, al, ac);
1114 result = form;
1117 n_children = left_buttons + right_buttons + 1;
1118 ac = 0;
1119 XtSetArg(al[ac], XmNpacking, n_children == 3?
1120 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
1121 XtSetArg(al[ac], XmNorientation, n_children == 3?
1122 XmVERTICAL: XmHORIZONTAL); ac++;
1123 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1124 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1125 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1126 XtSetArg(al[ac], XmNspacing, 13); ac++;
1127 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1128 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1129 XtSetArg(al[ac], XmNisAligned, True); ac++;
1130 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1131 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1132 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1133 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1134 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1135 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1136 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1137 row = XmCreateRowColumn (form, "row", al, ac);
1139 n_children = 0;
1140 for (i = 0; i < left_buttons; i++)
1142 char button_name [16];
1143 sprintf (button_name, "button%d", i + 1);
1144 ac = 0;
1145 if (i == 0)
1147 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1148 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1150 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1151 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1152 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1153 XtAddEventHandler (children [n_children],
1154 KeyPressMask, False, dialog_key_cb, result);
1156 if (i == 0)
1158 button = children [n_children];
1159 ac = 0;
1160 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1161 XtSetValues (row, al, ac);
1164 n_children++;
1167 /* invisible separator button */
1168 ac = 0;
1169 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1170 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1171 n_children++;
1173 for (i = 0; i < right_buttons; i++)
1175 char button_name [16];
1176 sprintf (button_name, "button%d", left_buttons + i + 1);
1177 ac = 0;
1178 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
1179 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1180 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1181 XtAddEventHandler (children [n_children],
1182 KeyPressMask, False, dialog_key_cb, result);
1184 if (! button) button = children [n_children];
1185 n_children++;
1188 XtManageChildren (children, n_children);
1190 ac = 0;
1191 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1192 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1193 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1194 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1195 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1196 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1197 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1198 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1199 separator = XmCreateSeparator (form, "", al, ac);
1201 ac = 0;
1202 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1203 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1204 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1205 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1206 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1207 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1208 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1209 icon = XmCreateLabel (form, icon_name, al, ac);
1211 ac = 0;
1212 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1213 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1214 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1215 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1216 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1217 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1218 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1219 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1220 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1221 icon_separator = XmCreateLabel (form, "", al, ac);
1223 if (text_input_slot)
1225 ac = 0;
1226 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1227 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1228 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1229 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1230 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1231 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1232 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1233 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1234 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1235 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1236 value = XmCreateTextField (form, "value", al, ac);
1238 else if (radio_box)
1240 Widget radio_butt;
1241 ac = 0;
1242 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1243 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1244 XtSetArg(al[ac], XmNspacing, 13); ac++;
1245 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1246 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1247 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1248 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1249 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1250 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1251 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1252 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1253 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1254 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1255 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1256 ac = 0;
1257 i = 0;
1258 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1259 children [i++] = radio_butt;
1260 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1261 children [i++] = radio_butt;
1262 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1263 children [i++] = radio_butt;
1264 XtManageChildren (children, i);
1266 else if (list)
1268 ac = 0;
1269 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1270 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1271 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1272 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1273 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1274 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1275 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1276 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1277 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1278 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1279 value = XmCreateScrolledList (form, "list", al, ac);
1281 /* this is the easiest way I found to have the dble click in the
1282 list activate the default button */
1283 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1286 ac = 0;
1287 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1288 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1289 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1290 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1291 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1292 XtSetArg(al[ac], XmNbottomWidget,
1293 text_input_slot || radio_box || list ? value : separator); ac++;
1294 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1295 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1296 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1297 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1298 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1299 message = XmCreateLabel (form, "message", al, ac);
1301 if (list)
1302 XtManageChild (value);
1304 i = 0;
1305 children [i] = row; i++;
1306 children [i] = separator; i++;
1307 if (text_input_slot || radio_box)
1309 children [i] = value; i++;
1311 children [i] = message; i++;
1312 children [i] = icon; i++;
1313 children [i] = icon_separator; i++;
1314 XtManageChildren (children, i);
1316 if (text_input_slot || list)
1318 XtInstallAccelerators (value, button);
1319 XtSetKeyboardFocus (result, value);
1321 else
1323 XtInstallAccelerators (form, button);
1324 XtSetKeyboardFocus (result, button);
1327 return result;
1330 static destroyed_instance*
1331 find_matching_instance (instance)
1332 widget_instance* instance;
1334 destroyed_instance* cur;
1335 destroyed_instance* prev;
1336 char* type = instance->info->type;
1337 char* name = instance->info->name;
1339 for (prev = NULL, cur = all_destroyed_instances;
1340 cur;
1341 prev = cur, cur = cur->next)
1343 if (!strcmp (cur->name, name)
1344 && !strcmp (cur->type, type)
1345 && cur->parent == instance->parent
1346 && cur->pop_up_p == instance->pop_up_p)
1348 if (prev)
1349 prev->next = cur->next;
1350 else
1351 all_destroyed_instances = cur->next;
1352 return cur;
1354 /* do some cleanup */
1355 else if (!cur->widget)
1357 if (prev)
1358 prev->next = cur->next;
1359 else
1360 all_destroyed_instances = cur->next;
1361 free_destroyed_instance (cur);
1362 cur = prev ? prev : all_destroyed_instances;
1365 return NULL;
1368 static void
1369 mark_dead_instance_destroyed (widget, closure, call_data)
1370 Widget widget;
1371 XtPointer closure;
1372 XtPointer call_data;
1374 destroyed_instance* instance = (destroyed_instance*)closure;
1375 instance->widget = NULL;
1378 static void
1379 recenter_widget (widget)
1380 Widget widget;
1382 Widget parent = XtParent (widget);
1383 Screen* screen = XtScreen (widget);
1384 Dimension screen_width = WidthOfScreen (screen);
1385 Dimension screen_height = HeightOfScreen (screen);
1386 Dimension parent_width = 0;
1387 Dimension parent_height = 0;
1388 Dimension child_width = 0;
1389 Dimension child_height = 0;
1390 Position x;
1391 Position y;
1393 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
1394 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1395 NULL);
1397 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1398 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1400 XtTranslateCoords (parent, x, y, &x, &y);
1402 if (x + child_width > screen_width)
1403 x = screen_width - child_width;
1404 if (x < 0)
1405 x = 0;
1407 if (y + child_height > screen_height)
1408 y = screen_height - child_height;
1409 if (y < 0)
1410 y = 0;
1412 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
1415 static Widget
1416 recycle_instance (instance)
1417 destroyed_instance* instance;
1419 Widget widget = instance->widget;
1421 /* widget is NULL if the parent was destroyed. */
1422 if (widget)
1424 Widget focus;
1425 Widget separator;
1427 /* Remove the destroy callback as the instance is not in the list
1428 anymore */
1429 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1430 mark_dead_instance_destroyed,
1431 (XtPointer)instance);
1433 /* Give the focus to the initial item */
1434 focus = XtNameToWidget (widget, "*value");
1435 if (!focus)
1436 focus = XtNameToWidget (widget, "*button1");
1437 if (focus)
1438 XtSetKeyboardFocus (widget, focus);
1440 /* shrink the separator label back to their original size */
1441 separator = XtNameToWidget (widget, "*separator_button");
1442 if (separator)
1443 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
1445 /* Center the dialog in its parent */
1446 recenter_widget (widget);
1448 free_destroyed_instance (instance);
1449 return widget;
1452 Widget
1453 xm_create_dialog (instance)
1454 widget_instance* instance;
1456 char* name = instance->info->type;
1457 Widget parent = instance->parent;
1458 Widget widget;
1459 Boolean pop_up_p = instance->pop_up_p;
1460 char* shell_name = 0;
1461 char* icon_name = 0;
1462 Boolean text_input_slot = False;
1463 Boolean radio_box = False;
1464 Boolean list = False;
1465 int total_buttons;
1466 int left_buttons = 0;
1467 int right_buttons = 1;
1468 destroyed_instance* dead_one;
1470 /* try to find a widget to recycle */
1471 dead_one = find_matching_instance (instance);
1472 if (dead_one)
1474 Widget recycled_widget = recycle_instance (dead_one);
1475 if (recycled_widget)
1476 return recycled_widget;
1479 switch (name [0]){
1480 case 'E': case 'e':
1481 icon_name = "dbox-error";
1482 shell_name = "Error";
1483 break;
1485 case 'I': case 'i':
1486 icon_name = "dbox-info";
1487 shell_name = "Information";
1488 break;
1490 case 'L': case 'l':
1491 list = True;
1492 icon_name = "dbox-question";
1493 shell_name = "Prompt";
1494 break;
1496 case 'P': case 'p':
1497 text_input_slot = True;
1498 icon_name = "dbox-question";
1499 shell_name = "Prompt";
1500 break;
1502 case 'Q': case 'q':
1503 icon_name = "dbox-question";
1504 shell_name = "Question";
1505 break;
1508 total_buttons = name [1] - '0';
1510 if (name [3] == 'T' || name [3] == 't')
1512 text_input_slot = False;
1513 radio_box = True;
1515 else if (name [3])
1516 right_buttons = name [4] - '0';
1518 left_buttons = total_buttons - right_buttons;
1520 widget = make_dialog (name, parent, pop_up_p,
1521 shell_name, icon_name, text_input_slot, radio_box,
1522 list, left_buttons, right_buttons);
1524 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1525 (XtPointer) instance);
1527 return widget;
1530 /* Create a menu bar. We turn off the f10 key
1531 because we have not yet managed to make it work right in Motif. */
1533 static Widget
1534 make_menubar (instance)
1535 widget_instance* instance;
1537 Arg al[3];
1538 int ac;
1540 ac = 0;
1541 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1542 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1545 static void
1546 remove_grabs (shell, closure, call_data)
1547 Widget shell;
1548 XtPointer closure;
1549 XtPointer call_data;
1551 Widget menu = (Widget) closure;
1552 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1555 static Widget
1556 make_popup_menu (instance)
1557 widget_instance* instance;
1559 Widget parent = instance->parent;
1560 Window parent_window = parent->core.window;
1561 Widget result;
1563 /* sets the parent window to 0 to fool Motif into not generating a grab */
1564 parent->core.window = 0;
1565 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1566 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1567 (XtPointer)result);
1568 parent->core.window = parent_window;
1569 return result;
1572 static Widget
1573 make_main (instance)
1574 widget_instance* instance;
1576 Widget parent = instance->parent;
1577 Widget result;
1578 Arg al[2];
1579 int ac;
1581 ac = 0;
1582 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1583 XtSetArg (al[ac], XmNspacing, 0); ac++;
1584 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1585 return result;
1588 \f/* Table of functions to create widgets */
1590 #ifdef ENERGIZE
1592 /* interface with the XDesigner generated functions */
1593 typedef Widget (*widget_maker) (Widget);
1594 extern Widget create_project_p_sheet (Widget parent);
1595 extern Widget create_debugger_p_sheet (Widget parent);
1596 extern Widget create_breaklist_p_sheet (Widget parent);
1597 extern Widget create_le_browser_p_sheet (Widget parent);
1598 extern Widget create_class_browser_p_sheet (Widget parent);
1599 extern Widget create_call_browser_p_sheet (Widget parent);
1600 extern Widget create_build_dialog (Widget parent);
1601 extern Widget create_editmode_dialog (Widget parent);
1602 extern Widget create_search_dialog (Widget parent);
1603 extern Widget create_project_display_dialog (Widget parent);
1605 static Widget
1606 make_one (widget_instance* instance, widget_maker fn)
1608 Widget result;
1609 Arg al [64];
1610 int ac = 0;
1612 if (instance->pop_up_p)
1614 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1615 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1616 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1617 (XtPointer) instance);
1618 (*fn) (result);
1620 else
1622 result = (*fn) (instance->parent);
1623 XtRealizeWidget (result);
1625 return result;
1628 static Widget
1629 make_project_p_sheet (widget_instance* instance)
1631 return make_one (instance, create_project_p_sheet);
1634 static Widget
1635 make_debugger_p_sheet (widget_instance* instance)
1637 return make_one (instance, create_debugger_p_sheet);
1640 static Widget
1641 make_breaklist_p_sheet (widget_instance* instance)
1643 return make_one (instance, create_breaklist_p_sheet);
1646 static Widget
1647 make_le_browser_p_sheet (widget_instance* instance)
1649 return make_one (instance, create_le_browser_p_sheet);
1652 static Widget
1653 make_class_browser_p_sheet (widget_instance* instance)
1655 return make_one (instance, create_class_browser_p_sheet);
1658 static Widget
1659 make_call_browser_p_sheet (widget_instance* instance)
1661 return make_one (instance, create_call_browser_p_sheet);
1664 static Widget
1665 make_build_dialog (widget_instance* instance)
1667 return make_one (instance, create_build_dialog);
1670 static Widget
1671 make_editmode_dialog (widget_instance* instance)
1673 return make_one (instance, create_editmode_dialog);
1676 static Widget
1677 make_search_dialog (widget_instance* instance)
1679 return make_one (instance, create_search_dialog);
1682 static Widget
1683 make_project_display_dialog (widget_instance* instance)
1685 return make_one (instance, create_project_display_dialog);
1688 #endif /* ENERGIZE */
1690 widget_creation_entry
1691 xm_creation_table [] =
1693 {"menubar", make_menubar},
1694 {"popup", make_popup_menu},
1695 {"main", make_main},
1696 #ifdef ENERGIZE
1697 {"project_p_sheet", make_project_p_sheet},
1698 {"debugger_p_sheet", make_debugger_p_sheet},
1699 {"breaklist_psheet", make_breaklist_p_sheet},
1700 {"leb_psheet", make_le_browser_p_sheet},
1701 {"class_browser_psheet", make_class_browser_p_sheet},
1702 {"ctree_browser_psheet", make_call_browser_p_sheet},
1703 {"build", make_build_dialog},
1704 {"editmode", make_editmode_dialog},
1705 {"search", make_search_dialog},
1706 {"project_display", make_project_display_dialog},
1707 #endif /* ENERGIZE */
1708 {NULL, NULL}
1711 \f/* Destruction of instances */
1712 void
1713 xm_destroy_instance (instance)
1714 widget_instance* instance;
1716 Widget widget = instance->widget;
1717 /* recycle the dialog boxes */
1718 /* Disable the recycling until we can find a way to have the dialog box
1719 get reasonable layout after we modify its contents. */
1720 if (0
1721 && XtClass (widget) == xmDialogShellWidgetClass)
1723 destroyed_instance* dead_instance =
1724 make_destroyed_instance (instance->info->name,
1725 instance->info->type,
1726 instance->widget,
1727 instance->parent,
1728 instance->pop_up_p);
1729 dead_instance->next = all_destroyed_instances;
1730 all_destroyed_instances = dead_instance;
1731 XtUnmanageChild (first_child (instance->widget));
1732 XFlush (XtDisplay (instance->widget));
1733 XtAddCallback (instance->parent, XtNdestroyCallback,
1734 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1736 else
1738 /* This might not be necessary now that the nosel is attached to
1739 popdown instead of destroy, but it can't hurt. */
1740 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1741 xm_nosel_callback, (XtPointer)instance);
1742 XtDestroyWidget (instance->widget);
1746 \f/* popup utility */
1747 void
1748 xm_popup_menu (widget, event)
1749 Widget widget;
1750 XEvent *event;
1752 XButtonPressedEvent dummy;
1754 if (event == 0)
1756 dummy.type = ButtonPress;
1757 dummy.serial = 0;
1758 dummy.send_event = 0;
1759 dummy.display = XtDisplay (widget);
1760 dummy.window = XtWindow (XtParent (widget));
1761 dummy.time = 0;
1762 dummy.button = 0;
1763 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1764 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1765 &dummy.x, &dummy.y, &dummy.state);
1766 event = (XEvent *) &dummy;
1769 if (event->type == ButtonPress || event->type == ButtonRelease)
1771 /* Setting the menuPost resource only required by Motif 1.1 and
1772 LessTif 0.84 and earlier. With later versions of LessTif,
1773 setting menuPost is unnecessary and may cause problems, so
1774 don't do it. */
1775 #if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1777 /* This is so totally ridiculous: there's NO WAY to tell Motif
1778 that *any* button can select a menu item. Only one button
1779 can have that honor. */
1781 char *trans = 0;
1782 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1783 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1784 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1785 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1786 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1787 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1789 #endif
1791 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1794 XtManageChild (widget);
1797 static void
1798 set_min_dialog_size (w)
1799 Widget w;
1801 short width;
1802 short height;
1803 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1804 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
1807 void
1808 xm_pop_instance (instance, up)
1809 widget_instance* instance;
1810 Boolean up;
1812 Widget widget = instance->widget;
1814 if (XtClass (widget) == xmDialogShellWidgetClass)
1816 Widget widget_to_manage = first_child (widget);
1817 if (up)
1819 XtManageChild (widget_to_manage);
1820 set_min_dialog_size (widget);
1821 XtSetKeyboardFocus (instance->parent, widget);
1823 else
1824 XtUnmanageChild (widget_to_manage);
1826 else
1828 if (up)
1829 XtManageChild (widget);
1830 else
1831 XtUnmanageChild (widget);
1836 /* motif callback */
1838 static void
1839 do_call (widget, closure, type)
1840 Widget widget;
1841 XtPointer closure;
1842 enum do_call_type type;
1844 Arg al [256];
1845 int ac;
1846 XtPointer user_data;
1847 widget_instance* instance = (widget_instance*)closure;
1848 Widget instance_widget;
1849 LWLIB_ID id;
1851 if (!instance)
1852 return;
1853 if (widget->core.being_destroyed)
1854 return;
1856 instance_widget = instance->widget;
1857 if (!instance_widget)
1858 return;
1860 id = instance->info->id;
1861 ac = 0;
1862 user_data = NULL;
1863 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1864 XtGetValues (widget, al, ac);
1866 switch (type)
1868 case pre_activate:
1869 if (instance->info->pre_activate_cb)
1870 instance->info->pre_activate_cb (widget, id, user_data);
1871 break;
1873 case selection:
1874 if (instance->info->selection_cb)
1875 instance->info->selection_cb (widget, id, user_data);
1876 break;
1878 case no_selection:
1879 if (instance->info->selection_cb)
1880 instance->info->selection_cb (widget, id, (XtPointer) -1);
1881 break;
1883 case post_activate:
1884 if (instance->info->post_activate_cb)
1885 instance->info->post_activate_cb (widget, id, user_data);
1886 break;
1888 default:
1889 abort ();
1893 /* Like lw_internal_update_other_instances except that it does not do
1894 anything if its shell parent is not managed. This is to protect
1895 lw_internal_update_other_instances to dereference freed memory
1896 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1897 list */
1898 static void
1899 xm_internal_update_other_instances (widget, closure, call_data)
1900 Widget widget;
1901 XtPointer closure;
1902 XtPointer call_data;
1904 Widget parent;
1905 for (parent = widget; parent; parent = XtParent (parent))
1906 if (XtIsShell (parent))
1907 break;
1908 else if (!XtIsManaged (parent))
1909 return;
1910 lw_internal_update_other_instances (widget, closure, call_data);
1913 static void
1914 xm_generic_callback (widget, closure, call_data)
1915 Widget widget;
1916 XtPointer closure;
1917 XtPointer call_data;
1919 lw_internal_update_other_instances (widget, closure, call_data);
1920 do_call (widget, closure, selection);
1923 static void
1924 xm_nosel_callback (widget, closure, call_data)
1925 Widget widget;
1926 XtPointer closure;
1927 XtPointer call_data;
1929 /* This callback is only called when a dialog box is dismissed with
1930 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1931 box to be destroyed in that case, not just unmapped, so that it
1932 releases its keyboard grabs. But there are problems with running
1933 our callbacks while the widget is in the process of being
1934 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1935 XmDESTROY and then destroy it ourself after having run the
1936 callback. */
1937 do_call (widget, closure, no_selection);
1938 XtDestroyWidget (widget);
1941 static void
1942 xm_pull_down_callback (widget, closure, call_data)
1943 Widget widget;
1944 XtPointer closure;
1945 XtPointer call_data;
1947 Widget parent = XtParent (widget);
1949 if (XmIsRowColumn (parent))
1951 unsigned char type = 0xff;
1952 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1953 if (type == XmMENU_BAR)
1954 do_call (widget, closure, pre_activate);
1959 /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
1960 CLOSURE is a pointer to the widget_instance of the shell,
1962 Note that this callback is called for each cascade button in a
1963 menu, whether or not its submenu is visible. */
1965 static void
1966 xm_pop_down_callback (widget, closure, call_data)
1967 Widget widget;
1968 XtPointer closure;
1969 XtPointer call_data;
1971 widget_instance *instance = (widget_instance *) closure;
1973 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1974 || XtParent (widget) == instance->parent)
1975 do_call (widget, closure, post_activate);
1979 /* set the keyboard focus */
1980 void
1981 xm_set_keyboard_focus (parent, w)
1982 Widget parent;
1983 Widget w;
1985 XmProcessTraversal (w, 0);
1986 XtSetKeyboardFocus (parent, w);
1989 /* Motif hack to set the main window areas. */
1990 void
1991 xm_set_main_areas (parent, menubar, work_area)
1992 Widget parent;
1993 Widget menubar;
1994 Widget work_area;
1996 XmMainWindowSetAreas (parent,
1997 menubar, /* menubar (maybe 0) */
1998 0, /* command area (psheets) */
1999 0, /* horizontal scroll */
2000 0, /* vertical scroll */
2001 work_area); /* work area */
2004 /* Motif hack to control resizing on the menubar. */
2005 void
2006 xm_manage_resizing (w, flag)
2007 Widget w;
2008 Boolean flag;
2010 XtVaSetValues (w, XtNallowShellResize, flag, NULL);
2013 /* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965
2014 (do not change this comment) */