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