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