(destroy_all_children): When freeing a cascade button, free its submenu too.
[bpt/emacs.git] / lwlib / lwlib-Xm.c
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
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.
10
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.
15
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. */
20
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdio.h>
25
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>
31
32 #include "lwlib-Xm.h"
33 #include "lwlib-utils.h"
34
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>
59
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 */);
66
67 static void xm_update_menu (/* widget_instance*, Widget, widget_value*,
68 Boolean) */);
69
70
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
73 {
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;
81
82 static destroyed_instance*
83 all_destroyed_instances = NULL;
84
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;
92 {
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;
102 }
103
104 static void
105 free_destroyed_instance (instance)
106 destroyed_instance* instance;
107 {
108 free (instance->name);
109 free (instance->type);
110 free (instance);
111 }
112
113 \f/* motif utility functions */
114 Widget
115 first_child (widget)
116 Widget widget;
117 {
118 return ((CompositeWidget)widget)->composite.children [0];
119 }
120
121 Boolean
122 lw_motif_widget_p (widget)
123 Widget widget;
124 {
125 return
126 XtClass (widget) == xmDialogShellWidgetClass
127 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
128 }
129
130 static XmString
131 resource_motif_string (widget, name)
132 Widget widget;
133 char* name;
134 {
135 XtResource resource;
136 XmString result = 0;
137
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;
145
146 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
147 "DialogString", &resource, 1, NULL, 0);
148 return result;
149 }
150
151 /* Destroy all of the children of WIDGET
152 starting with number FIRST_CHILD_TO_DESTROY. */
153
154 static void
155 destroy_all_children (widget, first_child_to_destroy)
156 Widget widget;
157 int first_child_to_destroy;
158 {
159 Widget* children;
160 unsigned int number;
161 int i;
162
163 children = XtCompositeChildren (widget, &number);
164 if (children)
165 {
166 XtUnmanageChildren (children + first_child_to_destroy,
167 number - first_child_to_destroy);
168
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++)
172 {
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]);
185 }
186
187 XtFree ((char *) children);
188 }
189 }
190
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;
197 {
198 XmString res_string = 0;
199 XmString built_string = 0;
200 XmString key_string = 0;
201 Arg al [256];
202 int ac;
203
204 ac = 0;
205
206 if (val->value)
207 {
208 res_string = resource_motif_string (widget, val->value);
209
210 if (res_string)
211 {
212 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
213 }
214 else
215 {
216 built_string =
217 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
218 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
219 }
220 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
221 }
222
223 if (val->key)
224 {
225 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
226 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
227 }
228
229 if (ac)
230 XtSetValues (widget, al, ac);
231
232 if (built_string)
233 XmStringFree (built_string);
234
235 if (key_string)
236 XmStringFree (key_string);
237 }
238
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;
245 {
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)
253 {
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);
260 }
261 }
262
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;
269 {
270 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
271 XtRemoveAllCallbacks (widget, XmNactivateCallback);
272 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
273 }
274
275 static void
276 xm_update_cascadebutton (instance, widget, val)
277 widget_instance* instance;
278 Widget widget;
279 widget_value* val;
280 {
281 /* Should also rebuild the menu by calling ...update_menu... */
282 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
283 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
284 instance);
285 }
286
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;
293 {
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);
299 }
300
301 static void
302 xm_update_radiobox (instance, widget, val)
303 widget_instance* instance;
304 Widget widget;
305 widget_value* val;
306
307 {
308 Widget toggle;
309 widget_value* cur;
310
311 /* update the callback */
312 XtRemoveAllCallbacks (widget, XmNentryCallback);
313 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
314
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)
322 {
323 toggle = XtNameToWidget (widget, cur->value);
324 if (toggle)
325 {
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);
331 }
332 }
333
334 /* The selected was specified by the value slot */
335 if (val->value)
336 {
337 toggle = XtNameToWidget (widget, val->value);
338 if (toggle)
339 XtVaSetValues (toggle, XmNset, True, 0);
340 }
341 }
342
343 \f/* update a popup menu, pulldown menu or a menubar */
344 static Boolean
345 all_dashes_p (s)
346 char* s;
347 {
348 char* t;
349 for (t = s; *t; t++)
350 if (*t != '-')
351 return False;
352 return True;
353 }
354
355 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
356
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;
363 {
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;
373
374 Widget* old_children;
375 unsigned int old_num_children;
376
377 old_children = XtCompositeChildren (widget, &old_num_children);
378
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));
382
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);
387
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);
393
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];
398
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 ();
403
404 /* Create the rest. */
405 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
406 {
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++;
411
412 if (instance->pop_up_p && !cur->contents && !cur->call_data
413 && !all_dashes_p (cur->name))
414 {
415 ac = 0;
416 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
417 button = XmCreateLabel (widget, cur->name, al, ac);
418 }
419 else if (all_dashes_p (cur->name))
420 {
421 button = XmCreateSeparator (widget, cur->name, NULL, 0);
422 }
423 else if (!cur->contents)
424 {
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);
431
432 xm_update_label (instance, button, cur);
433
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);
438 }
439 else
440 {
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 button = XmCreateCascadeButtonGadget (widget, cur->name, al, ac);
445
446 xm_update_label (instance, button, cur);
447
448 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
449 (XtPointer)instance);
450 }
451
452 children [child_index] = button;
453 }
454
455 XtManageChildren (children, num_children);
456
457 /* Last entry is the help button. Has to be done after managing
458 * the buttons otherwise the menubar is only 4 pixels high... */
459 if (button)
460 {
461 ac = 0;
462 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
463 XtSetValues (widget, al, ac);
464 }
465
466 XtFree ((char *) children);
467 if (old_children)
468 XtFree ((char *) old_children);
469 }
470
471 static void
472 update_one_menu_entry (instance, widget, val, deep_p)
473 widget_instance* instance;
474 Widget widget;
475 widget_value* val;
476 Boolean deep_p;
477 {
478 Arg al [256];
479 int ac;
480 Widget menu;
481 widget_value* contents;
482
483 if (val->this_one_change == NO_CHANGE)
484 return;
485
486 /* update the sensitivity and userdata */
487 /* Common to all widget types */
488 XtVaSetValues (widget,
489 XmNsensitive, val->enabled,
490 XmNuserData, val->call_data,
491 0);
492
493 /* update the menu button as a label. */
494 if (val->this_one_change >= VISIBLE_CHANGE)
495 xm_update_label (instance, widget, val);
496
497 /* update the pulldown/pullaside as needed */
498 ac = 0;
499 menu = NULL;
500 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
501 XtGetValues (widget, al, ac);
502
503 contents = val->contents;
504
505 if (!menu)
506 {
507 if (contents)
508 {
509 menu = XmCreatePulldownMenu (XtParent (widget), XtName (widget), NULL, 0);
510 make_menu_in_widget (instance, menu, contents, 0);
511 ac = 0;
512 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
513 XtSetValues (widget, al, ac);
514 }
515 }
516 else if (!contents)
517 {
518 ac = 0;
519 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
520 XtSetValues (widget, al, ac);
521 XtDestroyWidget (menu);
522 }
523 else if (deep_p && contents->change != NO_CHANGE)
524 xm_update_menu (instance, menu, val, 1);
525 }
526
527 static void
528 xm_update_menu (instance, widget, val, deep_p)
529 widget_instance* instance;
530 Widget widget;
531 widget_value* val;
532 Boolean deep_p;
533 {
534 Widget* children;
535 unsigned int num_children;
536 int num_children_to_keep = 0;
537 int i;
538 widget_value* cur;
539
540 children = XtCompositeChildren (widget, &num_children);
541
542 /* Widget is a RowColumn widget whose contents have to be updated
543 * to reflect the list of items in val->contents */
544
545 /* See how many buttons we can keep, and how many we
546 must completely replace. */
547 if (val->contents == 0)
548 num_children_to_keep = 0;
549 else if (val->contents->change == STRUCTURAL_CHANGE)
550 {
551 if (children)
552 {
553 for (i = 0, cur = val->contents; i < num_children;
554 i++, cur = cur->next)
555 {
556 if (cur->this_one_change == STRUCTURAL_CHANGE)
557 break;
558 }
559
560 num_children_to_keep = i;
561 }
562 }
563 else
564 num_children_to_keep = num_children;
565
566 /* Update all the buttons of the RowColumn, in order,
567 except for those we are going to replace entirely. */
568 if (children)
569 {
570 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
571 {
572 if (!cur)
573 abort ();
574 if (children [i]->core.being_destroyed
575 || strcmp (XtName (children [i]), cur->name))
576 continue;
577 update_one_menu_entry (instance, children [i], cur, deep_p);
578 cur = cur->next;
579 }
580 }
581
582 /* Now replace from scratch all the buttons after the last
583 place that the top-level structure changed. */
584 if (val->contents->change == STRUCTURAL_CHANGE)
585 {
586 destroy_all_children (widget, num_children_to_keep);
587 make_menu_in_widget (instance, widget, val->contents,
588 num_children_to_keep);
589 }
590
591 XtFree ((char *) children);
592 }
593
594 \f
595 /* update text widgets */
596
597 static void
598 xm_update_text (instance, widget, val)
599 widget_instance* instance;
600 Widget widget;
601 widget_value* val;
602 {
603 XmTextSetString (widget, val->value ? val->value : "");
604 XtRemoveAllCallbacks (widget, XmNactivateCallback);
605 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
606 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
607 XtAddCallback (widget, XmNvalueChangedCallback,
608 xm_internal_update_other_instances, instance);
609 }
610
611 static void
612 xm_update_text_field (instance, widget, val)
613 widget_instance* instance;
614 Widget widget;
615 widget_value* val;
616 {
617 XmTextFieldSetString (widget, val->value ? val->value : "");
618 XtRemoveAllCallbacks (widget, XmNactivateCallback);
619 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
620 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
621 XtAddCallback (widget, XmNvalueChangedCallback,
622 xm_internal_update_other_instances, instance);
623 }
624
625 \f
626 /* update a motif widget */
627
628 void
629 xm_update_one_widget (instance, widget, val, deep_p)
630 widget_instance* instance;
631 Widget widget;
632 widget_value* val;
633 Boolean deep_p;
634 {
635 WidgetClass class;
636
637 /* Mark as not edited */
638 val->edited = False;
639
640 /* Common to all widget types */
641 XtVaSetValues (widget,
642 XmNsensitive, val->enabled,
643 XmNuserData, val->call_data,
644 0);
645
646 /* Common to all label like widgets */
647 if (XtIsSubclass (widget, xmLabelWidgetClass))
648 xm_update_label (instance, widget, val);
649
650 class = XtClass (widget);
651 /* Class specific things */
652 if (class == xmPushButtonWidgetClass ||
653 class == xmArrowButtonWidgetClass)
654 {
655 xm_update_pushbutton (instance, widget, val);
656 }
657 else if (class == xmCascadeButtonWidgetClass)
658 {
659 xm_update_cascadebutton (instance, widget, val);
660 }
661 else if (class == xmToggleButtonWidgetClass
662 || class == xmToggleButtonGadgetClass)
663 {
664 xm_update_toggle (instance, widget, val);
665 }
666 else if (class == xmRowColumnWidgetClass)
667 {
668 Boolean radiobox = 0;
669 int ac = 0;
670 Arg al [1];
671
672 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
673 XtGetValues (widget, al, ac);
674
675 if (radiobox)
676 xm_update_radiobox (instance, widget, val);
677 else
678 xm_update_menu (instance, widget, val, deep_p);
679 }
680 else if (class == xmTextWidgetClass)
681 {
682 xm_update_text (instance, widget, val);
683 }
684 else if (class == xmTextFieldWidgetClass)
685 {
686 xm_update_text_field (instance, widget, val);
687 }
688 else if (class == xmListWidgetClass)
689 {
690 xm_update_list (instance, widget, val);
691 }
692 }
693
694 \f/* getting the value back */
695 void
696 xm_update_one_value (instance, widget, val)
697 widget_instance* instance;
698 Widget widget;
699 widget_value* val;
700 {
701 WidgetClass class = XtClass (widget);
702 widget_value *old_wv;
703
704 /* copy the call_data slot into the "return" widget_value */
705 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
706 if (!strcmp (val->name, old_wv->name))
707 {
708 val->call_data = old_wv->call_data;
709 break;
710 }
711
712 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
713 {
714 XtVaGetValues (widget, XmNset, &val->selected, 0);
715 val->edited = True;
716 }
717 else if (class == xmTextWidgetClass)
718 {
719 if (val->value)
720 free (val->value);
721 val->value = XmTextGetString (widget);
722 val->edited = True;
723 }
724 else if (class == xmTextFieldWidgetClass)
725 {
726 if (val->value)
727 free (val->value);
728 val->value = XmTextFieldGetString (widget);
729 val->edited = True;
730 }
731 else if (class == xmRowColumnWidgetClass)
732 {
733 Boolean radiobox = 0;
734 int ac = 0;
735 Arg al [1];
736
737 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
738 XtGetValues (widget, al, ac);
739
740 if (radiobox)
741 {
742 CompositeWidget radio = (CompositeWidget)widget;
743 int i;
744 for (i = 0; i < radio->composite.num_children; i++)
745 {
746 int set = False;
747 Widget toggle = radio->composite.children [i];
748
749 XtVaGetValues (toggle, XmNset, &set, 0);
750 if (set)
751 {
752 if (val->value)
753 free (val->value);
754 val->value = safe_strdup (XtName (toggle));
755 }
756 }
757 val->edited = True;
758 }
759 }
760 else if (class == xmListWidgetClass)
761 {
762 int pos_cnt;
763 int* pos_list;
764 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
765 {
766 int i;
767 widget_value* cur;
768 for (cur = val->contents, i = 0; cur; cur = cur->next)
769 if (cur->value)
770 {
771 int j;
772 cur->selected = False;
773 i += 1;
774 for (j = 0; j < pos_cnt; j++)
775 if (pos_list [j] == i)
776 {
777 cur->selected = True;
778 val->value = safe_strdup (cur->name);
779 }
780 }
781 val->edited = 1;
782 XtFree ((char *) pos_list);
783 }
784 }
785 }
786
787 \f
788 /* This function is for activating a button from a program. It's wrong because
789 we pass a NULL argument in the call_data which is not Motif compatible.
790 This is used from the XmNdefaultAction callback of the List widgets to
791 have a double-click put down a dialog box like the button would do.
792 I could not find a way to do that with accelerators.
793 */
794 static void
795 activate_button (widget, closure, call_data)
796 Widget widget;
797 XtPointer closure;
798 XtPointer call_data;
799 {
800 Widget button = (Widget)closure;
801 XtCallCallbacks (button, XmNactivateCallback, NULL);
802 }
803
804 /* creation functions */
805
806 /* dialogs */
807 static Widget
808 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
809 radio_box, list, left_buttons, right_buttons)
810 char* name;
811 Widget parent;
812 Boolean pop_up_p;
813 char* shell_title;
814 char* icon_name;
815 Boolean text_input_slot;
816 Boolean radio_box;
817 Boolean list;
818 int left_buttons;
819 int right_buttons;
820 {
821 Widget result;
822 Widget form;
823 Widget row;
824 Widget icon;
825 Widget icon_separator;
826 Widget message;
827 Widget value = 0;
828 Widget separator;
829 Widget button = 0;
830 Widget children [16]; /* for the final XtManageChildren */
831 int n_children;
832 Arg al[64]; /* Arg List */
833 int ac; /* Arg Count */
834 int i;
835
836 if (pop_up_p)
837 {
838 ac = 0;
839 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
840 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
841 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
842 result = XmCreateDialogShell (parent, "dialog", al, ac);
843 ac = 0;
844 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
845 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
846 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
847 form = XmCreateForm (result, shell_title, al, ac);
848 }
849 else
850 {
851 ac = 0;
852 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
853 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
854 form = XmCreateForm (parent, shell_title, al, ac);
855 result = form;
856 }
857
858 n_children = left_buttons + right_buttons + 1;
859 ac = 0;
860 XtSetArg(al[ac], XmNpacking, n_children == 3?
861 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
862 XtSetArg(al[ac], XmNorientation, n_children == 3?
863 XmVERTICAL: XmHORIZONTAL); ac++;
864 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
865 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
866 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
867 XtSetArg(al[ac], XmNspacing, 13); ac++;
868 XtSetArg(al[ac], XmNadjustLast, False); ac++;
869 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
870 XtSetArg(al[ac], XmNisAligned, True); ac++;
871 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
872 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
873 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
874 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
875 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
876 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
877 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
878 row = XmCreateRowColumn (form, "row", al, ac);
879
880 n_children = 0;
881 for (i = 0; i < left_buttons; i++)
882 {
883 char button_name [16];
884 sprintf (button_name, "button%d", i + 1);
885 ac = 0;
886 if (i == 0)
887 {
888 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
889 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
890 }
891 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
892 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
893 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
894
895 if (i == 0)
896 {
897 button = children [n_children];
898 ac = 0;
899 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
900 XtSetValues (row, al, ac);
901 }
902
903 n_children++;
904 }
905
906 /* invisible separator button */
907 ac = 0;
908 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
909 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
910 n_children++;
911
912 for (i = 0; i < right_buttons; i++)
913 {
914 char button_name [16];
915 sprintf (button_name, "button%d", left_buttons + i + 1);
916 ac = 0;
917 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
918 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
919 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
920 if (! button) button = children [n_children];
921 n_children++;
922 }
923
924 XtManageChildren (children, n_children);
925
926 ac = 0;
927 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
928 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
929 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
930 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
931 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
932 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
933 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
934 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
935 separator = XmCreateSeparator (form, "", al, ac);
936
937 ac = 0;
938 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
939 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
940 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
941 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
942 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
943 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
944 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
945 icon = XmCreateLabel (form, icon_name, al, ac);
946
947 ac = 0;
948 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
949 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
950 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
951 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
952 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
953 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
954 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
955 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
956 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
957 icon_separator = XmCreateLabel (form, "", al, ac);
958
959 if (text_input_slot)
960 {
961 ac = 0;
962 XtSetArg(al[ac], XmNcolumns, 50); ac++;
963 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
964 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
965 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
966 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
967 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
968 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
969 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
970 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
971 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
972 value = XmCreateTextField (form, "value", al, ac);
973 }
974 else if (radio_box)
975 {
976 Widget radio_butt;
977 ac = 0;
978 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
979 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
980 XtSetArg(al[ac], XmNspacing, 13); ac++;
981 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
982 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
983 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
984 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
985 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
986 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
987 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
988 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
989 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
990 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
991 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
992 ac = 0;
993 i = 0;
994 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
995 children [i++] = radio_butt;
996 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
997 children [i++] = radio_butt;
998 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
999 children [i++] = radio_butt;
1000 XtManageChildren (children, i);
1001 }
1002 else if (list)
1003 {
1004 ac = 0;
1005 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1006 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1007 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1008 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1009 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1010 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1011 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1012 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1013 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1014 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1015 value = XmCreateScrolledList (form, "list", al, ac);
1016
1017 /* this is the easiest way I found to have the dble click in the
1018 list activate the default button */
1019 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1020 }
1021
1022 ac = 0;
1023 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1024 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1025 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1026 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1027 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1028 XtSetArg(al[ac], XmNbottomWidget,
1029 text_input_slot || radio_box || list ? value : separator); ac++;
1030 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1031 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1032 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1033 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1034 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1035 message = XmCreateLabel (form, "message", al, ac);
1036
1037 if (list)
1038 XtManageChild (value);
1039
1040 i = 0;
1041 children [i] = row; i++;
1042 children [i] = separator; i++;
1043 if (text_input_slot || radio_box)
1044 {
1045 children [i] = value; i++;
1046 }
1047 children [i] = message; i++;
1048 children [i] = icon; i++;
1049 children [i] = icon_separator; i++;
1050 XtManageChildren (children, i);
1051
1052 if (text_input_slot || list)
1053 {
1054 XtInstallAccelerators (value, button);
1055 XtSetKeyboardFocus (result, value);
1056 }
1057 else
1058 {
1059 XtInstallAccelerators (form, button);
1060 XtSetKeyboardFocus (result, button);
1061 }
1062
1063 return result;
1064 }
1065
1066 static destroyed_instance*
1067 find_matching_instance (instance)
1068 widget_instance* instance;
1069 {
1070 destroyed_instance* cur;
1071 destroyed_instance* prev;
1072 char* type = instance->info->type;
1073 char* name = instance->info->name;
1074
1075 for (prev = NULL, cur = all_destroyed_instances;
1076 cur;
1077 prev = cur, cur = cur->next)
1078 {
1079 if (!strcmp (cur->name, name)
1080 && !strcmp (cur->type, type)
1081 && cur->parent == instance->parent
1082 && cur->pop_up_p == instance->pop_up_p)
1083 {
1084 if (prev)
1085 prev->next = cur->next;
1086 else
1087 all_destroyed_instances = cur->next;
1088 return cur;
1089 }
1090 /* do some cleanup */
1091 else if (!cur->widget)
1092 {
1093 if (prev)
1094 prev->next = cur->next;
1095 else
1096 all_destroyed_instances = cur->next;
1097 free_destroyed_instance (cur);
1098 cur = prev ? prev : all_destroyed_instances;
1099 }
1100 }
1101 return NULL;
1102 }
1103
1104 static void
1105 mark_dead_instance_destroyed (widget, closure, call_data)
1106 Widget widget;
1107 XtPointer closure;
1108 XtPointer call_data;
1109 {
1110 destroyed_instance* instance = (destroyed_instance*)closure;
1111 instance->widget = NULL;
1112 }
1113
1114 static void
1115 recenter_widget (widget)
1116 Widget widget;
1117 {
1118 Widget parent = XtParent (widget);
1119 Screen* screen = XtScreen (widget);
1120 Dimension screen_width = WidthOfScreen (screen);
1121 Dimension screen_height = HeightOfScreen (screen);
1122 Dimension parent_width = 0;
1123 Dimension parent_height = 0;
1124 Dimension child_width = 0;
1125 Dimension child_height = 0;
1126 Position x;
1127 Position y;
1128
1129 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1130 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1131 0);
1132
1133 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1134 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1135
1136 XtTranslateCoords (parent, x, y, &x, &y);
1137
1138 if (x + child_width > screen_width)
1139 x = screen_width - child_width;
1140 if (x < 0)
1141 x = 0;
1142
1143 if (y + child_height > screen_height)
1144 y = screen_height - child_height;
1145 if (y < 0)
1146 y = 0;
1147
1148 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1149 }
1150
1151 static Widget
1152 recycle_instance (instance)
1153 destroyed_instance* instance;
1154 {
1155 Widget widget = instance->widget;
1156
1157 /* widget is NULL if the parent was destroyed. */
1158 if (widget)
1159 {
1160 Widget focus;
1161 Widget separator;
1162
1163 /* Remove the destroy callback as the instance is not in the list
1164 anymore */
1165 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1166 mark_dead_instance_destroyed,
1167 (XtPointer)instance);
1168
1169 /* Give the focus to the initial item */
1170 focus = XtNameToWidget (widget, "*value");
1171 if (!focus)
1172 focus = XtNameToWidget (widget, "*button1");
1173 if (focus)
1174 XtSetKeyboardFocus (widget, focus);
1175
1176 /* shrink the separator label back to their original size */
1177 separator = XtNameToWidget (widget, "*separator_button");
1178 if (separator)
1179 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1180
1181 /* Center the dialog in its parent */
1182 recenter_widget (widget);
1183 }
1184 free_destroyed_instance (instance);
1185 return widget;
1186 }
1187
1188 Widget
1189 xm_create_dialog (instance)
1190 widget_instance* instance;
1191 {
1192 char* name = instance->info->type;
1193 Widget parent = instance->parent;
1194 Widget widget;
1195 Boolean pop_up_p = instance->pop_up_p;
1196 char* shell_name = 0;
1197 char* icon_name;
1198 Boolean text_input_slot = False;
1199 Boolean radio_box = False;
1200 Boolean list = False;
1201 int total_buttons;
1202 int left_buttons = 0;
1203 int right_buttons = 1;
1204 destroyed_instance* dead_one;
1205
1206 /* try to find a widget to recycle */
1207 dead_one = find_matching_instance (instance);
1208 if (dead_one)
1209 {
1210 Widget recycled_widget = recycle_instance (dead_one);
1211 if (recycled_widget)
1212 return recycled_widget;
1213 }
1214
1215 switch (name [0]){
1216 case 'E': case 'e':
1217 icon_name = "dbox-error";
1218 shell_name = "Error";
1219 break;
1220
1221 case 'I': case 'i':
1222 icon_name = "dbox-info";
1223 shell_name = "Information";
1224 break;
1225
1226 case 'L': case 'l':
1227 list = True;
1228 icon_name = "dbox-question";
1229 shell_name = "Prompt";
1230 break;
1231
1232 case 'P': case 'p':
1233 text_input_slot = True;
1234 icon_name = "dbox-question";
1235 shell_name = "Prompt";
1236 break;
1237
1238 case 'Q': case 'q':
1239 icon_name = "dbox-question";
1240 shell_name = "Question";
1241 break;
1242 }
1243
1244 total_buttons = name [1] - '0';
1245
1246 if (name [3] == 'T' || name [3] == 't')
1247 {
1248 text_input_slot = False;
1249 radio_box = True;
1250 }
1251 else if (name [3])
1252 right_buttons = name [4] - '0';
1253
1254 left_buttons = total_buttons - right_buttons;
1255
1256 widget = make_dialog (name, parent, pop_up_p,
1257 shell_name, icon_name, text_input_slot, radio_box,
1258 list, left_buttons, right_buttons);
1259
1260 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1261 (XtPointer) instance);
1262 return widget;
1263 }
1264
1265 static Widget
1266 make_menubar (instance)
1267 widget_instance* instance;
1268 {
1269 return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
1270 }
1271
1272 static void
1273 remove_grabs (shell, closure, call_data)
1274 Widget shell;
1275 XtPointer closure;
1276 XtPointer call_data;
1277 {
1278 Widget menu = (Widget) closure;
1279 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1280 }
1281
1282 static Widget
1283 make_popup_menu (instance)
1284 widget_instance* instance;
1285 {
1286 Widget parent = instance->parent;
1287 Window parent_window = parent->core.window;
1288 Widget result;
1289
1290 /* sets the parent window to 0 to fool Motif into not generating a grab */
1291 parent->core.window = 0;
1292 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1293 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1294 (XtPointer)result);
1295 parent->core.window = parent_window;
1296 return result;
1297 }
1298 static Widget
1299 make_main (instance)
1300 widget_instance* instance;
1301 {
1302 Widget parent = instance->parent;
1303 Widget result;
1304 Arg al[2];
1305 int ac;
1306
1307 ac = 0;
1308 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1309 XtSetArg (al[ac], XmNspacing, 0); ac++;
1310 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1311 return result;
1312 }
1313
1314 \f/* Table of functions to create widgets */
1315
1316 #ifdef ENERGIZE
1317
1318 /* interface with the XDesigner generated functions */
1319 typedef Widget (*widget_maker) (Widget);
1320 extern Widget create_project_p_sheet (Widget parent);
1321 extern Widget create_debugger_p_sheet (Widget parent);
1322 extern Widget create_breaklist_p_sheet (Widget parent);
1323 extern Widget create_le_browser_p_sheet (Widget parent);
1324 extern Widget create_class_browser_p_sheet (Widget parent);
1325 extern Widget create_call_browser_p_sheet (Widget parent);
1326 extern Widget create_build_dialog (Widget parent);
1327 extern Widget create_editmode_dialog (Widget parent);
1328 extern Widget create_search_dialog (Widget parent);
1329 extern Widget create_project_display_dialog (Widget parent);
1330
1331 static Widget
1332 make_one (widget_instance* instance, widget_maker fn)
1333 {
1334 Widget result;
1335 Arg al [64];
1336 int ac = 0;
1337
1338 if (instance->pop_up_p)
1339 {
1340 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1341 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1342 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1343 (XtPointer) instance);
1344 (*fn) (result);
1345 }
1346 else
1347 {
1348 result = (*fn) (instance->parent);
1349 XtRealizeWidget (result);
1350 }
1351 return result;
1352 }
1353
1354 static Widget
1355 make_project_p_sheet (widget_instance* instance)
1356 {
1357 return make_one (instance, create_project_p_sheet);
1358 }
1359
1360 static Widget
1361 make_debugger_p_sheet (widget_instance* instance)
1362 {
1363 return make_one (instance, create_debugger_p_sheet);
1364 }
1365
1366 static Widget
1367 make_breaklist_p_sheet (widget_instance* instance)
1368 {
1369 return make_one (instance, create_breaklist_p_sheet);
1370 }
1371
1372 static Widget
1373 make_le_browser_p_sheet (widget_instance* instance)
1374 {
1375 return make_one (instance, create_le_browser_p_sheet);
1376 }
1377
1378 static Widget
1379 make_class_browser_p_sheet (widget_instance* instance)
1380 {
1381 return make_one (instance, create_class_browser_p_sheet);
1382 }
1383
1384 static Widget
1385 make_call_browser_p_sheet (widget_instance* instance)
1386 {
1387 return make_one (instance, create_call_browser_p_sheet);
1388 }
1389
1390 static Widget
1391 make_build_dialog (widget_instance* instance)
1392 {
1393 return make_one (instance, create_build_dialog);
1394 }
1395
1396 static Widget
1397 make_editmode_dialog (widget_instance* instance)
1398 {
1399 return make_one (instance, create_editmode_dialog);
1400 }
1401
1402 static Widget
1403 make_search_dialog (widget_instance* instance)
1404 {
1405 return make_one (instance, create_search_dialog);
1406 }
1407
1408 static Widget
1409 make_project_display_dialog (widget_instance* instance)
1410 {
1411 return make_one (instance, create_project_display_dialog);
1412 }
1413
1414 #endif /* ENERGIZE */
1415
1416 widget_creation_entry
1417 xm_creation_table [] =
1418 {
1419 {"menubar", make_menubar},
1420 {"popup", make_popup_menu},
1421 {"main", make_main},
1422 #ifdef ENERGIZE
1423 {"project_p_sheet", make_project_p_sheet},
1424 {"debugger_p_sheet", make_debugger_p_sheet},
1425 {"breaklist_psheet", make_breaklist_p_sheet},
1426 {"leb_psheet", make_le_browser_p_sheet},
1427 {"class_browser_psheet", make_class_browser_p_sheet},
1428 {"ctree_browser_psheet", make_call_browser_p_sheet},
1429 {"build", make_build_dialog},
1430 {"editmode", make_editmode_dialog},
1431 {"search", make_search_dialog},
1432 {"project_display", make_project_display_dialog},
1433 #endif /* ENERGIZE */
1434 {NULL, NULL}
1435 };
1436
1437 \f/* Destruction of instances */
1438 void
1439 xm_destroy_instance (instance)
1440 widget_instance* instance;
1441 {
1442 Widget widget = instance->widget;
1443 /* recycle the dialog boxes */
1444 /* Disable the recycling until we can find a way to have the dialog box
1445 get reasonable layout after we modify its contents. */
1446 if (0
1447 && XtClass (widget) == xmDialogShellWidgetClass)
1448 {
1449 destroyed_instance* dead_instance =
1450 make_destroyed_instance (instance->info->name,
1451 instance->info->type,
1452 instance->widget,
1453 instance->parent,
1454 instance->pop_up_p);
1455 dead_instance->next = all_destroyed_instances;
1456 all_destroyed_instances = dead_instance;
1457 XtUnmanageChild (first_child (instance->widget));
1458 XFlush (XtDisplay (instance->widget));
1459 XtAddCallback (instance->parent, XtNdestroyCallback,
1460 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1461 }
1462 else
1463 {
1464 /* This might not be necessary now that the nosel is attached to
1465 popdown instead of destroy, but it can't hurt. */
1466 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1467 xm_nosel_callback, (XtPointer)instance);
1468 XtDestroyWidget (instance->widget);
1469 }
1470 }
1471
1472 \f/* popup utility */
1473 void
1474 xm_popup_menu (widget, event)
1475 Widget widget;
1476 XEvent *event;
1477 {
1478 XButtonPressedEvent dummy;
1479
1480 if (event == 0)
1481 {
1482 dummy.type = ButtonPress;
1483 dummy.serial = 0;
1484 dummy.send_event = 0;
1485 dummy.display = XtDisplay (widget);
1486 dummy.window = XtWindow (XtParent (widget));
1487 dummy.time = 0;
1488 dummy.button = 0;
1489 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1490 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1491 &dummy.x, &dummy.y, &dummy.state);
1492 event = (XEvent *) &dummy;
1493 }
1494
1495 if (event->type == ButtonPress || event->type == ButtonRelease)
1496 {
1497 /* This is so totally ridiculous: there's NO WAY to tell Motif
1498 that *any* button can select a menu item. Only one button
1499 can have that honor.
1500 */
1501 char *trans = 0;
1502 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1503 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1504 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1505 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1506 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1507 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1508 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1509 }
1510 XtManageChild (widget);
1511 }
1512
1513 static void
1514 set_min_dialog_size (w)
1515 Widget w;
1516 {
1517 short width;
1518 short height;
1519 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1520 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1521 }
1522
1523 void
1524 xm_pop_instance (instance, up)
1525 widget_instance* instance;
1526 Boolean up;
1527 {
1528 Widget widget = instance->widget;
1529
1530 if (XtClass (widget) == xmDialogShellWidgetClass)
1531 {
1532 Widget widget_to_manage = first_child (widget);
1533 if (up)
1534 {
1535 XtManageChild (widget_to_manage);
1536 set_min_dialog_size (widget);
1537 XtSetKeyboardFocus (instance->parent, widget);
1538 }
1539 else
1540 XtUnmanageChild (widget_to_manage);
1541 }
1542 else
1543 {
1544 if (up)
1545 XtManageChild (widget);
1546 else
1547 XtUnmanageChild (widget);
1548 }
1549 }
1550
1551 \f
1552 /* motif callback */
1553
1554 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1555
1556 static void
1557 do_call (widget, closure, type)
1558 Widget widget;
1559 XtPointer closure;
1560 enum do_call_type type;
1561 {
1562 Arg al [256];
1563 int ac;
1564 XtPointer user_data;
1565 widget_instance* instance = (widget_instance*)closure;
1566 Widget instance_widget;
1567 LWLIB_ID id;
1568
1569 if (!instance)
1570 return;
1571 if (widget->core.being_destroyed)
1572 return;
1573
1574 instance_widget = instance->widget;
1575 if (!instance_widget)
1576 return;
1577
1578 id = instance->info->id;
1579 ac = 0;
1580 user_data = NULL;
1581 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1582 XtGetValues (widget, al, ac);
1583 switch (type)
1584 {
1585 case pre_activate:
1586 if (instance->info->pre_activate_cb)
1587 instance->info->pre_activate_cb (widget, id, user_data);
1588 break;
1589 case selection:
1590 if (instance->info->selection_cb)
1591 instance->info->selection_cb (widget, id, user_data);
1592 break;
1593 case no_selection:
1594 if (instance->info->selection_cb)
1595 instance->info->selection_cb (widget, id, (XtPointer) -1);
1596 break;
1597 case post_activate:
1598 if (instance->info->post_activate_cb)
1599 instance->info->post_activate_cb (widget, id, user_data);
1600 break;
1601 default:
1602 abort ();
1603 }
1604 }
1605
1606 /* Like lw_internal_update_other_instances except that it does not do
1607 anything if its shell parent is not managed. This is to protect
1608 lw_internal_update_other_instances to dereference freed memory
1609 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1610 list */
1611 static void
1612 xm_internal_update_other_instances (widget, closure, call_data)
1613 Widget widget;
1614 XtPointer closure;
1615 XtPointer call_data;
1616 {
1617 Widget parent;
1618 for (parent = widget; parent; parent = XtParent (parent))
1619 if (XtIsShell (parent))
1620 break;
1621 else if (!XtIsManaged (parent))
1622 return;
1623 lw_internal_update_other_instances (widget, closure, call_data);
1624 }
1625
1626 static void
1627 xm_generic_callback (widget, closure, call_data)
1628 Widget widget;
1629 XtPointer closure;
1630 XtPointer call_data;
1631 {
1632 lw_internal_update_other_instances (widget, closure, call_data);
1633 do_call (widget, closure, selection);
1634 }
1635
1636 static void
1637 xm_nosel_callback (widget, closure, call_data)
1638 Widget widget;
1639 XtPointer closure;
1640 XtPointer call_data;
1641 {
1642 /* This callback is only called when a dialog box is dismissed with the wm's
1643 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1644 in that case, not just unmapped, so that it releases its keyboard grabs.
1645 But there are problems with running our callbacks while the widget is in
1646 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1647 instead of XmDESTROY and then destroy it ourself after having run the
1648 callback.
1649 */
1650 do_call (widget, closure, no_selection);
1651 XtDestroyWidget (widget);
1652 }
1653
1654 static void
1655 xm_pull_down_callback (widget, closure, call_data)
1656 Widget widget;
1657 XtPointer closure;
1658 XtPointer call_data;
1659 {
1660 do_call (widget, closure, pre_activate);
1661 }
1662
1663 static void
1664 xm_pop_down_callback (widget, closure, call_data)
1665 Widget widget;
1666 XtPointer closure;
1667 XtPointer call_data;
1668 {
1669 widget_instance *instance = (widget_instance *) closure;
1670
1671 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1672 || (XtParent (widget) == instance->parent))
1673 do_call (widget, closure, post_activate);
1674 }
1675
1676 \f
1677 /* set the keyboard focus */
1678 void
1679 xm_set_keyboard_focus (parent, w)
1680 Widget parent;
1681 Widget w;
1682 {
1683 XmProcessTraversal (w, 0);
1684 XtSetKeyboardFocus (parent, w);
1685 }
1686
1687 /* Motif hack to set the main window areas. */
1688 void
1689 xm_set_main_areas (parent, menubar, work_area)
1690 Widget parent;
1691 Widget menubar;
1692 Widget work_area;
1693 {
1694 XmMainWindowSetAreas (parent,
1695 menubar, /* menubar (maybe 0) */
1696 0, /* command area (psheets) */
1697 0, /* horizontal scroll */
1698 0, /* vertical scroll */
1699 work_area); /* work area */
1700 }
1701
1702 /* Motif hack to control resizing on the menubar. */
1703 void
1704 xm_manage_resizing (w, flag)
1705 Widget w;
1706 Boolean flag;
1707 {
1708 if (flag)
1709 {
1710 /* Enable the edit widget for resizing. */
1711 Arg al[1];
1712
1713 XtSetArg (al[0], XtNallowShellResize, 0);
1714 XtSetValues (w, al, 1);
1715 }
1716 else
1717 {
1718 /* Disable the edit widget from resizing. */
1719 Arg al[1];
1720
1721 XtSetArg (al[0], XtNallowShellResize, 0);
1722 XtSetValues (w, al, 1);
1723 }
1724 }