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