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