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