(xlw_popup_menu): New arg event.
[bpt/emacs.git] / lwlib / lwlib-Xm.c
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 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>
40 #include <Xm/MainW.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/MessageB.h>
43 #include <Xm/PanedW.h>
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
58 static void xm_pull_down_callback (/* Widget, XtPointer, XtPointer */);
59 static void xm_internal_update_other_instances (/* Widget, XtPointer,
60 XtPointer */);
61 static void xm_generic_callback (/* Widget, XtPointer, XtPointer */);
62 static void xm_nosel_callback (/* Widget, XtPointer, XtPointer */);
63 static void xm_pop_down_callback (/* Widget, XtPointer, XtPointer */);
64
65 static void xm_update_menu (/* widget_instance*, Widget, widget_value*,
66 Boolean) */);
67
68
69 \f/* Structures to keep destroyed instances */
70 typedef 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
80 static destroyed_instance*
81 all_destroyed_instances = NULL;
82
83 static destroyed_instance*
84 make_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;
90 {
91 destroyed_instance* instance =
92 (destroyed_instance*)malloc (sizeof (destroyed_instance));
93 instance->name = safe_strdup (name);
94 instance->type = safe_strdup (type);
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
102 static void
103 free_destroyed_instance (instance)
104 destroyed_instance* instance;
105 {
106 free (instance->name);
107 free (instance->type);
108 free (instance);
109 }
110
111 \f/* motif utility functions */
112 Widget
113 first_child (widget)
114 Widget widget;
115 {
116 return ((CompositeWidget)widget)->composite.children [0];
117 }
118
119 Boolean
120 lw_motif_widget_p (widget)
121 Widget widget;
122 {
123 return
124 XtClass (widget) == xmDialogShellWidgetClass
125 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
126 }
127
128 static XmString
129 resource_motif_string (widget, name)
130 Widget widget;
131 char* name;
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
149 static void
150 destroy_all_children (widget)
151 Widget widget;
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 */
176 static void
177 xm_update_label (instance, widget, val)
178 widget_instance* instance;
179 Widget widget;
180 widget_value* val;
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 */
224 static void
225 xm_update_list (instance, widget, val)
226 widget_instance* instance;
227 Widget widget;
228 widget_value* val;
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 */
248 static void
249 xm_update_pushbutton (instance, widget, val)
250 widget_instance* instance;
251 Widget widget;
252 widget_value* val;
253 {
254 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
255 XtRemoveAllCallbacks (widget, XmNactivateCallback);
256 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
257 }
258
259 static void
260 xm_update_cascadebutton (instance, widget, val)
261 widget_instance* instance;
262 Widget widget;
263 widget_value* val;
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 */
272 static void
273 xm_update_toggle (instance, widget, val)
274 widget_instance* instance;
275 Widget widget;
276 widget_value* val;
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
285 static void
286 xm_update_radiobox (instance, widget, val)
287 widget_instance* instance;
288 Widget widget;
289 widget_value* val;
290
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 */
328 static Boolean
329 all_dashes_p (s)
330 char* s;
331 {
332 char* t;
333 for (t = s; *t; t++)
334 if (*t != '-')
335 return False;
336 return True;
337 }
338
339 static void
340 make_menu_in_widget (instance, widget, val)
341 widget_instance* instance;
342 Widget widget;
343 widget_value* val;
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
377 if (instance->pop_up_p && !cur->contents && !cur->call_data
378 && !all_dashes_p (cur->name))
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))
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 {
406 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
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
434 static void
435 update_one_menu_entry (instance, widget, val, deep_p)
436 widget_instance* instance;
437 Widget widget;
438 widget_value* val;
439 Boolean deep_p;
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 {
472 menu = XmCreatePulldownMenu (XtParent (widget), XtName (widget), NULL, 0);
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
490 static void
491 xm_update_menu (instance, widget, val, deep_p)
492 widget_instance* instance;
493 Widget widget;
494 widget_value* val;
495 Boolean deep_p;
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
535 static void
536 xm_update_text (instance, widget, val)
537 widget_instance* instance;
538 Widget widget;
539 widget_value* val;
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
549 static void
550 xm_update_text_field (instance, widget, val)
551 widget_instance* instance;
552 Widget widget;
553 widget_value* val;
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
566 void
567 xm_update_one_widget (instance, widget, val, deep_p)
568 widget_instance* instance;
569 Widget widget;
570 widget_value* val;
571 Boolean deep_p;
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 */
633 void
634 xm_update_one_value (instance, widget, val)
635 widget_instance* instance;
636 Widget widget;
637 widget_value* val;
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);
692 val->value = safe_strdup (XtName (toggle));
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;
716 val->value = safe_strdup (cur->name);
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 */
732 static void
733 activate_button (widget, closure, call_data)
734 Widget widget;
735 XtPointer closure;
736 XtPointer call_data;
737 {
738 Widget button = (Widget)closure;
739 XtCallCallbacks (button, XmNactivateCallback, NULL);
740 }
741
742 /* creation functions */
743
744 /* dialogs */
745 static Widget
746 make_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;
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
796 n_children = left_buttons + right_buttons + 1;
797 ac = 0;
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++;
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 }
829 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
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;
855 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
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
1004 static destroyed_instance*
1005 find_matching_instance (instance)
1006 widget_instance* instance;
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
1042 static void
1043 mark_dead_instance_destroyed (widget, closure, call_data)
1044 Widget widget;
1045 XtPointer closure;
1046 XtPointer call_data;
1047 {
1048 destroyed_instance* instance = (destroyed_instance*)closure;
1049 instance->widget = NULL;
1050 }
1051
1052 static void
1053 recenter_widget (widget)
1054 Widget widget;
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
1089 static Widget
1090 recycle_instance (instance)
1091 destroyed_instance* instance;
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
1126 Widget
1127 xm_create_dialog (instance)
1128 widget_instance* instance;
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
1203 static Widget
1204 make_menubar (instance)
1205 widget_instance* instance;
1206 {
1207 return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
1208 }
1209
1210 static void
1211 remove_grabs (shell, closure, call_data)
1212 Widget shell;
1213 XtPointer closure;
1214 XtPointer call_data;
1215 {
1216 Widget menu = (Widget) closure;
1217 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1218 }
1219
1220 static Widget
1221 make_popup_menu (instance)
1222 widget_instance* instance;
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 }
1236 static Widget
1237 make_main (instance)
1238 widget_instance* instance;
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 }
1251
1252 \f/* Table of functions to create widgets */
1253
1254 #ifdef ENERGIZE
1255
1256 /* interface with the XDesigner generated functions */
1257 typedef Widget (*widget_maker) (Widget);
1258 extern Widget create_project_p_sheet (Widget parent);
1259 extern Widget create_debugger_p_sheet (Widget parent);
1260 extern Widget create_breaklist_p_sheet (Widget parent);
1261 extern Widget create_le_browser_p_sheet (Widget parent);
1262 extern Widget create_class_browser_p_sheet (Widget parent);
1263 extern Widget create_call_browser_p_sheet (Widget parent);
1264 extern Widget create_build_dialog (Widget parent);
1265 extern Widget create_editmode_dialog (Widget parent);
1266 extern Widget create_search_dialog (Widget parent);
1267 extern Widget create_project_display_dialog (Widget parent);
1268
1269 static Widget
1270 make_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
1292 static Widget
1293 make_project_p_sheet (widget_instance* instance)
1294 {
1295 return make_one (instance, create_project_p_sheet);
1296 }
1297
1298 static Widget
1299 make_debugger_p_sheet (widget_instance* instance)
1300 {
1301 return make_one (instance, create_debugger_p_sheet);
1302 }
1303
1304 static Widget
1305 make_breaklist_p_sheet (widget_instance* instance)
1306 {
1307 return make_one (instance, create_breaklist_p_sheet);
1308 }
1309
1310 static Widget
1311 make_le_browser_p_sheet (widget_instance* instance)
1312 {
1313 return make_one (instance, create_le_browser_p_sheet);
1314 }
1315
1316 static Widget
1317 make_class_browser_p_sheet (widget_instance* instance)
1318 {
1319 return make_one (instance, create_class_browser_p_sheet);
1320 }
1321
1322 static Widget
1323 make_call_browser_p_sheet (widget_instance* instance)
1324 {
1325 return make_one (instance, create_call_browser_p_sheet);
1326 }
1327
1328 static Widget
1329 make_build_dialog (widget_instance* instance)
1330 {
1331 return make_one (instance, create_build_dialog);
1332 }
1333
1334 static Widget
1335 make_editmode_dialog (widget_instance* instance)
1336 {
1337 return make_one (instance, create_editmode_dialog);
1338 }
1339
1340 static Widget
1341 make_search_dialog (widget_instance* instance)
1342 {
1343 return make_one (instance, create_search_dialog);
1344 }
1345
1346 static Widget
1347 make_project_display_dialog (widget_instance* instance)
1348 {
1349 return make_one (instance, create_project_display_dialog);
1350 }
1351
1352 #endif /* ENERGIZE */
1353
1354 widget_creation_entry
1355 xm_creation_table [] =
1356 {
1357 {"menubar", make_menubar},
1358 {"popup", make_popup_menu},
1359 {"main", make_main},
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 */
1376 void
1377 xm_destroy_instance (instance)
1378 widget_instance* instance;
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 */
1411 void
1412 xm_popup_menu (widget)
1413 Widget widget;
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
1448 static void
1449 set_min_dialog_size (w)
1450 Widget w;
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
1458 void
1459 xm_pop_instance (instance, up)
1460 widget_instance* instance;
1461 Boolean up;
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
1489 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1490
1491 static void
1492 do_call (widget, closure, type)
1493 Widget widget;
1494 XtPointer closure;
1495 enum do_call_type type;
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 */
1546 static void
1547 xm_internal_update_other_instances (widget, closure, call_data)
1548 Widget widget;
1549 XtPointer closure;
1550 XtPointer call_data;
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
1561 static void
1562 xm_generic_callback (widget, closure, call_data)
1563 Widget widget;
1564 XtPointer closure;
1565 XtPointer call_data;
1566 {
1567 lw_internal_update_other_instances (widget, closure, call_data);
1568 do_call (widget, closure, selection);
1569 }
1570
1571 static void
1572 xm_nosel_callback (widget, closure, call_data)
1573 Widget widget;
1574 XtPointer closure;
1575 XtPointer call_data;
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
1589 static void
1590 xm_pull_down_callback (widget, closure, call_data)
1591 Widget widget;
1592 XtPointer closure;
1593 XtPointer call_data;
1594 {
1595 do_call (widget, closure, pre_activate);
1596 }
1597
1598 static void
1599 xm_pop_down_callback (widget, closure, call_data)
1600 Widget widget;
1601 XtPointer closure;
1602 XtPointer call_data;
1603 {
1604 widget_instance *instance = (widget_instance *) closure;
1605
1606 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1607 || (XtParent (widget) == instance->parent))
1608 do_call (widget, closure, post_activate);
1609 }
1610
1611 \f
1612 /* set the keyboard focus */
1613 void
1614 xm_set_keyboard_focus (parent, w)
1615 Widget parent;
1616 Widget w;
1617 {
1618 XmProcessTraversal (w, 0);
1619 XtSetKeyboardFocus (parent, w);
1620 }
1621
1622 /* Motif hack to set the main window areas. */
1623 void
1624 xm_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. */
1638 void
1639 xm_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 }