comparison lwlib/lwlib-Xm.c @ 0:376386a54a3c r19-14

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