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