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