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