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