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