(do-auto-fill): Do break after one word as last resort
[emacs.git] / lwlib / lwlib-Xm.c
blob2050c2957550e1ed9ef3d894f34f18798f19f5ea
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 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdio.h>
26 #include <X11/StringDefs.h>
27 #include <X11/IntrinsicP.h>
28 #include <X11/ObjectP.h>
29 #include <X11/CoreP.h>
30 #include <X11/CompositeP.h>
32 #include "lwlib-Xm.h"
33 #include "lwlib-utils.h"
35 #include <Xm/BulletinB.h>
36 #include <Xm/CascadeB.h>
37 #include <Xm/CascadeBG.h>
38 #include <Xm/DrawingA.h>
39 #include <Xm/FileSB.h>
40 #include <Xm/Label.h>
41 #include <Xm/List.h>
42 #include <Xm/MainW.h>
43 #include <Xm/MenuShell.h>
44 #include <Xm/MessageB.h>
45 #include <Xm/PanedW.h>
46 #include <Xm/PushB.h>
47 #include <Xm/PushBG.h>
48 #include <Xm/ArrowB.h>
49 #include <Xm/SelectioB.h>
50 #include <Xm/Text.h>
51 #include <Xm/TextF.h>
52 #include <Xm/ToggleB.h>
53 #include <Xm/ToggleBG.h>
54 #include <Xm/RowColumn.h>
55 #include <Xm/ScrolledW.h>
56 #include <Xm/Separator.h>
57 #include <Xm/DialogS.h>
58 #include <Xm/Form.h>
60 static void xm_pull_down_callback (/* Widget, XtPointer, XtPointer */);
61 static void xm_internal_update_other_instances (/* Widget, XtPointer,
62 XtPointer */);
63 static void xm_generic_callback (/* Widget, XtPointer, XtPointer */);
64 static void xm_nosel_callback (/* Widget, XtPointer, XtPointer */);
65 static void xm_pop_down_callback (/* Widget, XtPointer, XtPointer */);
67 static void xm_update_menu (/* widget_instance*, Widget, widget_value*,
68 Boolean) */);
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance*
83 all_destroyed_instances = NULL;
85 static destroyed_instance*
86 make_destroyed_instance (name, type, widget, parent, pop_up_p)
87 char* name;
88 char* type;
89 Widget widget;
90 Widget parent;
91 Boolean pop_up_p;
93 destroyed_instance* instance =
94 (destroyed_instance*)malloc (sizeof (destroyed_instance));
95 instance->name = safe_strdup (name);
96 instance->type = safe_strdup (type);
97 instance->widget = widget;
98 instance->parent = parent;
99 instance->pop_up_p = pop_up_p;
100 instance->next = NULL;
101 return instance;
104 static void
105 free_destroyed_instance (instance)
106 destroyed_instance* instance;
108 free (instance->name);
109 free (instance->type);
110 free (instance);
113 \f/* motif utility functions */
114 Widget
115 first_child (widget)
116 Widget widget;
118 return ((CompositeWidget)widget)->composite.children [0];
121 Boolean
122 lw_motif_widget_p (widget)
123 Widget widget;
125 return
126 XtClass (widget) == xmDialogShellWidgetClass
127 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
130 static XmString
131 resource_motif_string (widget, name)
132 Widget widget;
133 char* name;
135 XtResource resource;
136 XmString result = 0;
138 resource.resource_name = name;
139 resource.resource_class = XmCXmString;
140 resource.resource_type = XmRXmString;
141 resource.resource_size = sizeof (XmString);
142 resource.resource_offset = 0;
143 resource.default_type = XtRImmediate;
144 resource.default_addr = 0;
146 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
147 "DialogString", &resource, 1, NULL, 0);
148 return result;
151 /* Destroy all of the children of WIDGET
152 starting with number FIRST_CHILD_TO_DESTROY. */
154 static void
155 destroy_all_children (widget, first_child_to_destroy)
156 Widget widget;
157 int first_child_to_destroy;
159 Widget* children;
160 unsigned int number;
161 int i;
163 children = XtCompositeChildren (widget, &number);
164 if (children)
166 XtUnmanageChildren (children + first_child_to_destroy,
167 number - first_child_to_destroy);
169 /* Unmanage all children and destroy them. They will only be
170 really destroyed when we get out of DispatchEvent. */
171 for (i = first_child_to_destroy; i < number; i++)
173 Arg al[2];
174 Widget submenu = 0;
175 /* Cascade buttons have submenus,and these submenus
176 need to be freed. But they are not included in
177 XtCompositeChildren. So get it out of the cascade button
178 and free it. If this child is not a cascade button,
179 then submenu should remain unchanged. */
180 XtSetArg (al[0], XmNsubMenuId, &submenu);
181 XtGetValues (children[i], al, 1);
182 if (submenu)
183 XtDestroyWidget (submenu);
184 XtDestroyWidget (children[i]);
187 XtFree ((char *) children);
191 \f/* update the label of anything subclass of a label */
192 static void
193 xm_update_label (instance, widget, val)
194 widget_instance* instance;
195 Widget widget;
196 widget_value* val;
198 XmString res_string = 0;
199 XmString built_string = 0;
200 XmString key_string = 0;
201 Arg al [256];
202 int ac;
204 ac = 0;
206 if (val->value)
208 res_string = resource_motif_string (widget, val->value);
210 if (res_string)
212 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
214 else
216 built_string =
217 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
218 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
220 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
223 if (val->key)
225 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
226 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
229 if (ac)
230 XtSetValues (widget, al, ac);
232 if (built_string)
233 XmStringFree (built_string);
235 if (key_string)
236 XmStringFree (key_string);
239 \f/* update of list */
240 static void
241 xm_update_list (instance, widget, val)
242 widget_instance* instance;
243 Widget widget;
244 widget_value* val;
246 widget_value* cur;
247 int i;
248 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
249 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
250 instance);
251 for (cur = val->contents, i = 0; cur; cur = cur->next)
252 if (cur->value)
254 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
255 i += 1;
256 XmListAddItem (widget, xmstr, 0);
257 if (cur->selected)
258 XmListSelectPos (widget, i, False);
259 XmStringFree (xmstr);
263 \f/* update of buttons */
264 static void
265 xm_update_pushbutton (instance, widget, val)
266 widget_instance* instance;
267 Widget widget;
268 widget_value* val;
270 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
271 XtRemoveAllCallbacks (widget, XmNactivateCallback);
272 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
275 static void
276 xm_update_cascadebutton (instance, widget, val)
277 widget_instance* instance;
278 Widget widget;
279 widget_value* val;
281 /* Should also rebuild the menu by calling ...update_menu... */
282 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
283 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
284 instance);
287 \f/* update toggle and radiobox */
288 static void
289 xm_update_toggle (instance, widget, val)
290 widget_instance* instance;
291 Widget widget;
292 widget_value* val;
294 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
295 XtAddCallback (widget, XmNvalueChangedCallback,
296 xm_internal_update_other_instances, instance);
297 XtVaSetValues (widget, XmNset, val->selected,
298 XmNalignment, XmALIGNMENT_BEGINNING, 0);
301 static void
302 xm_update_radiobox (instance, widget, val)
303 widget_instance* instance;
304 Widget widget;
305 widget_value* val;
308 Widget toggle;
309 widget_value* cur;
311 /* update the callback */
312 XtRemoveAllCallbacks (widget, XmNentryCallback);
313 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
315 /* first update all the toggles */
316 /* Energize kernel interface is currently bad. It sets the selected widget
317 with the selected flag but returns it by its name. So we currently
318 have to support both setting the selection with the selected slot
319 of val contents and setting it with the "value" slot of val. The latter
320 has a higher priority. This to be removed when the kernel is fixed. */
321 for (cur = val->contents; cur; cur = cur->next)
323 toggle = XtNameToWidget (widget, cur->value);
324 if (toggle)
326 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
327 if (!val->value && cur->selected)
328 XtVaSetValues (toggle, XmNset, cur->selected, 0);
329 if (val->value && strcmp (val->value, cur->value))
330 XtVaSetValues (toggle, XmNset, False, 0);
334 /* The selected was specified by the value slot */
335 if (val->value)
337 toggle = XtNameToWidget (widget, val->value);
338 if (toggle)
339 XtVaSetValues (toggle, XmNset, True, 0);
343 \f/* update a popup menu, pulldown menu or a menubar */
344 static Boolean
345 all_dashes_p (s)
346 char* s;
348 char* t;
349 for (t = s; *t; t++)
350 if (*t != '-')
351 return False;
352 return True;
355 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
357 static void
358 make_menu_in_widget (instance, widget, val, keep_first_children)
359 widget_instance* instance;
360 Widget widget;
361 widget_value* val;
362 int keep_first_children;
364 Widget* children = 0;
365 int num_children;
366 int child_index;
367 widget_value* cur;
368 Widget button = 0;
369 Widget menu;
370 Arg al [256];
371 int ac;
372 Boolean menubar_p;
374 Widget* old_children;
375 unsigned int old_num_children;
377 old_children = XtCompositeChildren (widget, &old_num_children);
379 /* Allocate the children array */
380 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
381 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
383 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
384 menubar_p = False;
385 XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
386 XtGetValues (widget, al, 1);
388 /* add the unmap callback for popups and pulldowns */
389 /*** this sounds bogus ***/
390 if (!menubar_p)
391 XtAddCallback (XtParent (widget), XmNpopdownCallback,
392 xm_pop_down_callback, (XtPointer)instance);
394 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
395 for (child_index = 0, cur = val; child_index < keep_first_children;
396 child_index++, cur = cur->next)
397 children[child_index] = old_children[child_index];
399 /* Check that those are all we have
400 (the caller should have deleted the rest). */
401 if (old_num_children != keep_first_children)
402 abort ();
404 /* Create the rest. */
405 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
407 ac = 0;
408 XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
409 XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
410 XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
412 if (instance->pop_up_p && !cur->contents && !cur->call_data
413 && !all_dashes_p (cur->name))
415 ac = 0;
416 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
417 button = XmCreateLabel (widget, cur->name, al, ac);
419 else if (all_dashes_p (cur->name))
421 button = XmCreateSeparator (widget, cur->name, NULL, 0);
423 else if (!cur->contents)
425 if (menubar_p)
426 button = XmCreateCascadeButton (widget, cur->name, al, ac);
427 else if (!cur->call_data)
428 button = XmCreateLabel (widget, cur->name, al, ac);
429 else
430 button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
432 xm_update_label (instance, button, cur);
434 /* don't add a callback to a simple label */
435 if (cur->call_data)
436 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
437 (XtPointer)instance);
439 else
441 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
442 make_menu_in_widget (instance, menu, cur->contents, 0);
443 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
444 /* non-zero values don't work reliably in
445 conjunction with Emacs' event loop */
446 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
447 button = XmCreateCascadeButtonGadget (widget, cur->name, al, ac);
449 xm_update_label (instance, button, cur);
451 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
452 (XtPointer)instance);
455 children [child_index] = button;
458 XtManageChildren (children, num_children);
460 /* Last entry is the help button. Has to be done after managing
461 * the buttons otherwise the menubar is only 4 pixels high... */
462 if (button)
464 ac = 0;
465 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
466 XtSetValues (widget, al, ac);
469 XtFree ((char *) children);
470 if (old_children)
471 XtFree ((char *) old_children);
474 static void
475 update_one_menu_entry (instance, widget, val, deep_p)
476 widget_instance* instance;
477 Widget widget;
478 widget_value* val;
479 Boolean deep_p;
481 Arg al [256];
482 int ac;
483 Widget menu;
484 widget_value* contents;
486 if (val->this_one_change == NO_CHANGE)
487 return;
489 /* update the sensitivity and userdata */
490 /* Common to all widget types */
491 XtVaSetValues (widget,
492 XmNsensitive, val->enabled,
493 XmNuserData, val->call_data,
496 /* update the menu button as a label. */
497 if (val->this_one_change >= VISIBLE_CHANGE)
498 xm_update_label (instance, widget, val);
500 /* update the pulldown/pullaside as needed */
501 ac = 0;
502 menu = NULL;
503 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
504 XtGetValues (widget, al, ac);
506 contents = val->contents;
508 if (!menu)
510 if (contents)
512 unsigned int old_num_children, i;
513 Widget parent;
514 Widget *widget_list;
516 parent = XtParent (widget);
517 widget_list = XtCompositeChildren (parent, &old_num_children);
519 /* Find the widget position within the parent's widget list. */
520 for (i = 0; i < old_num_children; i++)
521 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
522 break;
523 if (i == old_num_children)
524 abort ();
525 if (XmIsCascadeButton (widget_list[i]))
527 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
528 make_menu_in_widget (instance, menu, contents, 0);
529 ac = 0;
530 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
531 XtSetValues (widget, al, ac);
533 else
535 Widget button;
537 /* The current menuitem is a XmPushButtonGadget, it
538 needs to be replaced by a CascadeButtonGadget */
539 XtDestroyWidget (widget_list[i]);
540 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
541 make_menu_in_widget (instance, menu, contents, 0);
542 ac = 0;
543 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
544 /* Non-zero values don't work reliably in
545 conjunction with Emacs' event loop */
546 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
547 /* Tell Motif to put it in the right place */
548 XtSetArg (al [ac], XmNpositionIndex, i); ac++;
549 button = XmCreateCascadeButtonGadget (parent, val->name, al, ac);
550 xm_update_label (instance, button, val);
552 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
553 (XtPointer)instance);
554 XtManageChild (button);
558 else if (!contents)
560 ac = 0;
561 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
562 XtSetValues (widget, al, ac);
563 XtDestroyWidget (menu);
565 else if (deep_p && contents->change != NO_CHANGE)
566 xm_update_menu (instance, menu, val, 1);
569 static void
570 xm_update_menu (instance, widget, val, deep_p)
571 widget_instance* instance;
572 Widget widget;
573 widget_value* val;
574 Boolean deep_p;
576 Widget* children;
577 unsigned int num_children;
578 int num_children_to_keep = 0;
579 int i;
580 widget_value* cur;
582 children = XtCompositeChildren (widget, &num_children);
584 /* Widget is a RowColumn widget whose contents have to be updated
585 * to reflect the list of items in val->contents */
587 /* See how many buttons we can keep, and how many we
588 must completely replace. */
589 if (val->contents == 0)
590 num_children_to_keep = 0;
591 else if (val->contents->change == STRUCTURAL_CHANGE)
593 if (children)
595 for (i = 0, cur = val->contents;
596 (i < num_children
597 && cur); /* how else to ditch unwanted children ?? - mgd */
598 i++, cur = cur->next)
600 if (cur->this_one_change == STRUCTURAL_CHANGE)
601 break;
604 num_children_to_keep = i;
607 else
608 num_children_to_keep = num_children;
610 /* Update all the buttons of the RowColumn, in order,
611 except for those we are going to replace entirely. */
612 if (children)
614 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
616 if (!cur)
618 num_children_to_keep = i;
619 break;
621 if (children [i]->core.being_destroyed
622 || strcmp (XtName (children [i]), cur->name))
623 continue;
624 update_one_menu_entry (instance, children [i], cur, deep_p);
625 cur = cur->next;
629 /* Now replace from scratch all the buttons after the last
630 place that the top-level structure changed. */
631 if (val->contents->change == STRUCTURAL_CHANGE)
633 destroy_all_children (widget, num_children_to_keep);
634 make_menu_in_widget (instance, widget, val->contents,
635 num_children_to_keep);
638 XtFree ((char *) children);
642 /* update text widgets */
644 static void
645 xm_update_text (instance, widget, val)
646 widget_instance* instance;
647 Widget widget;
648 widget_value* val;
650 XmTextSetString (widget, val->value ? val->value : "");
651 XtRemoveAllCallbacks (widget, XmNactivateCallback);
652 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
653 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
654 XtAddCallback (widget, XmNvalueChangedCallback,
655 xm_internal_update_other_instances, instance);
658 static void
659 xm_update_text_field (instance, widget, val)
660 widget_instance* instance;
661 Widget widget;
662 widget_value* val;
664 XmTextFieldSetString (widget, val->value ? val->value : "");
665 XtRemoveAllCallbacks (widget, XmNactivateCallback);
666 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
667 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
668 XtAddCallback (widget, XmNvalueChangedCallback,
669 xm_internal_update_other_instances, instance);
673 /* update a motif widget */
675 void
676 xm_update_one_widget (instance, widget, val, deep_p)
677 widget_instance* instance;
678 Widget widget;
679 widget_value* val;
680 Boolean deep_p;
682 WidgetClass class;
684 /* Mark as not edited */
685 val->edited = False;
687 /* Common to all widget types */
688 XtVaSetValues (widget,
689 XmNsensitive, val->enabled,
690 XmNuserData, val->call_data,
693 /* Common to all label like widgets */
694 if (XtIsSubclass (widget, xmLabelWidgetClass))
695 xm_update_label (instance, widget, val);
697 class = XtClass (widget);
698 /* Class specific things */
699 if (class == xmPushButtonWidgetClass ||
700 class == xmArrowButtonWidgetClass)
702 xm_update_pushbutton (instance, widget, val);
704 else if (class == xmCascadeButtonWidgetClass)
706 xm_update_cascadebutton (instance, widget, val);
708 else if (class == xmToggleButtonWidgetClass
709 || class == xmToggleButtonGadgetClass)
711 xm_update_toggle (instance, widget, val);
713 else if (class == xmRowColumnWidgetClass)
715 Boolean radiobox = 0;
716 int ac = 0;
717 Arg al [1];
719 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
720 XtGetValues (widget, al, ac);
722 if (radiobox)
723 xm_update_radiobox (instance, widget, val);
724 else
725 xm_update_menu (instance, widget, val, deep_p);
727 else if (class == xmTextWidgetClass)
729 xm_update_text (instance, widget, val);
731 else if (class == xmTextFieldWidgetClass)
733 xm_update_text_field (instance, widget, val);
735 else if (class == xmListWidgetClass)
737 xm_update_list (instance, widget, val);
741 \f/* getting the value back */
742 void
743 xm_update_one_value (instance, widget, val)
744 widget_instance* instance;
745 Widget widget;
746 widget_value* val;
748 WidgetClass class = XtClass (widget);
749 widget_value *old_wv;
751 /* copy the call_data slot into the "return" widget_value */
752 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
753 if (!strcmp (val->name, old_wv->name))
755 val->call_data = old_wv->call_data;
756 break;
759 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
761 XtVaGetValues (widget, XmNset, &val->selected, 0);
762 val->edited = True;
764 else if (class == xmTextWidgetClass)
766 if (val->value)
767 free (val->value);
768 val->value = XmTextGetString (widget);
769 val->edited = True;
771 else if (class == xmTextFieldWidgetClass)
773 if (val->value)
774 free (val->value);
775 val->value = XmTextFieldGetString (widget);
776 val->edited = True;
778 else if (class == xmRowColumnWidgetClass)
780 Boolean radiobox = 0;
781 int ac = 0;
782 Arg al [1];
784 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
785 XtGetValues (widget, al, ac);
787 if (radiobox)
789 CompositeWidget radio = (CompositeWidget)widget;
790 int i;
791 for (i = 0; i < radio->composite.num_children; i++)
793 int set = False;
794 Widget toggle = radio->composite.children [i];
796 XtVaGetValues (toggle, XmNset, &set, 0);
797 if (set)
799 if (val->value)
800 free (val->value);
801 val->value = safe_strdup (XtName (toggle));
804 val->edited = True;
807 else if (class == xmListWidgetClass)
809 int pos_cnt;
810 int* pos_list;
811 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
813 int i;
814 widget_value* cur;
815 for (cur = val->contents, i = 0; cur; cur = cur->next)
816 if (cur->value)
818 int j;
819 cur->selected = False;
820 i += 1;
821 for (j = 0; j < pos_cnt; j++)
822 if (pos_list [j] == i)
824 cur->selected = True;
825 val->value = safe_strdup (cur->name);
828 val->edited = 1;
829 XtFree ((char *) pos_list);
835 /* This function is for activating a button from a program. It's wrong because
836 we pass a NULL argument in the call_data which is not Motif compatible.
837 This is used from the XmNdefaultAction callback of the List widgets to
838 have a double-click put down a dialog box like the button would do.
839 I could not find a way to do that with accelerators.
841 static void
842 activate_button (widget, closure, call_data)
843 Widget widget;
844 XtPointer closure;
845 XtPointer call_data;
847 Widget button = (Widget)closure;
848 XtCallCallbacks (button, XmNactivateCallback, NULL);
851 /* creation functions */
853 /* dialogs */
854 static Widget
855 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
856 radio_box, list, left_buttons, right_buttons)
857 char* name;
858 Widget parent;
859 Boolean pop_up_p;
860 char* shell_title;
861 char* icon_name;
862 Boolean text_input_slot;
863 Boolean radio_box;
864 Boolean list;
865 int left_buttons;
866 int right_buttons;
868 Widget result;
869 Widget form;
870 Widget row;
871 Widget icon;
872 Widget icon_separator;
873 Widget message;
874 Widget value = 0;
875 Widget separator;
876 Widget button = 0;
877 Widget children [16]; /* for the final XtManageChildren */
878 int n_children;
879 Arg al[64]; /* Arg List */
880 int ac; /* Arg Count */
881 int i;
883 if (pop_up_p)
885 ac = 0;
886 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
887 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
888 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
889 result = XmCreateDialogShell (parent, "dialog", al, ac);
890 ac = 0;
891 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
892 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
893 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
894 form = XmCreateForm (result, shell_title, al, ac);
896 else
898 ac = 0;
899 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
900 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
901 form = XmCreateForm (parent, shell_title, al, ac);
902 result = form;
905 n_children = left_buttons + right_buttons + 1;
906 ac = 0;
907 XtSetArg(al[ac], XmNpacking, n_children == 3?
908 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
909 XtSetArg(al[ac], XmNorientation, n_children == 3?
910 XmVERTICAL: XmHORIZONTAL); ac++;
911 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
912 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
913 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
914 XtSetArg(al[ac], XmNspacing, 13); ac++;
915 XtSetArg(al[ac], XmNadjustLast, False); ac++;
916 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
917 XtSetArg(al[ac], XmNisAligned, True); ac++;
918 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
919 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
920 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
921 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
922 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
923 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
924 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
925 row = XmCreateRowColumn (form, "row", al, ac);
927 n_children = 0;
928 for (i = 0; i < left_buttons; i++)
930 char button_name [16];
931 sprintf (button_name, "button%d", i + 1);
932 ac = 0;
933 if (i == 0)
935 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
936 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
938 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
939 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
940 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
942 if (i == 0)
944 button = children [n_children];
945 ac = 0;
946 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
947 XtSetValues (row, al, ac);
950 n_children++;
953 /* invisible separator button */
954 ac = 0;
955 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
956 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
957 n_children++;
959 for (i = 0; i < right_buttons; i++)
961 char button_name [16];
962 sprintf (button_name, "button%d", left_buttons + i + 1);
963 ac = 0;
964 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
965 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
966 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
967 if (! button) button = children [n_children];
968 n_children++;
971 XtManageChildren (children, n_children);
973 ac = 0;
974 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
975 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
976 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
977 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
978 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
979 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
980 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
981 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
982 separator = XmCreateSeparator (form, "", al, ac);
984 ac = 0;
985 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
986 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
987 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
988 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
989 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
990 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
991 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
992 icon = XmCreateLabel (form, icon_name, al, ac);
994 ac = 0;
995 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
996 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
997 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
998 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
999 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1000 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1001 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1002 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1003 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1004 icon_separator = XmCreateLabel (form, "", al, ac);
1006 if (text_input_slot)
1008 ac = 0;
1009 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1010 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1011 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1012 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1013 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1014 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1015 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1016 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1017 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1018 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1019 value = XmCreateTextField (form, "value", al, ac);
1021 else if (radio_box)
1023 Widget radio_butt;
1024 ac = 0;
1025 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1026 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1027 XtSetArg(al[ac], XmNspacing, 13); ac++;
1028 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1029 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1030 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1031 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1032 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1033 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1034 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1035 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1036 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1037 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1038 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1039 ac = 0;
1040 i = 0;
1041 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1042 children [i++] = radio_butt;
1043 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1044 children [i++] = radio_butt;
1045 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1046 children [i++] = radio_butt;
1047 XtManageChildren (children, i);
1049 else if (list)
1051 ac = 0;
1052 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1053 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1054 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1055 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1056 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1057 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1058 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1059 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1060 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1061 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1062 value = XmCreateScrolledList (form, "list", al, ac);
1064 /* this is the easiest way I found to have the dble click in the
1065 list activate the default button */
1066 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1069 ac = 0;
1070 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1071 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1072 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1073 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1074 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1075 XtSetArg(al[ac], XmNbottomWidget,
1076 text_input_slot || radio_box || list ? value : separator); ac++;
1077 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1078 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1079 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1080 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1081 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1082 message = XmCreateLabel (form, "message", al, ac);
1084 if (list)
1085 XtManageChild (value);
1087 i = 0;
1088 children [i] = row; i++;
1089 children [i] = separator; i++;
1090 if (text_input_slot || radio_box)
1092 children [i] = value; i++;
1094 children [i] = message; i++;
1095 children [i] = icon; i++;
1096 children [i] = icon_separator; i++;
1097 XtManageChildren (children, i);
1099 if (text_input_slot || list)
1101 XtInstallAccelerators (value, button);
1102 XtSetKeyboardFocus (result, value);
1104 else
1106 XtInstallAccelerators (form, button);
1107 XtSetKeyboardFocus (result, button);
1110 return result;
1113 static destroyed_instance*
1114 find_matching_instance (instance)
1115 widget_instance* instance;
1117 destroyed_instance* cur;
1118 destroyed_instance* prev;
1119 char* type = instance->info->type;
1120 char* name = instance->info->name;
1122 for (prev = NULL, cur = all_destroyed_instances;
1123 cur;
1124 prev = cur, cur = cur->next)
1126 if (!strcmp (cur->name, name)
1127 && !strcmp (cur->type, type)
1128 && cur->parent == instance->parent
1129 && cur->pop_up_p == instance->pop_up_p)
1131 if (prev)
1132 prev->next = cur->next;
1133 else
1134 all_destroyed_instances = cur->next;
1135 return cur;
1137 /* do some cleanup */
1138 else if (!cur->widget)
1140 if (prev)
1141 prev->next = cur->next;
1142 else
1143 all_destroyed_instances = cur->next;
1144 free_destroyed_instance (cur);
1145 cur = prev ? prev : all_destroyed_instances;
1148 return NULL;
1151 static void
1152 mark_dead_instance_destroyed (widget, closure, call_data)
1153 Widget widget;
1154 XtPointer closure;
1155 XtPointer call_data;
1157 destroyed_instance* instance = (destroyed_instance*)closure;
1158 instance->widget = NULL;
1161 static void
1162 recenter_widget (widget)
1163 Widget widget;
1165 Widget parent = XtParent (widget);
1166 Screen* screen = XtScreen (widget);
1167 Dimension screen_width = WidthOfScreen (screen);
1168 Dimension screen_height = HeightOfScreen (screen);
1169 Dimension parent_width = 0;
1170 Dimension parent_height = 0;
1171 Dimension child_width = 0;
1172 Dimension child_height = 0;
1173 Position x;
1174 Position y;
1176 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1177 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1180 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1181 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1183 XtTranslateCoords (parent, x, y, &x, &y);
1185 if (x + child_width > screen_width)
1186 x = screen_width - child_width;
1187 if (x < 0)
1188 x = 0;
1190 if (y + child_height > screen_height)
1191 y = screen_height - child_height;
1192 if (y < 0)
1193 y = 0;
1195 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1198 static Widget
1199 recycle_instance (instance)
1200 destroyed_instance* instance;
1202 Widget widget = instance->widget;
1204 /* widget is NULL if the parent was destroyed. */
1205 if (widget)
1207 Widget focus;
1208 Widget separator;
1210 /* Remove the destroy callback as the instance is not in the list
1211 anymore */
1212 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1213 mark_dead_instance_destroyed,
1214 (XtPointer)instance);
1216 /* Give the focus to the initial item */
1217 focus = XtNameToWidget (widget, "*value");
1218 if (!focus)
1219 focus = XtNameToWidget (widget, "*button1");
1220 if (focus)
1221 XtSetKeyboardFocus (widget, focus);
1223 /* shrink the separator label back to their original size */
1224 separator = XtNameToWidget (widget, "*separator_button");
1225 if (separator)
1226 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1228 /* Center the dialog in its parent */
1229 recenter_widget (widget);
1231 free_destroyed_instance (instance);
1232 return widget;
1235 Widget
1236 xm_create_dialog (instance)
1237 widget_instance* instance;
1239 char* name = instance->info->type;
1240 Widget parent = instance->parent;
1241 Widget widget;
1242 Boolean pop_up_p = instance->pop_up_p;
1243 char* shell_name = 0;
1244 char* icon_name;
1245 Boolean text_input_slot = False;
1246 Boolean radio_box = False;
1247 Boolean list = False;
1248 int total_buttons;
1249 int left_buttons = 0;
1250 int right_buttons = 1;
1251 destroyed_instance* dead_one;
1253 /* try to find a widget to recycle */
1254 dead_one = find_matching_instance (instance);
1255 if (dead_one)
1257 Widget recycled_widget = recycle_instance (dead_one);
1258 if (recycled_widget)
1259 return recycled_widget;
1262 switch (name [0]){
1263 case 'E': case 'e':
1264 icon_name = "dbox-error";
1265 shell_name = "Error";
1266 break;
1268 case 'I': case 'i':
1269 icon_name = "dbox-info";
1270 shell_name = "Information";
1271 break;
1273 case 'L': case 'l':
1274 list = True;
1275 icon_name = "dbox-question";
1276 shell_name = "Prompt";
1277 break;
1279 case 'P': case 'p':
1280 text_input_slot = True;
1281 icon_name = "dbox-question";
1282 shell_name = "Prompt";
1283 break;
1285 case 'Q': case 'q':
1286 icon_name = "dbox-question";
1287 shell_name = "Question";
1288 break;
1291 total_buttons = name [1] - '0';
1293 if (name [3] == 'T' || name [3] == 't')
1295 text_input_slot = False;
1296 radio_box = True;
1298 else if (name [3])
1299 right_buttons = name [4] - '0';
1301 left_buttons = total_buttons - right_buttons;
1303 widget = make_dialog (name, parent, pop_up_p,
1304 shell_name, icon_name, text_input_slot, radio_box,
1305 list, left_buttons, right_buttons);
1307 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1308 (XtPointer) instance);
1309 return widget;
1312 /* Create a menu bar. We turn off the f10 key
1313 because we have not yet managed to make it work right in Motif. */
1315 static Widget
1316 make_menubar (instance)
1317 widget_instance* instance;
1319 Arg al[1];
1320 int ac;
1322 ac = 0;
1323 XtSetArg(al[0], XmNmenuAccelerator, 0);
1324 return XmCreateMenuBar (instance->parent, instance->info->name, al, 1);
1327 static void
1328 remove_grabs (shell, closure, call_data)
1329 Widget shell;
1330 XtPointer closure;
1331 XtPointer call_data;
1333 Widget menu = (Widget) closure;
1334 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1337 static Widget
1338 make_popup_menu (instance)
1339 widget_instance* instance;
1341 Widget parent = instance->parent;
1342 Window parent_window = parent->core.window;
1343 Widget result;
1345 /* sets the parent window to 0 to fool Motif into not generating a grab */
1346 parent->core.window = 0;
1347 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1348 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1349 (XtPointer)result);
1350 parent->core.window = parent_window;
1351 return result;
1353 static Widget
1354 make_main (instance)
1355 widget_instance* instance;
1357 Widget parent = instance->parent;
1358 Widget result;
1359 Arg al[2];
1360 int ac;
1362 ac = 0;
1363 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1364 XtSetArg (al[ac], XmNspacing, 0); ac++;
1365 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1366 return result;
1369 \f/* Table of functions to create widgets */
1371 #ifdef ENERGIZE
1373 /* interface with the XDesigner generated functions */
1374 typedef Widget (*widget_maker) (Widget);
1375 extern Widget create_project_p_sheet (Widget parent);
1376 extern Widget create_debugger_p_sheet (Widget parent);
1377 extern Widget create_breaklist_p_sheet (Widget parent);
1378 extern Widget create_le_browser_p_sheet (Widget parent);
1379 extern Widget create_class_browser_p_sheet (Widget parent);
1380 extern Widget create_call_browser_p_sheet (Widget parent);
1381 extern Widget create_build_dialog (Widget parent);
1382 extern Widget create_editmode_dialog (Widget parent);
1383 extern Widget create_search_dialog (Widget parent);
1384 extern Widget create_project_display_dialog (Widget parent);
1386 static Widget
1387 make_one (widget_instance* instance, widget_maker fn)
1389 Widget result;
1390 Arg al [64];
1391 int ac = 0;
1393 if (instance->pop_up_p)
1395 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1396 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1397 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1398 (XtPointer) instance);
1399 (*fn) (result);
1401 else
1403 result = (*fn) (instance->parent);
1404 XtRealizeWidget (result);
1406 return result;
1409 static Widget
1410 make_project_p_sheet (widget_instance* instance)
1412 return make_one (instance, create_project_p_sheet);
1415 static Widget
1416 make_debugger_p_sheet (widget_instance* instance)
1418 return make_one (instance, create_debugger_p_sheet);
1421 static Widget
1422 make_breaklist_p_sheet (widget_instance* instance)
1424 return make_one (instance, create_breaklist_p_sheet);
1427 static Widget
1428 make_le_browser_p_sheet (widget_instance* instance)
1430 return make_one (instance, create_le_browser_p_sheet);
1433 static Widget
1434 make_class_browser_p_sheet (widget_instance* instance)
1436 return make_one (instance, create_class_browser_p_sheet);
1439 static Widget
1440 make_call_browser_p_sheet (widget_instance* instance)
1442 return make_one (instance, create_call_browser_p_sheet);
1445 static Widget
1446 make_build_dialog (widget_instance* instance)
1448 return make_one (instance, create_build_dialog);
1451 static Widget
1452 make_editmode_dialog (widget_instance* instance)
1454 return make_one (instance, create_editmode_dialog);
1457 static Widget
1458 make_search_dialog (widget_instance* instance)
1460 return make_one (instance, create_search_dialog);
1463 static Widget
1464 make_project_display_dialog (widget_instance* instance)
1466 return make_one (instance, create_project_display_dialog);
1469 #endif /* ENERGIZE */
1471 widget_creation_entry
1472 xm_creation_table [] =
1474 {"menubar", make_menubar},
1475 {"popup", make_popup_menu},
1476 {"main", make_main},
1477 #ifdef ENERGIZE
1478 {"project_p_sheet", make_project_p_sheet},
1479 {"debugger_p_sheet", make_debugger_p_sheet},
1480 {"breaklist_psheet", make_breaklist_p_sheet},
1481 {"leb_psheet", make_le_browser_p_sheet},
1482 {"class_browser_psheet", make_class_browser_p_sheet},
1483 {"ctree_browser_psheet", make_call_browser_p_sheet},
1484 {"build", make_build_dialog},
1485 {"editmode", make_editmode_dialog},
1486 {"search", make_search_dialog},
1487 {"project_display", make_project_display_dialog},
1488 #endif /* ENERGIZE */
1489 {NULL, NULL}
1492 \f/* Destruction of instances */
1493 void
1494 xm_destroy_instance (instance)
1495 widget_instance* instance;
1497 Widget widget = instance->widget;
1498 /* recycle the dialog boxes */
1499 /* Disable the recycling until we can find a way to have the dialog box
1500 get reasonable layout after we modify its contents. */
1501 if (0
1502 && XtClass (widget) == xmDialogShellWidgetClass)
1504 destroyed_instance* dead_instance =
1505 make_destroyed_instance (instance->info->name,
1506 instance->info->type,
1507 instance->widget,
1508 instance->parent,
1509 instance->pop_up_p);
1510 dead_instance->next = all_destroyed_instances;
1511 all_destroyed_instances = dead_instance;
1512 XtUnmanageChild (first_child (instance->widget));
1513 XFlush (XtDisplay (instance->widget));
1514 XtAddCallback (instance->parent, XtNdestroyCallback,
1515 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1517 else
1519 /* This might not be necessary now that the nosel is attached to
1520 popdown instead of destroy, but it can't hurt. */
1521 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1522 xm_nosel_callback, (XtPointer)instance);
1523 XtDestroyWidget (instance->widget);
1527 \f/* popup utility */
1528 void
1529 xm_popup_menu (widget, event)
1530 Widget widget;
1531 XEvent *event;
1533 XButtonPressedEvent dummy;
1535 if (event == 0)
1537 dummy.type = ButtonPress;
1538 dummy.serial = 0;
1539 dummy.send_event = 0;
1540 dummy.display = XtDisplay (widget);
1541 dummy.window = XtWindow (XtParent (widget));
1542 dummy.time = 0;
1543 dummy.button = 0;
1544 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1545 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1546 &dummy.x, &dummy.y, &dummy.state);
1547 event = (XEvent *) &dummy;
1550 if (event->type == ButtonPress || event->type == ButtonRelease)
1552 /* This is so totally ridiculous: there's NO WAY to tell Motif
1553 that *any* button can select a menu item. Only one button
1554 can have that honor.
1556 char *trans = 0;
1557 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1558 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1559 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1560 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1561 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1562 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1563 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1565 XtManageChild (widget);
1568 static void
1569 set_min_dialog_size (w)
1570 Widget w;
1572 short width;
1573 short height;
1574 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1575 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1578 void
1579 xm_pop_instance (instance, up)
1580 widget_instance* instance;
1581 Boolean up;
1583 Widget widget = instance->widget;
1585 if (XtClass (widget) == xmDialogShellWidgetClass)
1587 Widget widget_to_manage = first_child (widget);
1588 if (up)
1590 XtManageChild (widget_to_manage);
1591 set_min_dialog_size (widget);
1592 XtSetKeyboardFocus (instance->parent, widget);
1594 else
1595 XtUnmanageChild (widget_to_manage);
1597 else
1599 if (up)
1600 XtManageChild (widget);
1601 else
1602 XtUnmanageChild (widget);
1607 /* motif callback */
1609 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1611 static void
1612 do_call (widget, closure, type)
1613 Widget widget;
1614 XtPointer closure;
1615 enum do_call_type type;
1617 Arg al [256];
1618 int ac;
1619 XtPointer user_data;
1620 widget_instance* instance = (widget_instance*)closure;
1621 Widget instance_widget;
1622 LWLIB_ID id;
1624 if (!instance)
1625 return;
1626 if (widget->core.being_destroyed)
1627 return;
1629 instance_widget = instance->widget;
1630 if (!instance_widget)
1631 return;
1633 id = instance->info->id;
1634 ac = 0;
1635 user_data = NULL;
1636 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1637 XtGetValues (widget, al, ac);
1638 switch (type)
1640 case pre_activate:
1641 if (instance->info->pre_activate_cb)
1642 instance->info->pre_activate_cb (widget, id, user_data);
1643 break;
1644 case selection:
1645 if (instance->info->selection_cb)
1646 instance->info->selection_cb (widget, id, user_data);
1647 break;
1648 case no_selection:
1649 if (instance->info->selection_cb)
1650 instance->info->selection_cb (widget, id, (XtPointer) -1);
1651 break;
1652 case post_activate:
1653 if (instance->info->post_activate_cb)
1654 instance->info->post_activate_cb (widget, id, user_data);
1655 break;
1656 default:
1657 abort ();
1661 /* Like lw_internal_update_other_instances except that it does not do
1662 anything if its shell parent is not managed. This is to protect
1663 lw_internal_update_other_instances to dereference freed memory
1664 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1665 list */
1666 static void
1667 xm_internal_update_other_instances (widget, closure, call_data)
1668 Widget widget;
1669 XtPointer closure;
1670 XtPointer call_data;
1672 Widget parent;
1673 for (parent = widget; parent; parent = XtParent (parent))
1674 if (XtIsShell (parent))
1675 break;
1676 else if (!XtIsManaged (parent))
1677 return;
1678 lw_internal_update_other_instances (widget, closure, call_data);
1681 static void
1682 xm_generic_callback (widget, closure, call_data)
1683 Widget widget;
1684 XtPointer closure;
1685 XtPointer call_data;
1687 lw_internal_update_other_instances (widget, closure, call_data);
1688 do_call (widget, closure, selection);
1691 static void
1692 xm_nosel_callback (widget, closure, call_data)
1693 Widget widget;
1694 XtPointer closure;
1695 XtPointer call_data;
1697 /* This callback is only called when a dialog box is dismissed with the wm's
1698 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1699 in that case, not just unmapped, so that it releases its keyboard grabs.
1700 But there are problems with running our callbacks while the widget is in
1701 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1702 instead of XmDESTROY and then destroy it ourself after having run the
1703 callback.
1705 do_call (widget, closure, no_selection);
1706 XtDestroyWidget (widget);
1709 static void
1710 xm_pull_down_callback (widget, closure, call_data)
1711 Widget widget;
1712 XtPointer closure;
1713 XtPointer call_data;
1715 do_call (widget, closure, pre_activate);
1718 static void
1719 xm_pop_down_callback (widget, closure, call_data)
1720 Widget widget;
1721 XtPointer closure;
1722 XtPointer call_data;
1724 widget_instance *instance = (widget_instance *) closure;
1726 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1727 || (XtParent (widget) == instance->parent))
1728 do_call (widget, closure, post_activate);
1732 /* set the keyboard focus */
1733 void
1734 xm_set_keyboard_focus (parent, w)
1735 Widget parent;
1736 Widget w;
1738 XmProcessTraversal (w, 0);
1739 XtSetKeyboardFocus (parent, w);
1742 /* Motif hack to set the main window areas. */
1743 void
1744 xm_set_main_areas (parent, menubar, work_area)
1745 Widget parent;
1746 Widget menubar;
1747 Widget work_area;
1749 XmMainWindowSetAreas (parent,
1750 menubar, /* menubar (maybe 0) */
1751 0, /* command area (psheets) */
1752 0, /* horizontal scroll */
1753 0, /* vertical scroll */
1754 work_area); /* work area */
1757 /* Motif hack to control resizing on the menubar. */
1758 void
1759 xm_manage_resizing (w, flag)
1760 Widget w;
1761 Boolean flag;
1763 if (flag)
1765 /* Enable the edit widget for resizing. */
1766 Arg al[1];
1768 XtSetArg (al[0], XtNallowShellResize, 0);
1769 XtSetValues (w, al, 1);
1771 else
1773 /* Disable the edit widget from resizing. */
1774 Arg al[1];
1776 XtSetArg (al[0], XtNallowShellResize, 0);
1777 XtSetValues (w, al, 1);