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