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