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