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