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