comparison lwlib/lwlib-Xm.c @ 428:3ecd8885ac67 r21-2-22

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