(make_menubar): Turn off menu accelerator.
[emacs.git] / lwlib / lwlib-Xm.c
blobc5da97f85ed4e60f8844e75dcd8f39f874951f12
1 /* The lwlib interface to Motif widgets.
2 Copyright (C) 1992 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
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.
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.
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. */
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdio.h>
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>
32 #include "lwlib-Xm.h"
33 #include "lwlib-utils.h"
35 #include <Xm/BulletinB.h>
36 #include <Xm/CascadeB.h>
37 #include <Xm/CascadeBG.h>
38 #include <Xm/DrawingA.h>
39 #include <Xm/FileSB.h>
40 #include <Xm/Label.h>
41 #include <Xm/List.h>
42 #include <Xm/MainW.h>
43 #include <Xm/MenuShell.h>
44 #include <Xm/MessageB.h>
45 #include <Xm/PanedW.h>
46 #include <Xm/PushB.h>
47 #include <Xm/PushBG.h>
48 #include <Xm/ArrowB.h>
49 #include <Xm/SelectioB.h>
50 #include <Xm/Text.h>
51 #include <Xm/TextF.h>
52 #include <Xm/ToggleB.h>
53 #include <Xm/ToggleBG.h>
54 #include <Xm/RowColumn.h>
55 #include <Xm/ScrolledW.h>
56 #include <Xm/Separator.h>
57 #include <Xm/DialogS.h>
58 #include <Xm/Form.h>
60 static void xm_pull_down_callback (/* Widget, XtPointer, XtPointer */);
61 static void xm_internal_update_other_instances (/* Widget, XtPointer,
62 XtPointer */);
63 static void xm_generic_callback (/* Widget, XtPointer, XtPointer */);
64 static void xm_nosel_callback (/* Widget, XtPointer, XtPointer */);
65 static void xm_pop_down_callback (/* Widget, XtPointer, XtPointer */);
67 static void xm_update_menu (/* widget_instance*, Widget, widget_value*,
68 Boolean) */);
71 \f/* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
74 char* name;
75 char* type;
76 Widget widget;
77 Widget parent;
78 Boolean pop_up_p;
79 struct _destroyed_instance* next;
80 } destroyed_instance;
82 static destroyed_instance*
83 all_destroyed_instances = NULL;
85 static destroyed_instance*
86 make_destroyed_instance (name, type, widget, parent, pop_up_p)
87 char* name;
88 char* type;
89 Widget widget;
90 Widget parent;
91 Boolean pop_up_p;
93 destroyed_instance* instance =
94 (destroyed_instance*)malloc (sizeof (destroyed_instance));
95 instance->name = safe_strdup (name);
96 instance->type = safe_strdup (type);
97 instance->widget = widget;
98 instance->parent = parent;
99 instance->pop_up_p = pop_up_p;
100 instance->next = NULL;
101 return instance;
104 static void
105 free_destroyed_instance (instance)
106 destroyed_instance* instance;
108 free (instance->name);
109 free (instance->type);
110 free (instance);
113 \f/* motif utility functions */
114 Widget
115 first_child (widget)
116 Widget widget;
118 return ((CompositeWidget)widget)->composite.children [0];
121 Boolean
122 lw_motif_widget_p (widget)
123 Widget widget;
125 return
126 XtClass (widget) == xmDialogShellWidgetClass
127 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
130 static XmString
131 resource_motif_string (widget, name)
132 Widget widget;
133 char* name;
135 XtResource resource;
136 XmString result = 0;
138 resource.resource_name = name;
139 resource.resource_class = XmCXmString;
140 resource.resource_type = XmRXmString;
141 resource.resource_size = sizeof (XmString);
142 resource.resource_offset = 0;
143 resource.default_type = XtRImmediate;
144 resource.default_addr = 0;
146 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
147 "DialogString", &resource, 1, NULL, 0);
148 return result;
151 /* Destroy all of the children of WIDGET
152 starting with number FIRST_CHILD_TO_DESTROY. */
154 static void
155 destroy_all_children (widget, first_child_to_destroy)
156 Widget widget;
157 int first_child_to_destroy;
159 Widget* children;
160 unsigned int number;
161 int i;
163 children = XtCompositeChildren (widget, &number);
164 if (children)
166 XtUnmanageChildren (children + first_child_to_destroy,
167 number - first_child_to_destroy);
169 /* Unmanage all children and destroy them. They will only be
170 really destroyed when we get out of DispatchEvent. */
171 for (i = first_child_to_destroy; i < number; i++)
173 Arg al[2];
174 Widget submenu = 0;
175 /* Cascade buttons have submenus,and these submenus
176 need to be freed. But they are not included in
177 XtCompositeChildren. So get it out of the cascade button
178 and free it. If this child is not a cascade button,
179 then submenu should remain unchanged. */
180 XtSetArg (al[0], XmNsubMenuId, &submenu);
181 XtGetValues (children[i], al, 1);
182 if (submenu)
183 XtDestroyWidget (submenu);
184 XtDestroyWidget (children[i]);
187 XtFree ((char *) children);
191 \f/* update the label of anything subclass of a label */
192 static void
193 xm_update_label (instance, widget, val)
194 widget_instance* instance;
195 Widget widget;
196 widget_value* val;
198 XmString res_string = 0;
199 XmString built_string = 0;
200 XmString key_string = 0;
201 Arg al [256];
202 int ac;
204 ac = 0;
206 if (val->value)
208 res_string = resource_motif_string (widget, val->value);
210 if (res_string)
212 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
214 else
216 built_string =
217 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
218 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
220 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
223 if (val->key)
225 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
226 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
229 if (ac)
230 XtSetValues (widget, al, ac);
232 if (built_string)
233 XmStringFree (built_string);
235 if (key_string)
236 XmStringFree (key_string);
239 \f/* update of list */
240 static void
241 xm_update_list (instance, widget, val)
242 widget_instance* instance;
243 Widget widget;
244 widget_value* val;
246 widget_value* cur;
247 int i;
248 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
249 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
250 instance);
251 for (cur = val->contents, i = 0; cur; cur = cur->next)
252 if (cur->value)
254 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
255 i += 1;
256 XmListAddItem (widget, xmstr, 0);
257 if (cur->selected)
258 XmListSelectPos (widget, i, False);
259 XmStringFree (xmstr);
263 \f/* update of buttons */
264 static void
265 xm_update_pushbutton (instance, widget, val)
266 widget_instance* instance;
267 Widget widget;
268 widget_value* val;
270 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
271 XtRemoveAllCallbacks (widget, XmNactivateCallback);
272 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
275 static void
276 xm_update_cascadebutton (instance, widget, val)
277 widget_instance* instance;
278 Widget widget;
279 widget_value* val;
281 /* Should also rebuild the menu by calling ...update_menu... */
282 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
283 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
284 instance);
287 \f/* update toggle and radiobox */
288 static void
289 xm_update_toggle (instance, widget, val)
290 widget_instance* instance;
291 Widget widget;
292 widget_value* val;
294 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
295 XtAddCallback (widget, XmNvalueChangedCallback,
296 xm_internal_update_other_instances, instance);
297 XtVaSetValues (widget, XmNset, val->selected,
298 XmNalignment, XmALIGNMENT_BEGINNING, 0);
301 static void
302 xm_update_radiobox (instance, widget, val)
303 widget_instance* instance;
304 Widget widget;
305 widget_value* val;
308 Widget toggle;
309 widget_value* cur;
311 /* update the callback */
312 XtRemoveAllCallbacks (widget, XmNentryCallback);
313 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
315 /* first update all the toggles */
316 /* Energize kernel interface is currently bad. It sets the selected widget
317 with the selected flag but returns it by its name. So we currently
318 have to support both setting the selection with the selected slot
319 of val contents and setting it with the "value" slot of val. The latter
320 has a higher priority. This to be removed when the kernel is fixed. */
321 for (cur = val->contents; cur; cur = cur->next)
323 toggle = XtNameToWidget (widget, cur->value);
324 if (toggle)
326 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
327 if (!val->value && cur->selected)
328 XtVaSetValues (toggle, XmNset, cur->selected, 0);
329 if (val->value && strcmp (val->value, cur->value))
330 XtVaSetValues (toggle, XmNset, False, 0);
334 /* The selected was specified by the value slot */
335 if (val->value)
337 toggle = XtNameToWidget (widget, val->value);
338 if (toggle)
339 XtVaSetValues (toggle, XmNset, True, 0);
343 \f/* update a popup menu, pulldown menu or a menubar */
344 static Boolean
345 all_dashes_p (s)
346 char* s;
348 char* t;
349 for (t = s; *t; t++)
350 if (*t != '-')
351 return False;
352 return True;
355 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
357 static void
358 make_menu_in_widget (instance, widget, val, keep_first_children)
359 widget_instance* instance;
360 Widget widget;
361 widget_value* val;
362 int keep_first_children;
364 Widget* children = 0;
365 int num_children;
366 int child_index;
367 widget_value* cur;
368 Widget button = 0;
369 Widget menu;
370 Arg al [256];
371 int ac;
372 Boolean menubar_p;
374 Widget* old_children;
375 unsigned int old_num_children;
377 old_children = XtCompositeChildren (widget, &old_num_children);
379 /* Allocate the children array */
380 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
381 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
383 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
384 menubar_p = False;
385 XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
386 XtGetValues (widget, al, 1);
388 /* add the unmap callback for popups and pulldowns */
389 /*** this sounds bogus ***/
390 if (!menubar_p)
391 XtAddCallback (XtParent (widget), XmNpopdownCallback,
392 xm_pop_down_callback, (XtPointer)instance);
394 /* Preserve the first KEEP_FIRST_CHILDREN old children. */
395 for (child_index = 0, cur = val; child_index < keep_first_children;
396 child_index++, cur = cur->next)
397 children[child_index] = old_children[child_index];
399 /* Check that those are all we have
400 (the caller should have deleted the rest). */
401 if (old_num_children != keep_first_children)
402 abort ();
404 /* Create the rest. */
405 for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
407 ac = 0;
408 XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
409 XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
410 XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
412 if (instance->pop_up_p && !cur->contents && !cur->call_data
413 && !all_dashes_p (cur->name))
415 ac = 0;
416 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
417 button = XmCreateLabel (widget, cur->name, al, ac);
419 else if (all_dashes_p (cur->name))
421 button = XmCreateSeparator (widget, cur->name, NULL, 0);
423 else if (!cur->contents)
425 if (menubar_p)
426 button = XmCreateCascadeButton (widget, cur->name, al, ac);
427 else if (!cur->call_data)
428 button = XmCreateLabel (widget, cur->name, al, ac);
429 else
430 button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
432 xm_update_label (instance, button, cur);
434 /* don't add a callback to a simple label */
435 if (cur->call_data)
436 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
437 (XtPointer)instance);
439 else
441 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
442 make_menu_in_widget (instance, menu, cur->contents, 0);
443 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
444 /* non-zero values don't work reliably in
445 conjunction with Emacs' event loop */
446 XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
447 button = XmCreateCascadeButtonGadget (widget, cur->name, al, ac);
449 xm_update_label (instance, button, cur);
451 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
452 (XtPointer)instance);
455 children [child_index] = button;
458 XtManageChildren (children, num_children);
460 /* Last entry is the help button. Has to be done after managing
461 * the buttons otherwise the menubar is only 4 pixels high... */
462 if (button)
464 ac = 0;
465 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
466 XtSetValues (widget, al, ac);
469 XtFree ((char *) children);
470 if (old_children)
471 XtFree ((char *) old_children);
474 static void
475 update_one_menu_entry (instance, widget, val, deep_p)
476 widget_instance* instance;
477 Widget widget;
478 widget_value* val;
479 Boolean deep_p;
481 Arg al [256];
482 int ac;
483 Widget menu;
484 widget_value* contents;
486 if (val->this_one_change == NO_CHANGE)
487 return;
489 /* update the sensitivity and userdata */
490 /* Common to all widget types */
491 XtVaSetValues (widget,
492 XmNsensitive, val->enabled,
493 XmNuserData, val->call_data,
496 /* update the menu button as a label. */
497 if (val->this_one_change >= VISIBLE_CHANGE)
498 xm_update_label (instance, widget, val);
500 /* update the pulldown/pullaside as needed */
501 ac = 0;
502 menu = NULL;
503 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
504 XtGetValues (widget, al, ac);
506 contents = val->contents;
508 if (!menu)
510 if (contents)
512 menu = XmCreatePulldownMenu (XtParent (widget), XtName (widget), NULL, 0);
513 make_menu_in_widget (instance, menu, contents, 0);
514 ac = 0;
515 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
516 XtSetValues (widget, al, ac);
519 else if (!contents)
521 ac = 0;
522 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
523 XtSetValues (widget, al, ac);
524 XtDestroyWidget (menu);
526 else if (deep_p && contents->change != NO_CHANGE)
527 xm_update_menu (instance, menu, val, 1);
530 static void
531 xm_update_menu (instance, widget, val, deep_p)
532 widget_instance* instance;
533 Widget widget;
534 widget_value* val;
535 Boolean deep_p;
537 Widget* children;
538 unsigned int num_children;
539 int num_children_to_keep = 0;
540 int i;
541 widget_value* cur;
543 children = XtCompositeChildren (widget, &num_children);
545 /* Widget is a RowColumn widget whose contents have to be updated
546 * to reflect the list of items in val->contents */
548 /* See how many buttons we can keep, and how many we
549 must completely replace. */
550 if (val->contents == 0)
551 num_children_to_keep = 0;
552 else if (val->contents->change == STRUCTURAL_CHANGE)
554 if (children)
556 for (i = 0, cur = val->contents;
557 (i < num_children
558 && cur); /* how else to ditch unwanted children ?? - mgd */
559 i++, cur = cur->next)
561 if (cur->this_one_change == STRUCTURAL_CHANGE)
562 break;
565 num_children_to_keep = i;
568 else
569 num_children_to_keep = num_children;
571 /* Update all the buttons of the RowColumn, in order,
572 except for those we are going to replace entirely. */
573 if (children)
575 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
577 if (!cur)
578 abort ();
579 if (children [i]->core.being_destroyed
580 || strcmp (XtName (children [i]), cur->name))
581 continue;
582 update_one_menu_entry (instance, children [i], cur, deep_p);
583 cur = cur->next;
587 /* Now replace from scratch all the buttons after the last
588 place that the top-level structure changed. */
589 if (val->contents->change == STRUCTURAL_CHANGE)
591 destroy_all_children (widget, num_children_to_keep);
592 make_menu_in_widget (instance, widget, val->contents,
593 num_children_to_keep);
596 XtFree ((char *) children);
600 /* update text widgets */
602 static void
603 xm_update_text (instance, widget, val)
604 widget_instance* instance;
605 Widget widget;
606 widget_value* val;
608 XmTextSetString (widget, val->value ? val->value : "");
609 XtRemoveAllCallbacks (widget, XmNactivateCallback);
610 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
611 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
612 XtAddCallback (widget, XmNvalueChangedCallback,
613 xm_internal_update_other_instances, instance);
616 static void
617 xm_update_text_field (instance, widget, val)
618 widget_instance* instance;
619 Widget widget;
620 widget_value* val;
622 XmTextFieldSetString (widget, val->value ? val->value : "");
623 XtRemoveAllCallbacks (widget, XmNactivateCallback);
624 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
625 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
626 XtAddCallback (widget, XmNvalueChangedCallback,
627 xm_internal_update_other_instances, instance);
631 /* update a motif widget */
633 void
634 xm_update_one_widget (instance, widget, val, deep_p)
635 widget_instance* instance;
636 Widget widget;
637 widget_value* val;
638 Boolean deep_p;
640 WidgetClass class;
642 /* Mark as not edited */
643 val->edited = False;
645 /* Common to all widget types */
646 XtVaSetValues (widget,
647 XmNsensitive, val->enabled,
648 XmNuserData, val->call_data,
651 /* Common to all label like widgets */
652 if (XtIsSubclass (widget, xmLabelWidgetClass))
653 xm_update_label (instance, widget, val);
655 class = XtClass (widget);
656 /* Class specific things */
657 if (class == xmPushButtonWidgetClass ||
658 class == xmArrowButtonWidgetClass)
660 xm_update_pushbutton (instance, widget, val);
662 else if (class == xmCascadeButtonWidgetClass)
664 xm_update_cascadebutton (instance, widget, val);
666 else if (class == xmToggleButtonWidgetClass
667 || class == xmToggleButtonGadgetClass)
669 xm_update_toggle (instance, widget, val);
671 else if (class == xmRowColumnWidgetClass)
673 Boolean radiobox = 0;
674 int ac = 0;
675 Arg al [1];
677 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
678 XtGetValues (widget, al, ac);
680 if (radiobox)
681 xm_update_radiobox (instance, widget, val);
682 else
683 xm_update_menu (instance, widget, val, deep_p);
685 else if (class == xmTextWidgetClass)
687 xm_update_text (instance, widget, val);
689 else if (class == xmTextFieldWidgetClass)
691 xm_update_text_field (instance, widget, val);
693 else if (class == xmListWidgetClass)
695 xm_update_list (instance, widget, val);
699 \f/* getting the value back */
700 void
701 xm_update_one_value (instance, widget, val)
702 widget_instance* instance;
703 Widget widget;
704 widget_value* val;
706 WidgetClass class = XtClass (widget);
707 widget_value *old_wv;
709 /* copy the call_data slot into the "return" widget_value */
710 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
711 if (!strcmp (val->name, old_wv->name))
713 val->call_data = old_wv->call_data;
714 break;
717 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
719 XtVaGetValues (widget, XmNset, &val->selected, 0);
720 val->edited = True;
722 else if (class == xmTextWidgetClass)
724 if (val->value)
725 free (val->value);
726 val->value = XmTextGetString (widget);
727 val->edited = True;
729 else if (class == xmTextFieldWidgetClass)
731 if (val->value)
732 free (val->value);
733 val->value = XmTextFieldGetString (widget);
734 val->edited = True;
736 else if (class == xmRowColumnWidgetClass)
738 Boolean radiobox = 0;
739 int ac = 0;
740 Arg al [1];
742 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
743 XtGetValues (widget, al, ac);
745 if (radiobox)
747 CompositeWidget radio = (CompositeWidget)widget;
748 int i;
749 for (i = 0; i < radio->composite.num_children; i++)
751 int set = False;
752 Widget toggle = radio->composite.children [i];
754 XtVaGetValues (toggle, XmNset, &set, 0);
755 if (set)
757 if (val->value)
758 free (val->value);
759 val->value = safe_strdup (XtName (toggle));
762 val->edited = True;
765 else if (class == xmListWidgetClass)
767 int pos_cnt;
768 int* pos_list;
769 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
771 int i;
772 widget_value* cur;
773 for (cur = val->contents, i = 0; cur; cur = cur->next)
774 if (cur->value)
776 int j;
777 cur->selected = False;
778 i += 1;
779 for (j = 0; j < pos_cnt; j++)
780 if (pos_list [j] == i)
782 cur->selected = True;
783 val->value = safe_strdup (cur->name);
786 val->edited = 1;
787 XtFree ((char *) pos_list);
793 /* This function is for activating a button from a program. It's wrong because
794 we pass a NULL argument in the call_data which is not Motif compatible.
795 This is used from the XmNdefaultAction callback of the List widgets to
796 have a double-click put down a dialog box like the button would do.
797 I could not find a way to do that with accelerators.
799 static void
800 activate_button (widget, closure, call_data)
801 Widget widget;
802 XtPointer closure;
803 XtPointer call_data;
805 Widget button = (Widget)closure;
806 XtCallCallbacks (button, XmNactivateCallback, NULL);
809 /* creation functions */
811 /* dialogs */
812 static Widget
813 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
814 radio_box, list, left_buttons, right_buttons)
815 char* name;
816 Widget parent;
817 Boolean pop_up_p;
818 char* shell_title;
819 char* icon_name;
820 Boolean text_input_slot;
821 Boolean radio_box;
822 Boolean list;
823 int left_buttons;
824 int right_buttons;
826 Widget result;
827 Widget form;
828 Widget row;
829 Widget icon;
830 Widget icon_separator;
831 Widget message;
832 Widget value = 0;
833 Widget separator;
834 Widget button = 0;
835 Widget children [16]; /* for the final XtManageChildren */
836 int n_children;
837 Arg al[64]; /* Arg List */
838 int ac; /* Arg Count */
839 int i;
841 if (pop_up_p)
843 ac = 0;
844 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
845 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
846 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
847 result = XmCreateDialogShell (parent, "dialog", al, ac);
848 ac = 0;
849 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
850 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
851 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
852 form = XmCreateForm (result, shell_title, al, ac);
854 else
856 ac = 0;
857 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
858 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
859 form = XmCreateForm (parent, shell_title, al, ac);
860 result = form;
863 n_children = left_buttons + right_buttons + 1;
864 ac = 0;
865 XtSetArg(al[ac], XmNpacking, n_children == 3?
866 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
867 XtSetArg(al[ac], XmNorientation, n_children == 3?
868 XmVERTICAL: XmHORIZONTAL); ac++;
869 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
870 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
871 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
872 XtSetArg(al[ac], XmNspacing, 13); ac++;
873 XtSetArg(al[ac], XmNadjustLast, False); ac++;
874 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
875 XtSetArg(al[ac], XmNisAligned, True); ac++;
876 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
877 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
878 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
879 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
880 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
881 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
882 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
883 row = XmCreateRowColumn (form, "row", al, ac);
885 n_children = 0;
886 for (i = 0; i < left_buttons; i++)
888 char button_name [16];
889 sprintf (button_name, "button%d", i + 1);
890 ac = 0;
891 if (i == 0)
893 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
894 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
896 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
897 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
898 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
900 if (i == 0)
902 button = children [n_children];
903 ac = 0;
904 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
905 XtSetValues (row, al, ac);
908 n_children++;
911 /* invisible separator button */
912 ac = 0;
913 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
914 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
915 n_children++;
917 for (i = 0; i < right_buttons; i++)
919 char button_name [16];
920 sprintf (button_name, "button%d", left_buttons + i + 1);
921 ac = 0;
922 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
923 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
924 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
925 if (! button) button = children [n_children];
926 n_children++;
929 XtManageChildren (children, n_children);
931 ac = 0;
932 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
933 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
934 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
935 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
936 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
937 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
938 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
939 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
940 separator = XmCreateSeparator (form, "", al, ac);
942 ac = 0;
943 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
944 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
945 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
946 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
947 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
948 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
949 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
950 icon = XmCreateLabel (form, icon_name, al, ac);
952 ac = 0;
953 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
954 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
955 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
956 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
957 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
958 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
959 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
960 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
961 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
962 icon_separator = XmCreateLabel (form, "", al, ac);
964 if (text_input_slot)
966 ac = 0;
967 XtSetArg(al[ac], XmNcolumns, 50); ac++;
968 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
969 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
970 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
971 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
972 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
973 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
974 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
975 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
976 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
977 value = XmCreateTextField (form, "value", al, ac);
979 else if (radio_box)
981 Widget radio_butt;
982 ac = 0;
983 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
984 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
985 XtSetArg(al[ac], XmNspacing, 13); ac++;
986 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
987 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
988 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
989 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
990 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
991 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
992 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
993 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
994 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
995 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
996 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
997 ac = 0;
998 i = 0;
999 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1000 children [i++] = radio_butt;
1001 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1002 children [i++] = radio_butt;
1003 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1004 children [i++] = radio_butt;
1005 XtManageChildren (children, i);
1007 else if (list)
1009 ac = 0;
1010 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1011 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1012 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1013 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1014 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1015 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1016 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1017 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1018 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1019 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1020 value = XmCreateScrolledList (form, "list", al, ac);
1022 /* this is the easiest way I found to have the dble click in the
1023 list activate the default button */
1024 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1027 ac = 0;
1028 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1029 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1030 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1031 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1032 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1033 XtSetArg(al[ac], XmNbottomWidget,
1034 text_input_slot || radio_box || list ? value : separator); ac++;
1035 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1036 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1037 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1038 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1039 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1040 message = XmCreateLabel (form, "message", al, ac);
1042 if (list)
1043 XtManageChild (value);
1045 i = 0;
1046 children [i] = row; i++;
1047 children [i] = separator; i++;
1048 if (text_input_slot || radio_box)
1050 children [i] = value; i++;
1052 children [i] = message; i++;
1053 children [i] = icon; i++;
1054 children [i] = icon_separator; i++;
1055 XtManageChildren (children, i);
1057 if (text_input_slot || list)
1059 XtInstallAccelerators (value, button);
1060 XtSetKeyboardFocus (result, value);
1062 else
1064 XtInstallAccelerators (form, button);
1065 XtSetKeyboardFocus (result, button);
1068 return result;
1071 static destroyed_instance*
1072 find_matching_instance (instance)
1073 widget_instance* instance;
1075 destroyed_instance* cur;
1076 destroyed_instance* prev;
1077 char* type = instance->info->type;
1078 char* name = instance->info->name;
1080 for (prev = NULL, cur = all_destroyed_instances;
1081 cur;
1082 prev = cur, cur = cur->next)
1084 if (!strcmp (cur->name, name)
1085 && !strcmp (cur->type, type)
1086 && cur->parent == instance->parent
1087 && cur->pop_up_p == instance->pop_up_p)
1089 if (prev)
1090 prev->next = cur->next;
1091 else
1092 all_destroyed_instances = cur->next;
1093 return cur;
1095 /* do some cleanup */
1096 else if (!cur->widget)
1098 if (prev)
1099 prev->next = cur->next;
1100 else
1101 all_destroyed_instances = cur->next;
1102 free_destroyed_instance (cur);
1103 cur = prev ? prev : all_destroyed_instances;
1106 return NULL;
1109 static void
1110 mark_dead_instance_destroyed (widget, closure, call_data)
1111 Widget widget;
1112 XtPointer closure;
1113 XtPointer call_data;
1115 destroyed_instance* instance = (destroyed_instance*)closure;
1116 instance->widget = NULL;
1119 static void
1120 recenter_widget (widget)
1121 Widget widget;
1123 Widget parent = XtParent (widget);
1124 Screen* screen = XtScreen (widget);
1125 Dimension screen_width = WidthOfScreen (screen);
1126 Dimension screen_height = HeightOfScreen (screen);
1127 Dimension parent_width = 0;
1128 Dimension parent_height = 0;
1129 Dimension child_width = 0;
1130 Dimension child_height = 0;
1131 Position x;
1132 Position y;
1134 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1135 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1138 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1139 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1141 XtTranslateCoords (parent, x, y, &x, &y);
1143 if (x + child_width > screen_width)
1144 x = screen_width - child_width;
1145 if (x < 0)
1146 x = 0;
1148 if (y + child_height > screen_height)
1149 y = screen_height - child_height;
1150 if (y < 0)
1151 y = 0;
1153 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1156 static Widget
1157 recycle_instance (instance)
1158 destroyed_instance* instance;
1160 Widget widget = instance->widget;
1162 /* widget is NULL if the parent was destroyed. */
1163 if (widget)
1165 Widget focus;
1166 Widget separator;
1168 /* Remove the destroy callback as the instance is not in the list
1169 anymore */
1170 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1171 mark_dead_instance_destroyed,
1172 (XtPointer)instance);
1174 /* Give the focus to the initial item */
1175 focus = XtNameToWidget (widget, "*value");
1176 if (!focus)
1177 focus = XtNameToWidget (widget, "*button1");
1178 if (focus)
1179 XtSetKeyboardFocus (widget, focus);
1181 /* shrink the separator label back to their original size */
1182 separator = XtNameToWidget (widget, "*separator_button");
1183 if (separator)
1184 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1186 /* Center the dialog in its parent */
1187 recenter_widget (widget);
1189 free_destroyed_instance (instance);
1190 return widget;
1193 Widget
1194 xm_create_dialog (instance)
1195 widget_instance* instance;
1197 char* name = instance->info->type;
1198 Widget parent = instance->parent;
1199 Widget widget;
1200 Boolean pop_up_p = instance->pop_up_p;
1201 char* shell_name = 0;
1202 char* icon_name;
1203 Boolean text_input_slot = False;
1204 Boolean radio_box = False;
1205 Boolean list = False;
1206 int total_buttons;
1207 int left_buttons = 0;
1208 int right_buttons = 1;
1209 destroyed_instance* dead_one;
1211 /* try to find a widget to recycle */
1212 dead_one = find_matching_instance (instance);
1213 if (dead_one)
1215 Widget recycled_widget = recycle_instance (dead_one);
1216 if (recycled_widget)
1217 return recycled_widget;
1220 switch (name [0]){
1221 case 'E': case 'e':
1222 icon_name = "dbox-error";
1223 shell_name = "Error";
1224 break;
1226 case 'I': case 'i':
1227 icon_name = "dbox-info";
1228 shell_name = "Information";
1229 break;
1231 case 'L': case 'l':
1232 list = True;
1233 icon_name = "dbox-question";
1234 shell_name = "Prompt";
1235 break;
1237 case 'P': case 'p':
1238 text_input_slot = True;
1239 icon_name = "dbox-question";
1240 shell_name = "Prompt";
1241 break;
1243 case 'Q': case 'q':
1244 icon_name = "dbox-question";
1245 shell_name = "Question";
1246 break;
1249 total_buttons = name [1] - '0';
1251 if (name [3] == 'T' || name [3] == 't')
1253 text_input_slot = False;
1254 radio_box = True;
1256 else if (name [3])
1257 right_buttons = name [4] - '0';
1259 left_buttons = total_buttons - right_buttons;
1261 widget = make_dialog (name, parent, pop_up_p,
1262 shell_name, icon_name, text_input_slot, radio_box,
1263 list, left_buttons, right_buttons);
1265 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1266 (XtPointer) instance);
1267 return widget;
1270 /* Create a menu bar. We turn off the f10 key
1271 because we have not yet managed to make it work right in Motif. */
1273 static Widget
1274 make_menubar (instance)
1275 widget_instance* instance;
1277 Arg al[1];
1278 int ac;
1280 ac = 0;
1281 XtSetArg(al[0], XmNmenuAccelerator, 0);
1282 return XmCreateMenuBar (instance->parent, instance->info->name, al, 1);
1285 static void
1286 remove_grabs (shell, closure, call_data)
1287 Widget shell;
1288 XtPointer closure;
1289 XtPointer call_data;
1291 Widget menu = (Widget) closure;
1292 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1295 static Widget
1296 make_popup_menu (instance)
1297 widget_instance* instance;
1299 Widget parent = instance->parent;
1300 Window parent_window = parent->core.window;
1301 Widget result;
1303 /* sets the parent window to 0 to fool Motif into not generating a grab */
1304 parent->core.window = 0;
1305 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1306 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1307 (XtPointer)result);
1308 parent->core.window = parent_window;
1309 return result;
1311 static Widget
1312 make_main (instance)
1313 widget_instance* instance;
1315 Widget parent = instance->parent;
1316 Widget result;
1317 Arg al[2];
1318 int ac;
1320 ac = 0;
1321 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1322 XtSetArg (al[ac], XmNspacing, 0); ac++;
1323 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1324 return result;
1327 \f/* Table of functions to create widgets */
1329 #ifdef ENERGIZE
1331 /* interface with the XDesigner generated functions */
1332 typedef Widget (*widget_maker) (Widget);
1333 extern Widget create_project_p_sheet (Widget parent);
1334 extern Widget create_debugger_p_sheet (Widget parent);
1335 extern Widget create_breaklist_p_sheet (Widget parent);
1336 extern Widget create_le_browser_p_sheet (Widget parent);
1337 extern Widget create_class_browser_p_sheet (Widget parent);
1338 extern Widget create_call_browser_p_sheet (Widget parent);
1339 extern Widget create_build_dialog (Widget parent);
1340 extern Widget create_editmode_dialog (Widget parent);
1341 extern Widget create_search_dialog (Widget parent);
1342 extern Widget create_project_display_dialog (Widget parent);
1344 static Widget
1345 make_one (widget_instance* instance, widget_maker fn)
1347 Widget result;
1348 Arg al [64];
1349 int ac = 0;
1351 if (instance->pop_up_p)
1353 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1354 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1355 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1356 (XtPointer) instance);
1357 (*fn) (result);
1359 else
1361 result = (*fn) (instance->parent);
1362 XtRealizeWidget (result);
1364 return result;
1367 static Widget
1368 make_project_p_sheet (widget_instance* instance)
1370 return make_one (instance, create_project_p_sheet);
1373 static Widget
1374 make_debugger_p_sheet (widget_instance* instance)
1376 return make_one (instance, create_debugger_p_sheet);
1379 static Widget
1380 make_breaklist_p_sheet (widget_instance* instance)
1382 return make_one (instance, create_breaklist_p_sheet);
1385 static Widget
1386 make_le_browser_p_sheet (widget_instance* instance)
1388 return make_one (instance, create_le_browser_p_sheet);
1391 static Widget
1392 make_class_browser_p_sheet (widget_instance* instance)
1394 return make_one (instance, create_class_browser_p_sheet);
1397 static Widget
1398 make_call_browser_p_sheet (widget_instance* instance)
1400 return make_one (instance, create_call_browser_p_sheet);
1403 static Widget
1404 make_build_dialog (widget_instance* instance)
1406 return make_one (instance, create_build_dialog);
1409 static Widget
1410 make_editmode_dialog (widget_instance* instance)
1412 return make_one (instance, create_editmode_dialog);
1415 static Widget
1416 make_search_dialog (widget_instance* instance)
1418 return make_one (instance, create_search_dialog);
1421 static Widget
1422 make_project_display_dialog (widget_instance* instance)
1424 return make_one (instance, create_project_display_dialog);
1427 #endif /* ENERGIZE */
1429 widget_creation_entry
1430 xm_creation_table [] =
1432 {"menubar", make_menubar},
1433 {"popup", make_popup_menu},
1434 {"main", make_main},
1435 #ifdef ENERGIZE
1436 {"project_p_sheet", make_project_p_sheet},
1437 {"debugger_p_sheet", make_debugger_p_sheet},
1438 {"breaklist_psheet", make_breaklist_p_sheet},
1439 {"leb_psheet", make_le_browser_p_sheet},
1440 {"class_browser_psheet", make_class_browser_p_sheet},
1441 {"ctree_browser_psheet", make_call_browser_p_sheet},
1442 {"build", make_build_dialog},
1443 {"editmode", make_editmode_dialog},
1444 {"search", make_search_dialog},
1445 {"project_display", make_project_display_dialog},
1446 #endif /* ENERGIZE */
1447 {NULL, NULL}
1450 \f/* Destruction of instances */
1451 void
1452 xm_destroy_instance (instance)
1453 widget_instance* instance;
1455 Widget widget = instance->widget;
1456 /* recycle the dialog boxes */
1457 /* Disable the recycling until we can find a way to have the dialog box
1458 get reasonable layout after we modify its contents. */
1459 if (0
1460 && XtClass (widget) == xmDialogShellWidgetClass)
1462 destroyed_instance* dead_instance =
1463 make_destroyed_instance (instance->info->name,
1464 instance->info->type,
1465 instance->widget,
1466 instance->parent,
1467 instance->pop_up_p);
1468 dead_instance->next = all_destroyed_instances;
1469 all_destroyed_instances = dead_instance;
1470 XtUnmanageChild (first_child (instance->widget));
1471 XFlush (XtDisplay (instance->widget));
1472 XtAddCallback (instance->parent, XtNdestroyCallback,
1473 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1475 else
1477 /* This might not be necessary now that the nosel is attached to
1478 popdown instead of destroy, but it can't hurt. */
1479 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1480 xm_nosel_callback, (XtPointer)instance);
1481 XtDestroyWidget (instance->widget);
1485 \f/* popup utility */
1486 void
1487 xm_popup_menu (widget, event)
1488 Widget widget;
1489 XEvent *event;
1491 XButtonPressedEvent dummy;
1493 if (event == 0)
1495 dummy.type = ButtonPress;
1496 dummy.serial = 0;
1497 dummy.send_event = 0;
1498 dummy.display = XtDisplay (widget);
1499 dummy.window = XtWindow (XtParent (widget));
1500 dummy.time = 0;
1501 dummy.button = 0;
1502 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1503 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1504 &dummy.x, &dummy.y, &dummy.state);
1505 event = (XEvent *) &dummy;
1508 if (event->type == ButtonPress || event->type == ButtonRelease)
1510 /* This is so totally ridiculous: there's NO WAY to tell Motif
1511 that *any* button can select a menu item. Only one button
1512 can have that honor.
1514 char *trans = 0;
1515 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1516 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1517 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1518 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1519 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1520 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1521 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1523 XtManageChild (widget);
1526 static void
1527 set_min_dialog_size (w)
1528 Widget w;
1530 short width;
1531 short height;
1532 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1533 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1536 void
1537 xm_pop_instance (instance, up)
1538 widget_instance* instance;
1539 Boolean up;
1541 Widget widget = instance->widget;
1543 if (XtClass (widget) == xmDialogShellWidgetClass)
1545 Widget widget_to_manage = first_child (widget);
1546 if (up)
1548 XtManageChild (widget_to_manage);
1549 set_min_dialog_size (widget);
1550 XtSetKeyboardFocus (instance->parent, widget);
1552 else
1553 XtUnmanageChild (widget_to_manage);
1555 else
1557 if (up)
1558 XtManageChild (widget);
1559 else
1560 XtUnmanageChild (widget);
1565 /* motif callback */
1567 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1569 static void
1570 do_call (widget, closure, type)
1571 Widget widget;
1572 XtPointer closure;
1573 enum do_call_type type;
1575 Arg al [256];
1576 int ac;
1577 XtPointer user_data;
1578 widget_instance* instance = (widget_instance*)closure;
1579 Widget instance_widget;
1580 LWLIB_ID id;
1582 if (!instance)
1583 return;
1584 if (widget->core.being_destroyed)
1585 return;
1587 instance_widget = instance->widget;
1588 if (!instance_widget)
1589 return;
1591 id = instance->info->id;
1592 ac = 0;
1593 user_data = NULL;
1594 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1595 XtGetValues (widget, al, ac);
1596 switch (type)
1598 case pre_activate:
1599 if (instance->info->pre_activate_cb)
1600 instance->info->pre_activate_cb (widget, id, user_data);
1601 break;
1602 case selection:
1603 if (instance->info->selection_cb)
1604 instance->info->selection_cb (widget, id, user_data);
1605 break;
1606 case no_selection:
1607 if (instance->info->selection_cb)
1608 instance->info->selection_cb (widget, id, (XtPointer) -1);
1609 break;
1610 case post_activate:
1611 if (instance->info->post_activate_cb)
1612 instance->info->post_activate_cb (widget, id, user_data);
1613 break;
1614 default:
1615 abort ();
1619 /* Like lw_internal_update_other_instances except that it does not do
1620 anything if its shell parent is not managed. This is to protect
1621 lw_internal_update_other_instances to dereference freed memory
1622 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1623 list */
1624 static void
1625 xm_internal_update_other_instances (widget, closure, call_data)
1626 Widget widget;
1627 XtPointer closure;
1628 XtPointer call_data;
1630 Widget parent;
1631 for (parent = widget; parent; parent = XtParent (parent))
1632 if (XtIsShell (parent))
1633 break;
1634 else if (!XtIsManaged (parent))
1635 return;
1636 lw_internal_update_other_instances (widget, closure, call_data);
1639 static void
1640 xm_generic_callback (widget, closure, call_data)
1641 Widget widget;
1642 XtPointer closure;
1643 XtPointer call_data;
1645 lw_internal_update_other_instances (widget, closure, call_data);
1646 do_call (widget, closure, selection);
1649 static void
1650 xm_nosel_callback (widget, closure, call_data)
1651 Widget widget;
1652 XtPointer closure;
1653 XtPointer call_data;
1655 /* This callback is only called when a dialog box is dismissed with the wm's
1656 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1657 in that case, not just unmapped, so that it releases its keyboard grabs.
1658 But there are problems with running our callbacks while the widget is in
1659 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1660 instead of XmDESTROY and then destroy it ourself after having run the
1661 callback.
1663 do_call (widget, closure, no_selection);
1664 XtDestroyWidget (widget);
1667 static void
1668 xm_pull_down_callback (widget, closure, call_data)
1669 Widget widget;
1670 XtPointer closure;
1671 XtPointer call_data;
1673 do_call (widget, closure, pre_activate);
1676 static void
1677 xm_pop_down_callback (widget, closure, call_data)
1678 Widget widget;
1679 XtPointer closure;
1680 XtPointer call_data;
1682 widget_instance *instance = (widget_instance *) closure;
1684 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1685 || (XtParent (widget) == instance->parent))
1686 do_call (widget, closure, post_activate);
1690 /* set the keyboard focus */
1691 void
1692 xm_set_keyboard_focus (parent, w)
1693 Widget parent;
1694 Widget w;
1696 XmProcessTraversal (w, 0);
1697 XtSetKeyboardFocus (parent, w);
1700 /* Motif hack to set the main window areas. */
1701 void
1702 xm_set_main_areas (parent, menubar, work_area)
1703 Widget parent;
1704 Widget menubar;
1705 Widget work_area;
1707 XmMainWindowSetAreas (parent,
1708 menubar, /* menubar (maybe 0) */
1709 0, /* command area (psheets) */
1710 0, /* horizontal scroll */
1711 0, /* vertical scroll */
1712 work_area); /* work area */
1715 /* Motif hack to control resizing on the menubar. */
1716 void
1717 xm_manage_resizing (w, flag)
1718 Widget w;
1719 Boolean flag;
1721 if (flag)
1723 /* Enable the edit widget for resizing. */
1724 Arg al[1];
1726 XtSetArg (al[0], XtNallowShellResize, 0);
1727 XtSetValues (w, al, 1);
1729 else
1731 /* Disable the edit widget from resizing. */
1732 Arg al[1];
1734 XtSetArg (al[0], XtNallowShellResize, 0);
1735 XtSetValues (w, al, 1);