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