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