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