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