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