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