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