(set-visited-file-name): New optional arg NO-QUERY.
[emacs.git] / lwlib / lwlib-Xm.c
blob57e4b4a2ca5cd9d32c059cc4965f33687f34f543
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; i < num_children;
557 i++, cur = cur->next)
559 if (cur->this_one_change == STRUCTURAL_CHANGE)
560 break;
563 num_children_to_keep = i;
566 else
567 num_children_to_keep = num_children;
569 /* Update all the buttons of the RowColumn, in order,
570 except for those we are going to replace entirely. */
571 if (children)
573 for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
575 if (!cur)
576 abort ();
577 if (children [i]->core.being_destroyed
578 || strcmp (XtName (children [i]), cur->name))
579 continue;
580 update_one_menu_entry (instance, children [i], cur, deep_p);
581 cur = cur->next;
585 /* Now replace from scratch all the buttons after the last
586 place that the top-level structure changed. */
587 if (val->contents->change == STRUCTURAL_CHANGE)
589 destroy_all_children (widget, num_children_to_keep);
590 make_menu_in_widget (instance, widget, val->contents,
591 num_children_to_keep);
594 XtFree ((char *) children);
598 /* update text widgets */
600 static void
601 xm_update_text (instance, widget, val)
602 widget_instance* instance;
603 Widget widget;
604 widget_value* val;
606 XmTextSetString (widget, val->value ? val->value : "");
607 XtRemoveAllCallbacks (widget, XmNactivateCallback);
608 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
609 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
610 XtAddCallback (widget, XmNvalueChangedCallback,
611 xm_internal_update_other_instances, instance);
614 static void
615 xm_update_text_field (instance, widget, val)
616 widget_instance* instance;
617 Widget widget;
618 widget_value* val;
620 XmTextFieldSetString (widget, val->value ? val->value : "");
621 XtRemoveAllCallbacks (widget, XmNactivateCallback);
622 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
623 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
624 XtAddCallback (widget, XmNvalueChangedCallback,
625 xm_internal_update_other_instances, instance);
629 /* update a motif widget */
631 void
632 xm_update_one_widget (instance, widget, val, deep_p)
633 widget_instance* instance;
634 Widget widget;
635 widget_value* val;
636 Boolean deep_p;
638 WidgetClass class;
640 /* Mark as not edited */
641 val->edited = False;
643 /* Common to all widget types */
644 XtVaSetValues (widget,
645 XmNsensitive, val->enabled,
646 XmNuserData, val->call_data,
649 /* Common to all label like widgets */
650 if (XtIsSubclass (widget, xmLabelWidgetClass))
651 xm_update_label (instance, widget, val);
653 class = XtClass (widget);
654 /* Class specific things */
655 if (class == xmPushButtonWidgetClass ||
656 class == xmArrowButtonWidgetClass)
658 xm_update_pushbutton (instance, widget, val);
660 else if (class == xmCascadeButtonWidgetClass)
662 xm_update_cascadebutton (instance, widget, val);
664 else if (class == xmToggleButtonWidgetClass
665 || class == xmToggleButtonGadgetClass)
667 xm_update_toggle (instance, widget, val);
669 else if (class == xmRowColumnWidgetClass)
671 Boolean radiobox = 0;
672 int ac = 0;
673 Arg al [1];
675 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
676 XtGetValues (widget, al, ac);
678 if (radiobox)
679 xm_update_radiobox (instance, widget, val);
680 else
681 xm_update_menu (instance, widget, val, deep_p);
683 else if (class == xmTextWidgetClass)
685 xm_update_text (instance, widget, val);
687 else if (class == xmTextFieldWidgetClass)
689 xm_update_text_field (instance, widget, val);
691 else if (class == xmListWidgetClass)
693 xm_update_list (instance, widget, val);
697 \f/* getting the value back */
698 void
699 xm_update_one_value (instance, widget, val)
700 widget_instance* instance;
701 Widget widget;
702 widget_value* val;
704 WidgetClass class = XtClass (widget);
705 widget_value *old_wv;
707 /* copy the call_data slot into the "return" widget_value */
708 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
709 if (!strcmp (val->name, old_wv->name))
711 val->call_data = old_wv->call_data;
712 break;
715 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
717 XtVaGetValues (widget, XmNset, &val->selected, 0);
718 val->edited = True;
720 else if (class == xmTextWidgetClass)
722 if (val->value)
723 free (val->value);
724 val->value = XmTextGetString (widget);
725 val->edited = True;
727 else if (class == xmTextFieldWidgetClass)
729 if (val->value)
730 free (val->value);
731 val->value = XmTextFieldGetString (widget);
732 val->edited = True;
734 else if (class == xmRowColumnWidgetClass)
736 Boolean radiobox = 0;
737 int ac = 0;
738 Arg al [1];
740 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
741 XtGetValues (widget, al, ac);
743 if (radiobox)
745 CompositeWidget radio = (CompositeWidget)widget;
746 int i;
747 for (i = 0; i < radio->composite.num_children; i++)
749 int set = False;
750 Widget toggle = radio->composite.children [i];
752 XtVaGetValues (toggle, XmNset, &set, 0);
753 if (set)
755 if (val->value)
756 free (val->value);
757 val->value = safe_strdup (XtName (toggle));
760 val->edited = True;
763 else if (class == xmListWidgetClass)
765 int pos_cnt;
766 int* pos_list;
767 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
769 int i;
770 widget_value* cur;
771 for (cur = val->contents, i = 0; cur; cur = cur->next)
772 if (cur->value)
774 int j;
775 cur->selected = False;
776 i += 1;
777 for (j = 0; j < pos_cnt; j++)
778 if (pos_list [j] == i)
780 cur->selected = True;
781 val->value = safe_strdup (cur->name);
784 val->edited = 1;
785 XtFree ((char *) pos_list);
791 /* This function is for activating a button from a program. It's wrong because
792 we pass a NULL argument in the call_data which is not Motif compatible.
793 This is used from the XmNdefaultAction callback of the List widgets to
794 have a double-click put down a dialog box like the button would do.
795 I could not find a way to do that with accelerators.
797 static void
798 activate_button (widget, closure, call_data)
799 Widget widget;
800 XtPointer closure;
801 XtPointer call_data;
803 Widget button = (Widget)closure;
804 XtCallCallbacks (button, XmNactivateCallback, NULL);
807 /* creation functions */
809 /* dialogs */
810 static Widget
811 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
812 radio_box, list, left_buttons, right_buttons)
813 char* name;
814 Widget parent;
815 Boolean pop_up_p;
816 char* shell_title;
817 char* icon_name;
818 Boolean text_input_slot;
819 Boolean radio_box;
820 Boolean list;
821 int left_buttons;
822 int right_buttons;
824 Widget result;
825 Widget form;
826 Widget row;
827 Widget icon;
828 Widget icon_separator;
829 Widget message;
830 Widget value = 0;
831 Widget separator;
832 Widget button = 0;
833 Widget children [16]; /* for the final XtManageChildren */
834 int n_children;
835 Arg al[64]; /* Arg List */
836 int ac; /* Arg Count */
837 int i;
839 if (pop_up_p)
841 ac = 0;
842 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
843 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
844 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
845 result = XmCreateDialogShell (parent, "dialog", al, ac);
846 ac = 0;
847 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
848 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
849 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
850 form = XmCreateForm (result, shell_title, al, ac);
852 else
854 ac = 0;
855 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
856 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
857 form = XmCreateForm (parent, shell_title, al, ac);
858 result = form;
861 n_children = left_buttons + right_buttons + 1;
862 ac = 0;
863 XtSetArg(al[ac], XmNpacking, n_children == 3?
864 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
865 XtSetArg(al[ac], XmNorientation, n_children == 3?
866 XmVERTICAL: XmHORIZONTAL); ac++;
867 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
868 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
869 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
870 XtSetArg(al[ac], XmNspacing, 13); ac++;
871 XtSetArg(al[ac], XmNadjustLast, False); ac++;
872 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
873 XtSetArg(al[ac], XmNisAligned, True); ac++;
874 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
875 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
876 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
877 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
878 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
879 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
880 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
881 row = XmCreateRowColumn (form, "row", al, ac);
883 n_children = 0;
884 for (i = 0; i < left_buttons; i++)
886 char button_name [16];
887 sprintf (button_name, "button%d", i + 1);
888 ac = 0;
889 if (i == 0)
891 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
892 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
894 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
895 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
896 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
898 if (i == 0)
900 button = children [n_children];
901 ac = 0;
902 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
903 XtSetValues (row, al, ac);
906 n_children++;
909 /* invisible separator button */
910 ac = 0;
911 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
912 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
913 n_children++;
915 for (i = 0; i < right_buttons; i++)
917 char button_name [16];
918 sprintf (button_name, "button%d", left_buttons + i + 1);
919 ac = 0;
920 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
921 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
922 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
923 if (! button) button = children [n_children];
924 n_children++;
927 XtManageChildren (children, n_children);
929 ac = 0;
930 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
931 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
932 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
933 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
934 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
935 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
936 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
937 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
938 separator = XmCreateSeparator (form, "", al, ac);
940 ac = 0;
941 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
942 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
943 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
944 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
945 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
946 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
947 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
948 icon = XmCreateLabel (form, icon_name, al, ac);
950 ac = 0;
951 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
952 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
953 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
954 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
955 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
956 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
957 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
958 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
959 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
960 icon_separator = XmCreateLabel (form, "", al, ac);
962 if (text_input_slot)
964 ac = 0;
965 XtSetArg(al[ac], XmNcolumns, 50); ac++;
966 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
967 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
968 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
969 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
970 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
971 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
972 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
973 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
974 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
975 value = XmCreateTextField (form, "value", al, ac);
977 else if (radio_box)
979 Widget radio_butt;
980 ac = 0;
981 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
982 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
983 XtSetArg(al[ac], XmNspacing, 13); ac++;
984 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
985 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
986 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
987 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
988 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
989 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
990 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
991 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
992 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
993 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
994 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
995 ac = 0;
996 i = 0;
997 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
998 children [i++] = radio_butt;
999 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1000 children [i++] = radio_butt;
1001 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1002 children [i++] = radio_butt;
1003 XtManageChildren (children, i);
1005 else if (list)
1007 ac = 0;
1008 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1009 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1010 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1011 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1012 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1013 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1014 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1015 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1016 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1017 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1018 value = XmCreateScrolledList (form, "list", al, ac);
1020 /* this is the easiest way I found to have the dble click in the
1021 list activate the default button */
1022 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1025 ac = 0;
1026 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1027 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1028 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1029 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1030 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1031 XtSetArg(al[ac], XmNbottomWidget,
1032 text_input_slot || radio_box || list ? value : separator); ac++;
1033 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1034 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1035 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1036 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1037 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1038 message = XmCreateLabel (form, "message", al, ac);
1040 if (list)
1041 XtManageChild (value);
1043 i = 0;
1044 children [i] = row; i++;
1045 children [i] = separator; i++;
1046 if (text_input_slot || radio_box)
1048 children [i] = value; i++;
1050 children [i] = message; i++;
1051 children [i] = icon; i++;
1052 children [i] = icon_separator; i++;
1053 XtManageChildren (children, i);
1055 if (text_input_slot || list)
1057 XtInstallAccelerators (value, button);
1058 XtSetKeyboardFocus (result, value);
1060 else
1062 XtInstallAccelerators (form, button);
1063 XtSetKeyboardFocus (result, button);
1066 return result;
1069 static destroyed_instance*
1070 find_matching_instance (instance)
1071 widget_instance* instance;
1073 destroyed_instance* cur;
1074 destroyed_instance* prev;
1075 char* type = instance->info->type;
1076 char* name = instance->info->name;
1078 for (prev = NULL, cur = all_destroyed_instances;
1079 cur;
1080 prev = cur, cur = cur->next)
1082 if (!strcmp (cur->name, name)
1083 && !strcmp (cur->type, type)
1084 && cur->parent == instance->parent
1085 && cur->pop_up_p == instance->pop_up_p)
1087 if (prev)
1088 prev->next = cur->next;
1089 else
1090 all_destroyed_instances = cur->next;
1091 return cur;
1093 /* do some cleanup */
1094 else if (!cur->widget)
1096 if (prev)
1097 prev->next = cur->next;
1098 else
1099 all_destroyed_instances = cur->next;
1100 free_destroyed_instance (cur);
1101 cur = prev ? prev : all_destroyed_instances;
1104 return NULL;
1107 static void
1108 mark_dead_instance_destroyed (widget, closure, call_data)
1109 Widget widget;
1110 XtPointer closure;
1111 XtPointer call_data;
1113 destroyed_instance* instance = (destroyed_instance*)closure;
1114 instance->widget = NULL;
1117 static void
1118 recenter_widget (widget)
1119 Widget widget;
1121 Widget parent = XtParent (widget);
1122 Screen* screen = XtScreen (widget);
1123 Dimension screen_width = WidthOfScreen (screen);
1124 Dimension screen_height = HeightOfScreen (screen);
1125 Dimension parent_width = 0;
1126 Dimension parent_height = 0;
1127 Dimension child_width = 0;
1128 Dimension child_height = 0;
1129 Position x;
1130 Position y;
1132 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1133 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1136 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1137 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1139 XtTranslateCoords (parent, x, y, &x, &y);
1141 if (x + child_width > screen_width)
1142 x = screen_width - child_width;
1143 if (x < 0)
1144 x = 0;
1146 if (y + child_height > screen_height)
1147 y = screen_height - child_height;
1148 if (y < 0)
1149 y = 0;
1151 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1154 static Widget
1155 recycle_instance (instance)
1156 destroyed_instance* instance;
1158 Widget widget = instance->widget;
1160 /* widget is NULL if the parent was destroyed. */
1161 if (widget)
1163 Widget focus;
1164 Widget separator;
1166 /* Remove the destroy callback as the instance is not in the list
1167 anymore */
1168 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1169 mark_dead_instance_destroyed,
1170 (XtPointer)instance);
1172 /* Give the focus to the initial item */
1173 focus = XtNameToWidget (widget, "*value");
1174 if (!focus)
1175 focus = XtNameToWidget (widget, "*button1");
1176 if (focus)
1177 XtSetKeyboardFocus (widget, focus);
1179 /* shrink the separator label back to their original size */
1180 separator = XtNameToWidget (widget, "*separator_button");
1181 if (separator)
1182 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1184 /* Center the dialog in its parent */
1185 recenter_widget (widget);
1187 free_destroyed_instance (instance);
1188 return widget;
1191 Widget
1192 xm_create_dialog (instance)
1193 widget_instance* instance;
1195 char* name = instance->info->type;
1196 Widget parent = instance->parent;
1197 Widget widget;
1198 Boolean pop_up_p = instance->pop_up_p;
1199 char* shell_name = 0;
1200 char* icon_name;
1201 Boolean text_input_slot = False;
1202 Boolean radio_box = False;
1203 Boolean list = False;
1204 int total_buttons;
1205 int left_buttons = 0;
1206 int right_buttons = 1;
1207 destroyed_instance* dead_one;
1209 /* try to find a widget to recycle */
1210 dead_one = find_matching_instance (instance);
1211 if (dead_one)
1213 Widget recycled_widget = recycle_instance (dead_one);
1214 if (recycled_widget)
1215 return recycled_widget;
1218 switch (name [0]){
1219 case 'E': case 'e':
1220 icon_name = "dbox-error";
1221 shell_name = "Error";
1222 break;
1224 case 'I': case 'i':
1225 icon_name = "dbox-info";
1226 shell_name = "Information";
1227 break;
1229 case 'L': case 'l':
1230 list = True;
1231 icon_name = "dbox-question";
1232 shell_name = "Prompt";
1233 break;
1235 case 'P': case 'p':
1236 text_input_slot = True;
1237 icon_name = "dbox-question";
1238 shell_name = "Prompt";
1239 break;
1241 case 'Q': case 'q':
1242 icon_name = "dbox-question";
1243 shell_name = "Question";
1244 break;
1247 total_buttons = name [1] - '0';
1249 if (name [3] == 'T' || name [3] == 't')
1251 text_input_slot = False;
1252 radio_box = True;
1254 else if (name [3])
1255 right_buttons = name [4] - '0';
1257 left_buttons = total_buttons - right_buttons;
1259 widget = make_dialog (name, parent, pop_up_p,
1260 shell_name, icon_name, text_input_slot, radio_box,
1261 list, left_buttons, right_buttons);
1263 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1264 (XtPointer) instance);
1265 return widget;
1268 static Widget
1269 make_menubar (instance)
1270 widget_instance* instance;
1272 return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
1275 static void
1276 remove_grabs (shell, closure, call_data)
1277 Widget shell;
1278 XtPointer closure;
1279 XtPointer call_data;
1281 Widget menu = (Widget) closure;
1282 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
1285 static Widget
1286 make_popup_menu (instance)
1287 widget_instance* instance;
1289 Widget parent = instance->parent;
1290 Window parent_window = parent->core.window;
1291 Widget result;
1293 /* sets the parent window to 0 to fool Motif into not generating a grab */
1294 parent->core.window = 0;
1295 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1296 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1297 (XtPointer)result);
1298 parent->core.window = parent_window;
1299 return result;
1301 static Widget
1302 make_main (instance)
1303 widget_instance* instance;
1305 Widget parent = instance->parent;
1306 Widget result;
1307 Arg al[2];
1308 int ac;
1310 ac = 0;
1311 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1312 XtSetArg (al[ac], XmNspacing, 0); ac++;
1313 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1314 return result;
1317 \f/* Table of functions to create widgets */
1319 #ifdef ENERGIZE
1321 /* interface with the XDesigner generated functions */
1322 typedef Widget (*widget_maker) (Widget);
1323 extern Widget create_project_p_sheet (Widget parent);
1324 extern Widget create_debugger_p_sheet (Widget parent);
1325 extern Widget create_breaklist_p_sheet (Widget parent);
1326 extern Widget create_le_browser_p_sheet (Widget parent);
1327 extern Widget create_class_browser_p_sheet (Widget parent);
1328 extern Widget create_call_browser_p_sheet (Widget parent);
1329 extern Widget create_build_dialog (Widget parent);
1330 extern Widget create_editmode_dialog (Widget parent);
1331 extern Widget create_search_dialog (Widget parent);
1332 extern Widget create_project_display_dialog (Widget parent);
1334 static Widget
1335 make_one (widget_instance* instance, widget_maker fn)
1337 Widget result;
1338 Arg al [64];
1339 int ac = 0;
1341 if (instance->pop_up_p)
1343 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1344 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1345 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1346 (XtPointer) instance);
1347 (*fn) (result);
1349 else
1351 result = (*fn) (instance->parent);
1352 XtRealizeWidget (result);
1354 return result;
1357 static Widget
1358 make_project_p_sheet (widget_instance* instance)
1360 return make_one (instance, create_project_p_sheet);
1363 static Widget
1364 make_debugger_p_sheet (widget_instance* instance)
1366 return make_one (instance, create_debugger_p_sheet);
1369 static Widget
1370 make_breaklist_p_sheet (widget_instance* instance)
1372 return make_one (instance, create_breaklist_p_sheet);
1375 static Widget
1376 make_le_browser_p_sheet (widget_instance* instance)
1378 return make_one (instance, create_le_browser_p_sheet);
1381 static Widget
1382 make_class_browser_p_sheet (widget_instance* instance)
1384 return make_one (instance, create_class_browser_p_sheet);
1387 static Widget
1388 make_call_browser_p_sheet (widget_instance* instance)
1390 return make_one (instance, create_call_browser_p_sheet);
1393 static Widget
1394 make_build_dialog (widget_instance* instance)
1396 return make_one (instance, create_build_dialog);
1399 static Widget
1400 make_editmode_dialog (widget_instance* instance)
1402 return make_one (instance, create_editmode_dialog);
1405 static Widget
1406 make_search_dialog (widget_instance* instance)
1408 return make_one (instance, create_search_dialog);
1411 static Widget
1412 make_project_display_dialog (widget_instance* instance)
1414 return make_one (instance, create_project_display_dialog);
1417 #endif /* ENERGIZE */
1419 widget_creation_entry
1420 xm_creation_table [] =
1422 {"menubar", make_menubar},
1423 {"popup", make_popup_menu},
1424 {"main", make_main},
1425 #ifdef ENERGIZE
1426 {"project_p_sheet", make_project_p_sheet},
1427 {"debugger_p_sheet", make_debugger_p_sheet},
1428 {"breaklist_psheet", make_breaklist_p_sheet},
1429 {"leb_psheet", make_le_browser_p_sheet},
1430 {"class_browser_psheet", make_class_browser_p_sheet},
1431 {"ctree_browser_psheet", make_call_browser_p_sheet},
1432 {"build", make_build_dialog},
1433 {"editmode", make_editmode_dialog},
1434 {"search", make_search_dialog},
1435 {"project_display", make_project_display_dialog},
1436 #endif /* ENERGIZE */
1437 {NULL, NULL}
1440 \f/* Destruction of instances */
1441 void
1442 xm_destroy_instance (instance)
1443 widget_instance* instance;
1445 Widget widget = instance->widget;
1446 /* recycle the dialog boxes */
1447 /* Disable the recycling until we can find a way to have the dialog box
1448 get reasonable layout after we modify its contents. */
1449 if (0
1450 && XtClass (widget) == xmDialogShellWidgetClass)
1452 destroyed_instance* dead_instance =
1453 make_destroyed_instance (instance->info->name,
1454 instance->info->type,
1455 instance->widget,
1456 instance->parent,
1457 instance->pop_up_p);
1458 dead_instance->next = all_destroyed_instances;
1459 all_destroyed_instances = dead_instance;
1460 XtUnmanageChild (first_child (instance->widget));
1461 XFlush (XtDisplay (instance->widget));
1462 XtAddCallback (instance->parent, XtNdestroyCallback,
1463 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1465 else
1467 /* This might not be necessary now that the nosel is attached to
1468 popdown instead of destroy, but it can't hurt. */
1469 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1470 xm_nosel_callback, (XtPointer)instance);
1471 XtDestroyWidget (instance->widget);
1475 \f/* popup utility */
1476 void
1477 xm_popup_menu (widget, event)
1478 Widget widget;
1479 XEvent *event;
1481 XButtonPressedEvent dummy;
1483 if (event == 0)
1485 dummy.type = ButtonPress;
1486 dummy.serial = 0;
1487 dummy.send_event = 0;
1488 dummy.display = XtDisplay (widget);
1489 dummy.window = XtWindow (XtParent (widget));
1490 dummy.time = 0;
1491 dummy.button = 0;
1492 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1493 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1494 &dummy.x, &dummy.y, &dummy.state);
1495 event = (XEvent *) &dummy;
1498 if (event->type == ButtonPress || event->type == ButtonRelease)
1500 /* This is so totally ridiculous: there's NO WAY to tell Motif
1501 that *any* button can select a menu item. Only one button
1502 can have that honor.
1504 char *trans = 0;
1505 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1506 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1507 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1508 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1509 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1510 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1511 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1513 XtManageChild (widget);
1516 static void
1517 set_min_dialog_size (w)
1518 Widget w;
1520 short width;
1521 short height;
1522 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1523 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1526 void
1527 xm_pop_instance (instance, up)
1528 widget_instance* instance;
1529 Boolean up;
1531 Widget widget = instance->widget;
1533 if (XtClass (widget) == xmDialogShellWidgetClass)
1535 Widget widget_to_manage = first_child (widget);
1536 if (up)
1538 XtManageChild (widget_to_manage);
1539 set_min_dialog_size (widget);
1540 XtSetKeyboardFocus (instance->parent, widget);
1542 else
1543 XtUnmanageChild (widget_to_manage);
1545 else
1547 if (up)
1548 XtManageChild (widget);
1549 else
1550 XtUnmanageChild (widget);
1555 /* motif callback */
1557 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1559 static void
1560 do_call (widget, closure, type)
1561 Widget widget;
1562 XtPointer closure;
1563 enum do_call_type type;
1565 Arg al [256];
1566 int ac;
1567 XtPointer user_data;
1568 widget_instance* instance = (widget_instance*)closure;
1569 Widget instance_widget;
1570 LWLIB_ID id;
1572 if (!instance)
1573 return;
1574 if (widget->core.being_destroyed)
1575 return;
1577 instance_widget = instance->widget;
1578 if (!instance_widget)
1579 return;
1581 id = instance->info->id;
1582 ac = 0;
1583 user_data = NULL;
1584 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1585 XtGetValues (widget, al, ac);
1586 switch (type)
1588 case pre_activate:
1589 if (instance->info->pre_activate_cb)
1590 instance->info->pre_activate_cb (widget, id, user_data);
1591 break;
1592 case selection:
1593 if (instance->info->selection_cb)
1594 instance->info->selection_cb (widget, id, user_data);
1595 break;
1596 case no_selection:
1597 if (instance->info->selection_cb)
1598 instance->info->selection_cb (widget, id, (XtPointer) -1);
1599 break;
1600 case post_activate:
1601 if (instance->info->post_activate_cb)
1602 instance->info->post_activate_cb (widget, id, user_data);
1603 break;
1604 default:
1605 abort ();
1609 /* Like lw_internal_update_other_instances except that it does not do
1610 anything if its shell parent is not managed. This is to protect
1611 lw_internal_update_other_instances to dereference freed memory
1612 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1613 list */
1614 static void
1615 xm_internal_update_other_instances (widget, closure, call_data)
1616 Widget widget;
1617 XtPointer closure;
1618 XtPointer call_data;
1620 Widget parent;
1621 for (parent = widget; parent; parent = XtParent (parent))
1622 if (XtIsShell (parent))
1623 break;
1624 else if (!XtIsManaged (parent))
1625 return;
1626 lw_internal_update_other_instances (widget, closure, call_data);
1629 static void
1630 xm_generic_callback (widget, closure, call_data)
1631 Widget widget;
1632 XtPointer closure;
1633 XtPointer call_data;
1635 lw_internal_update_other_instances (widget, closure, call_data);
1636 do_call (widget, closure, selection);
1639 static void
1640 xm_nosel_callback (widget, closure, call_data)
1641 Widget widget;
1642 XtPointer closure;
1643 XtPointer call_data;
1645 /* This callback is only called when a dialog box is dismissed with the wm's
1646 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1647 in that case, not just unmapped, so that it releases its keyboard grabs.
1648 But there are problems with running our callbacks while the widget is in
1649 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1650 instead of XmDESTROY and then destroy it ourself after having run the
1651 callback.
1653 do_call (widget, closure, no_selection);
1654 XtDestroyWidget (widget);
1657 static void
1658 xm_pull_down_callback (widget, closure, call_data)
1659 Widget widget;
1660 XtPointer closure;
1661 XtPointer call_data;
1663 do_call (widget, closure, pre_activate);
1666 static void
1667 xm_pop_down_callback (widget, closure, call_data)
1668 Widget widget;
1669 XtPointer closure;
1670 XtPointer call_data;
1672 widget_instance *instance = (widget_instance *) closure;
1674 if ((!instance->pop_up_p && (XtParent (widget) == instance->widget))
1675 || (XtParent (widget) == instance->parent))
1676 do_call (widget, closure, post_activate);
1680 /* set the keyboard focus */
1681 void
1682 xm_set_keyboard_focus (parent, w)
1683 Widget parent;
1684 Widget w;
1686 XmProcessTraversal (w, 0);
1687 XtSetKeyboardFocus (parent, w);
1690 /* Motif hack to set the main window areas. */
1691 void
1692 xm_set_main_areas (parent, menubar, work_area)
1693 Widget parent;
1694 Widget menubar;
1695 Widget work_area;
1697 XmMainWindowSetAreas (parent,
1698 menubar, /* menubar (maybe 0) */
1699 0, /* command area (psheets) */
1700 0, /* horizontal scroll */
1701 0, /* vertical scroll */
1702 work_area); /* work area */
1705 /* Motif hack to control resizing on the menubar. */
1706 void
1707 xm_manage_resizing (w, flag)
1708 Widget w;
1709 Boolean flag;
1711 if (flag)
1713 /* Enable the edit widget for resizing. */
1714 Arg al[1];
1716 XtSetArg (al[0], XtNallowShellResize, 0);
1717 XtSetValues (w, al, 1);
1719 else
1721 /* Disable the edit widget from resizing. */
1722 Arg al[1];
1724 XtSetArg (al[0], XtNallowShellResize, 0);
1725 XtSetValues (w, al, 1);