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