Add arch taglines
[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
1038/* dialogs */
1039static Widget
41bf6a06
PR
1040make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
1041 radio_box, list, left_buttons, right_buttons)
1042 char* name;
1043 Widget parent;
1044 Boolean pop_up_p;
1045 char* shell_title;
1046 char* icon_name;
1047 Boolean text_input_slot;
1048 Boolean radio_box;
1049 Boolean list;
1050 int left_buttons;
1051 int right_buttons;
07bf635f
RS
1052{
1053 Widget result;
1054 Widget form;
1055 Widget row;
1056 Widget icon;
1057 Widget icon_separator;
1058 Widget message;
1059 Widget value = 0;
1060 Widget separator;
1061 Widget button = 0;
1062 Widget children [16]; /* for the final XtManageChildren */
1063 int n_children;
1064 Arg al[64]; /* Arg List */
1065 int ac; /* Arg Count */
1066 int i;
177c0ea7 1067
07bf635f
RS
1068 if (pop_up_p)
1069 {
1070 ac = 0;
1071 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1072 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1073 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1074 result = XmCreateDialogShell (parent, "dialog", al, ac);
1075 ac = 0;
1076 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1077/* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1078 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1079 form = XmCreateForm (result, shell_title, al, ac);
1080 }
1081 else
1082 {
1083 ac = 0;
1084 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1085 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1086 form = XmCreateForm (parent, shell_title, al, ac);
1087 result = form;
1088 }
1089
688f8f7f 1090 n_children = left_buttons + right_buttons + 1;
07bf635f 1091 ac = 0;
177c0ea7 1092 XtSetArg(al[ac], XmNpacking, n_children == 3?
688f8f7f 1093 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
177c0ea7 1094 XtSetArg(al[ac], XmNorientation, n_children == 3?
688f8f7f 1095 XmVERTICAL: XmHORIZONTAL); ac++;
07bf635f
RS
1096 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1097 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1098 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1099 XtSetArg(al[ac], XmNspacing, 13); ac++;
1100 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1101 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1102 XtSetArg(al[ac], XmNisAligned, True); ac++;
1103 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1104 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1105 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1106 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1107 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1108 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1109 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1110 row = XmCreateRowColumn (form, "row", al, ac);
177c0ea7 1111
07bf635f
RS
1112 n_children = 0;
1113 for (i = 0; i < left_buttons; i++)
1114 {
1115 char button_name [16];
1116 sprintf (button_name, "button%d", i + 1);
1117 ac = 0;
1118 if (i == 0)
1119 {
1120 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1121 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1122 }
688f8f7f 1123 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
07bf635f
RS
1124 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1125 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1126
1127 if (i == 0)
1128 {
1129 button = children [n_children];
1130 ac = 0;
1131 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1132 XtSetValues (row, al, ac);
1133 }
1134
1135 n_children++;
1136 }
1137
908ff139 1138 /* invisible separator button */
07bf635f
RS
1139 ac = 0;
1140 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1141 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
1142 n_children++;
177c0ea7 1143
07bf635f
RS
1144 for (i = 0; i < right_buttons; i++)
1145 {
1146 char button_name [16];
1147 sprintf (button_name, "button%d", left_buttons + i + 1);
1148 ac = 0;
688f8f7f 1149 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
07bf635f
RS
1150 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1151 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1152 if (! button) button = children [n_children];
1153 n_children++;
1154 }
177c0ea7 1155
07bf635f 1156 XtManageChildren (children, n_children);
177c0ea7 1157
07bf635f
RS
1158 ac = 0;
1159 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1160 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1161 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1162 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1163 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1164 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1165 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1166 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1167 separator = XmCreateSeparator (form, "", al, ac);
1168
1169 ac = 0;
1170 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1171 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1172 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1173 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1174 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1175 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1176 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1177 icon = XmCreateLabel (form, icon_name, al, ac);
1178
1179 ac = 0;
1180 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1181 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1182 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1183 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1184 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1185 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1186 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1187 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1188 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1189 icon_separator = XmCreateLabel (form, "", al, ac);
1190
1191 if (text_input_slot)
1192 {
1193 ac = 0;
1194 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1195 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1196 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1197 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1198 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1199 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1200 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1201 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1202 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1203 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1204 value = XmCreateTextField (form, "value", al, ac);
1205 }
1206 else if (radio_box)
1207 {
1208 Widget radio_butt;
1209 ac = 0;
1210 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1211 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1212 XtSetArg(al[ac], XmNspacing, 13); ac++;
1213 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1214 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1215 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1216 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1217 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1218 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1219 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1220 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1221 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1222 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1223 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1224 ac = 0;
1225 i = 0;
1226 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1227 children [i++] = radio_butt;
1228 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1229 children [i++] = radio_butt;
1230 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1231 children [i++] = radio_butt;
1232 XtManageChildren (children, i);
1233 }
1234 else if (list)
1235 {
1236 ac = 0;
1237 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1238 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1239 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1240 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1241 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1242 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1243 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1244 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1245 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1246 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1247 value = XmCreateScrolledList (form, "list", al, ac);
1248
1249 /* this is the easiest way I found to have the dble click in the
1250 list activate the default button */
1251 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1252 }
177c0ea7 1253
07bf635f
RS
1254 ac = 0;
1255 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1256 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1257 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1258 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1259 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1260 XtSetArg(al[ac], XmNbottomWidget,
1261 text_input_slot || radio_box || list ? value : separator); ac++;
1262 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1263 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1264 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1265 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1266 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1267 message = XmCreateLabel (form, "message", al, ac);
177c0ea7 1268
07bf635f
RS
1269 if (list)
1270 XtManageChild (value);
1271
1272 i = 0;
1273 children [i] = row; i++;
1274 children [i] = separator; i++;
1275 if (text_input_slot || radio_box)
1276 {
1277 children [i] = value; i++;
1278 }
1279 children [i] = message; i++;
1280 children [i] = icon; i++;
1281 children [i] = icon_separator; i++;
1282 XtManageChildren (children, i);
177c0ea7 1283
07bf635f
RS
1284 if (text_input_slot || list)
1285 {
1286 XtInstallAccelerators (value, button);
1287 XtSetKeyboardFocus (result, value);
1288 }
1289 else
1290 {
1291 XtInstallAccelerators (form, button);
1292 XtSetKeyboardFocus (result, button);
1293 }
177c0ea7 1294
07bf635f
RS
1295 return result;
1296}
1297
1298static destroyed_instance*
41bf6a06
PR
1299find_matching_instance (instance)
1300 widget_instance* instance;
07bf635f
RS
1301{
1302 destroyed_instance* cur;
1303 destroyed_instance* prev;
1304 char* type = instance->info->type;
1305 char* name = instance->info->name;
1306
1307 for (prev = NULL, cur = all_destroyed_instances;
1308 cur;
1309 prev = cur, cur = cur->next)
1310 {
1311 if (!strcmp (cur->name, name)
1312 && !strcmp (cur->type, type)
1313 && cur->parent == instance->parent
1314 && cur->pop_up_p == instance->pop_up_p)
1315 {
1316 if (prev)
1317 prev->next = cur->next;
1318 else
1319 all_destroyed_instances = cur->next;
1320 return cur;
1321 }
1322 /* do some cleanup */
1323 else if (!cur->widget)
1324 {
1325 if (prev)
1326 prev->next = cur->next;
1327 else
1328 all_destroyed_instances = cur->next;
1329 free_destroyed_instance (cur);
1330 cur = prev ? prev : all_destroyed_instances;
1331 }
1332 }
1333 return NULL;
1334}
1335
1336static void
41bf6a06
PR
1337mark_dead_instance_destroyed (widget, closure, call_data)
1338 Widget widget;
1339 XtPointer closure;
1340 XtPointer call_data;
07bf635f
RS
1341{
1342 destroyed_instance* instance = (destroyed_instance*)closure;
1343 instance->widget = NULL;
1344}
1345
1346static void
41bf6a06
PR
1347recenter_widget (widget)
1348 Widget widget;
07bf635f
RS
1349{
1350 Widget parent = XtParent (widget);
1351 Screen* screen = XtScreen (widget);
1352 Dimension screen_width = WidthOfScreen (screen);
1353 Dimension screen_height = HeightOfScreen (screen);
1354 Dimension parent_width = 0;
1355 Dimension parent_height = 0;
1356 Dimension child_width = 0;
1357 Dimension child_height = 0;
1358 Position x;
1359 Position y;
1360
8dd095ee 1361 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL);
07bf635f 1362 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
8dd095ee 1363 NULL);
07bf635f
RS
1364
1365 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1366 y = (((Position)parent_height) - ((Position)child_height)) / 2;
177c0ea7 1367
07bf635f
RS
1368 XtTranslateCoords (parent, x, y, &x, &y);
1369
1370 if (x + child_width > screen_width)
1371 x = screen_width - child_width;
1372 if (x < 0)
1373 x = 0;
1374
1375 if (y + child_height > screen_height)
1376 y = screen_height - child_height;
1377 if (y < 0)
1378 y = 0;
1379
8dd095ee 1380 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL);
07bf635f
RS
1381}
1382
1383static Widget
41bf6a06
PR
1384recycle_instance (instance)
1385 destroyed_instance* instance;
07bf635f
RS
1386{
1387 Widget widget = instance->widget;
1388
1389 /* widget is NULL if the parent was destroyed. */
1390 if (widget)
1391 {
1392 Widget focus;
1393 Widget separator;
1394
1395 /* Remove the destroy callback as the instance is not in the list
1396 anymore */
1397 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1398 mark_dead_instance_destroyed,
1399 (XtPointer)instance);
1400
1401 /* Give the focus to the initial item */
1402 focus = XtNameToWidget (widget, "*value");
1403 if (!focus)
1404 focus = XtNameToWidget (widget, "*button1");
1405 if (focus)
1406 XtSetKeyboardFocus (widget, focus);
177c0ea7 1407
07bf635f
RS
1408 /* shrink the separator label back to their original size */
1409 separator = XtNameToWidget (widget, "*separator_button");
1410 if (separator)
8dd095ee 1411 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL);
07bf635f
RS
1412
1413 /* Center the dialog in its parent */
1414 recenter_widget (widget);
1415 }
1416 free_destroyed_instance (instance);
1417 return widget;
1418}
1419
1420Widget
41bf6a06
PR
1421xm_create_dialog (instance)
1422 widget_instance* instance;
07bf635f
RS
1423{
1424 char* name = instance->info->type;
1425 Widget parent = instance->parent;
1426 Widget widget;
1427 Boolean pop_up_p = instance->pop_up_p;
1428 char* shell_name = 0;
2f87cc74 1429 char* icon_name = 0;
07bf635f
RS
1430 Boolean text_input_slot = False;
1431 Boolean radio_box = False;
1432 Boolean list = False;
1433 int total_buttons;
1434 int left_buttons = 0;
1435 int right_buttons = 1;
1436 destroyed_instance* dead_one;
1437
1438 /* try to find a widget to recycle */
1439 dead_one = find_matching_instance (instance);
1440 if (dead_one)
1441 {
1442 Widget recycled_widget = recycle_instance (dead_one);
1443 if (recycled_widget)
1444 return recycled_widget;
1445 }
1446
1447 switch (name [0]){
1448 case 'E': case 'e':
1449 icon_name = "dbox-error";
1450 shell_name = "Error";
1451 break;
1452
1453 case 'I': case 'i':
1454 icon_name = "dbox-info";
1455 shell_name = "Information";
1456 break;
1457
1458 case 'L': case 'l':
1459 list = True;
1460 icon_name = "dbox-question";
1461 shell_name = "Prompt";
1462 break;
1463
1464 case 'P': case 'p':
1465 text_input_slot = True;
1466 icon_name = "dbox-question";
1467 shell_name = "Prompt";
1468 break;
1469
1470 case 'Q': case 'q':
1471 icon_name = "dbox-question";
1472 shell_name = "Question";
1473 break;
1474 }
177c0ea7 1475
07bf635f
RS
1476 total_buttons = name [1] - '0';
1477
1478 if (name [3] == 'T' || name [3] == 't')
1479 {
1480 text_input_slot = False;
1481 radio_box = True;
1482 }
1483 else if (name [3])
1484 right_buttons = name [4] - '0';
177c0ea7 1485
07bf635f 1486 left_buttons = total_buttons - right_buttons;
177c0ea7 1487
07bf635f
RS
1488 widget = make_dialog (name, parent, pop_up_p,
1489 shell_name, icon_name, text_input_slot, radio_box,
1490 list, left_buttons, right_buttons);
1491
1492 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1493 (XtPointer) instance);
1494 return widget;
1495}
1496
42de618f
RS
1497/* Create a menu bar. We turn off the f10 key
1498 because we have not yet managed to make it work right in Motif. */
1499
07bf635f 1500static Widget
41bf6a06
PR
1501make_menubar (instance)
1502 widget_instance* instance;
07bf635f 1503{
1f0cf6ee 1504 Arg al[3];
42de618f
RS
1505 int ac;
1506
1507 ac = 0;
1f0cf6ee 1508 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac;
1f0cf6ee 1509 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
07bf635f
RS
1510}
1511
1512static void
41bf6a06
PR
1513remove_grabs (shell, closure, call_data)
1514 Widget shell;
1515 XtPointer closure;
1516 XtPointer call_data;
07bf635f 1517{
0cb00a44
RS
1518 Widget menu = (Widget) closure;
1519 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu)));
07bf635f
RS
1520}
1521
1522static Widget
41bf6a06
PR
1523make_popup_menu (instance)
1524 widget_instance* instance;
07bf635f
RS
1525{
1526 Widget parent = instance->parent;
1527 Window parent_window = parent->core.window;
1528 Widget result;
1529
1530 /* sets the parent window to 0 to fool Motif into not generating a grab */
1531 parent->core.window = 0;
1532 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1533 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1534 (XtPointer)result);
1535 parent->core.window = parent_window;
1536 return result;
1537}
968aa0ad 1538
dfdcaf49 1539static Widget
41bf6a06
PR
1540make_main (instance)
1541 widget_instance* instance;
dfdcaf49
PR
1542{
1543 Widget parent = instance->parent;
1544 Widget result;
1545 Arg al[2];
1546 int ac;
1547
1548 ac = 0;
1549 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1550 XtSetArg (al[ac], XmNspacing, 0); ac++;
1551 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1552 return result;
1553}
07bf635f
RS
1554
1555\f/* Table of functions to create widgets */
1556
1557#ifdef ENERGIZE
1558
1559/* interface with the XDesigner generated functions */
1560typedef Widget (*widget_maker) (Widget);
1561extern Widget create_project_p_sheet (Widget parent);
1562extern Widget create_debugger_p_sheet (Widget parent);
1563extern Widget create_breaklist_p_sheet (Widget parent);
1564extern Widget create_le_browser_p_sheet (Widget parent);
1565extern Widget create_class_browser_p_sheet (Widget parent);
1566extern Widget create_call_browser_p_sheet (Widget parent);
1567extern Widget create_build_dialog (Widget parent);
1568extern Widget create_editmode_dialog (Widget parent);
1569extern Widget create_search_dialog (Widget parent);
1570extern Widget create_project_display_dialog (Widget parent);
1571
1572static Widget
1573make_one (widget_instance* instance, widget_maker fn)
1574{
1575 Widget result;
1576 Arg al [64];
1577 int ac = 0;
1578
1579 if (instance->pop_up_p)
1580 {
1581 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1582 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1583 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1584 (XtPointer) instance);
1585 (*fn) (result);
1586 }
1587 else
1588 {
1589 result = (*fn) (instance->parent);
1590 XtRealizeWidget (result);
1591 }
1592 return result;
1593}
1594
1595static Widget
1596make_project_p_sheet (widget_instance* instance)
1597{
1598 return make_one (instance, create_project_p_sheet);
1599}
1600
1601static Widget
1602make_debugger_p_sheet (widget_instance* instance)
1603{
1604 return make_one (instance, create_debugger_p_sheet);
1605}
1606
1607static Widget
1608make_breaklist_p_sheet (widget_instance* instance)
1609{
1610 return make_one (instance, create_breaklist_p_sheet);
1611}
1612
1613static Widget
1614make_le_browser_p_sheet (widget_instance* instance)
1615{
1616 return make_one (instance, create_le_browser_p_sheet);
1617}
1618
1619static Widget
1620make_class_browser_p_sheet (widget_instance* instance)
1621{
1622 return make_one (instance, create_class_browser_p_sheet);
1623}
1624
1625static Widget
1626make_call_browser_p_sheet (widget_instance* instance)
1627{
1628 return make_one (instance, create_call_browser_p_sheet);
1629}
1630
1631static Widget
1632make_build_dialog (widget_instance* instance)
1633{
1634 return make_one (instance, create_build_dialog);
1635}
1636
1637static Widget
1638make_editmode_dialog (widget_instance* instance)
1639{
1640 return make_one (instance, create_editmode_dialog);
1641}
1642
1643static Widget
1644make_search_dialog (widget_instance* instance)
1645{
1646 return make_one (instance, create_search_dialog);
1647}
1648
1649static Widget
1650make_project_display_dialog (widget_instance* instance)
1651{
1652 return make_one (instance, create_project_display_dialog);
1653}
1654
1655#endif /* ENERGIZE */
1656
1657widget_creation_entry
177c0ea7 1658xm_creation_table [] =
07bf635f
RS
1659{
1660 {"menubar", make_menubar},
1661 {"popup", make_popup_menu},
dfdcaf49 1662 {"main", make_main},
07bf635f
RS
1663#ifdef ENERGIZE
1664 {"project_p_sheet", make_project_p_sheet},
1665 {"debugger_p_sheet", make_debugger_p_sheet},
1666 {"breaklist_psheet", make_breaklist_p_sheet},
1667 {"leb_psheet", make_le_browser_p_sheet},
1668 {"class_browser_psheet", make_class_browser_p_sheet},
1669 {"ctree_browser_psheet", make_call_browser_p_sheet},
1670 {"build", make_build_dialog},
1671 {"editmode", make_editmode_dialog},
1672 {"search", make_search_dialog},
1673 {"project_display", make_project_display_dialog},
1674#endif /* ENERGIZE */
1675 {NULL, NULL}
1676};
1677
1678\f/* Destruction of instances */
1679void
41bf6a06
PR
1680xm_destroy_instance (instance)
1681 widget_instance* instance;
07bf635f
RS
1682{
1683 Widget widget = instance->widget;
1684 /* recycle the dialog boxes */
1685 /* Disable the recycling until we can find a way to have the dialog box
1686 get reasonable layout after we modify its contents. */
1687 if (0
1688 && XtClass (widget) == xmDialogShellWidgetClass)
1689 {
1690 destroyed_instance* dead_instance =
1691 make_destroyed_instance (instance->info->name,
1692 instance->info->type,
1693 instance->widget,
1694 instance->parent,
1695 instance->pop_up_p);
1696 dead_instance->next = all_destroyed_instances;
1697 all_destroyed_instances = dead_instance;
1698 XtUnmanageChild (first_child (instance->widget));
1699 XFlush (XtDisplay (instance->widget));
1700 XtAddCallback (instance->parent, XtNdestroyCallback,
1701 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1702 }
1703 else
1704 {
1705 /* This might not be necessary now that the nosel is attached to
1706 popdown instead of destroy, but it can't hurt. */
1707 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1708 xm_nosel_callback, (XtPointer)instance);
1709 XtDestroyWidget (instance->widget);
1710 }
1711}
1712
1713\f/* popup utility */
1714void
86c42dbd 1715xm_popup_menu (widget, event)
41bf6a06 1716 Widget widget;
86c42dbd 1717 XEvent *event;
07bf635f
RS
1718{
1719 XButtonPressedEvent dummy;
86c42dbd
RS
1720
1721 if (event == 0)
1722 {
1723 dummy.type = ButtonPress;
1724 dummy.serial = 0;
1725 dummy.send_event = 0;
1726 dummy.display = XtDisplay (widget);
1727 dummy.window = XtWindow (XtParent (widget));
1728 dummy.time = 0;
1729 dummy.button = 0;
1730 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1731 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1732 &dummy.x, &dummy.y, &dummy.state);
1733 event = (XEvent *) &dummy;
1734 }
07bf635f
RS
1735
1736 if (event->type == ButtonPress || event->type == ButtonRelease)
1737 {
3d57dbba
GM
1738 /* Setting the menuPost resource only required by Motif 1.1 and
1739 LessTif 0.84 and earlier. With later versions of LessTif,
1740 setting menuPost is unnecessary and may cause problems, so
1741 don't do it. */
1742#if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84)
1743 {
1744 /* This is so totally ridiculous: there's NO WAY to tell Motif
1745 that *any* button can select a menu item. Only one button
1746 can have that honor. */
177c0ea7 1747
3d57dbba
GM
1748 char *trans = 0;
1749 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1750 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1751 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1752 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1753 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1754 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL);
1755 }
1756#endif
177c0ea7 1757
07bf635f
RS
1758 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1759 }
177c0ea7 1760
07bf635f
RS
1761 XtManageChild (widget);
1762}
1763
1764static void
41bf6a06
PR
1765set_min_dialog_size (w)
1766 Widget w;
07bf635f
RS
1767{
1768 short width;
1769 short height;
8dd095ee
GM
1770 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
1771 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL);
07bf635f
RS
1772}
1773
1774void
41bf6a06
PR
1775xm_pop_instance (instance, up)
1776 widget_instance* instance;
1777 Boolean up;
07bf635f
RS
1778{
1779 Widget widget = instance->widget;
1780
1781 if (XtClass (widget) == xmDialogShellWidgetClass)
1782 {
1783 Widget widget_to_manage = first_child (widget);
1784 if (up)
1785 {
1786 XtManageChild (widget_to_manage);
1787 set_min_dialog_size (widget);
1788 XtSetKeyboardFocus (instance->parent, widget);
1789 }
1790 else
1791 XtUnmanageChild (widget_to_manage);
1792 }
1793 else
1794 {
1795 if (up)
1796 XtManageChild (widget);
1797 else
177c0ea7 1798 XtUnmanageChild (widget);
07bf635f
RS
1799 }
1800}
1801
1802\f
177c0ea7 1803/* motif callback */
07bf635f 1804
07bf635f 1805static void
41bf6a06
PR
1806do_call (widget, closure, type)
1807 Widget widget;
1808 XtPointer closure;
1809 enum do_call_type type;
07bf635f
RS
1810{
1811 Arg al [256];
1812 int ac;
1813 XtPointer user_data;
1814 widget_instance* instance = (widget_instance*)closure;
1815 Widget instance_widget;
1816 LWLIB_ID id;
1817
1818 if (!instance)
1819 return;
1820 if (widget->core.being_destroyed)
1821 return;
1822
1823 instance_widget = instance->widget;
1824 if (!instance_widget)
1825 return;
1826
1827 id = instance->info->id;
1828 ac = 0;
1829 user_data = NULL;
1830 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1831 XtGetValues (widget, al, ac);
177c0ea7 1832
07bf635f
RS
1833 switch (type)
1834 {
1835 case pre_activate:
1836 if (instance->info->pre_activate_cb)
1837 instance->info->pre_activate_cb (widget, id, user_data);
1838 break;
177c0ea7 1839
07bf635f
RS
1840 case selection:
1841 if (instance->info->selection_cb)
1842 instance->info->selection_cb (widget, id, user_data);
1843 break;
177c0ea7 1844
07bf635f
RS
1845 case no_selection:
1846 if (instance->info->selection_cb)
1847 instance->info->selection_cb (widget, id, (XtPointer) -1);
1848 break;
177c0ea7 1849
07bf635f
RS
1850 case post_activate:
1851 if (instance->info->post_activate_cb)
1852 instance->info->post_activate_cb (widget, id, user_data);
1853 break;
177c0ea7 1854
07bf635f
RS
1855 default:
1856 abort ();
1857 }
1858}
1859
1860/* Like lw_internal_update_other_instances except that it does not do
177c0ea7 1861 anything if its shell parent is not managed. This is to protect
07bf635f
RS
1862 lw_internal_update_other_instances to dereference freed memory
1863 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1864 list */
1865static void
41bf6a06
PR
1866xm_internal_update_other_instances (widget, closure, call_data)
1867 Widget widget;
1868 XtPointer closure;
1869 XtPointer call_data;
07bf635f
RS
1870{
1871 Widget parent;
1872 for (parent = widget; parent; parent = XtParent (parent))
1873 if (XtIsShell (parent))
1874 break;
1875 else if (!XtIsManaged (parent))
1876 return;
1877 lw_internal_update_other_instances (widget, closure, call_data);
1878}
1879
1880static void
41bf6a06
PR
1881xm_generic_callback (widget, closure, call_data)
1882 Widget widget;
1883 XtPointer closure;
1884 XtPointer call_data;
07bf635f
RS
1885{
1886 lw_internal_update_other_instances (widget, closure, call_data);
1887 do_call (widget, closure, selection);
1888}
1889
1890static void
41bf6a06
PR
1891xm_nosel_callback (widget, closure, call_data)
1892 Widget widget;
1893 XtPointer closure;
1894 XtPointer call_data;
07bf635f 1895{
f25d58a4
GM
1896 /* This callback is only called when a dialog box is dismissed with
1897 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog
1898 box to be destroyed in that case, not just unmapped, so that it
1899 releases its keyboard grabs. But there are problems with running
1900 our callbacks while the widget is in the process of being
1901 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of
1902 XmDESTROY and then destroy it ourself after having run the
1903 callback. */
07bf635f
RS
1904 do_call (widget, closure, no_selection);
1905 XtDestroyWidget (widget);
1906}
1907
1908static void
41bf6a06
PR
1909xm_pull_down_callback (widget, closure, call_data)
1910 Widget widget;
1911 XtPointer closure;
1912 XtPointer call_data;
07bf635f 1913{
640438b0
GM
1914 Widget parent = XtParent (widget);
1915
1916 if (XmIsRowColumn (parent))
1917 {
1918 unsigned char type = 0xff;
1919 XtVaGetValues (parent, XmNrowColumnType, &type, NULL);
1920 if (type == XmMENU_BAR)
1921 do_call (widget, closure, pre_activate);
1922 }
07bf635f
RS
1923}
1924
640438b0
GM
1925
1926/* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell,
177c0ea7 1927 CLOSURE is a pointer to the widget_instance of the shell,
640438b0 1928
f25d58a4
GM
1929 Note that this callback is called for each cascade button in a
1930 menu, whether or not its submenu is visible. */
640438b0 1931
07bf635f 1932static void
41bf6a06
PR
1933xm_pop_down_callback (widget, closure, call_data)
1934 Widget widget;
1935 XtPointer closure;
1936 XtPointer call_data;
07bf635f 1937{
ffa47e54
PR
1938 widget_instance *instance = (widget_instance *) closure;
1939
f25d58a4
GM
1940 if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
1941 || XtParent (widget) == instance->parent)
640438b0 1942 do_call (widget, closure, post_activate);
07bf635f
RS
1943}
1944
1945\f
1946/* set the keyboard focus */
1947void
41bf6a06
PR
1948xm_set_keyboard_focus (parent, w)
1949 Widget parent;
1950 Widget w;
07bf635f
RS
1951{
1952 XmProcessTraversal (w, 0);
1953 XtSetKeyboardFocus (parent, w);
1954}
c884904e
PR
1955
1956/* Motif hack to set the main window areas. */
1957void
1958xm_set_main_areas (parent, menubar, work_area)
1959 Widget parent;
1960 Widget menubar;
1961 Widget work_area;
1962{
1963 XmMainWindowSetAreas (parent,
1964 menubar, /* menubar (maybe 0) */
1965 0, /* command area (psheets) */
1966 0, /* horizontal scroll */
1967 0, /* vertical scroll */
1968 work_area); /* work area */
1969}
1970
1971/* Motif hack to control resizing on the menubar. */
1972void
1973xm_manage_resizing (w, flag)
1974 Widget w;
1975 Boolean flag;
1976{
566f7ec8 1977 XtVaSetValues (w, XtNallowShellResize, flag, NULL);
c884904e 1978}
ab5796a9
MB
1979
1980/* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965
1981 (do not change this comment) */