Merge from trunk
[bpt/emacs.git] / lwlib / lwlib-Xaw.c
1 /* The lwlib interface to Athena widgets.
2 Copyright (C) 1993 Chuck Thompson <cthomp@cs.uiuc.edu>
3 Copyright (C) 1994, 2001-2011 Free Software Foundation, Inc.
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 1, 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, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <setjmp.h>
28 #include <ctype.h>
29
30 #include "../src/lisp.h"
31
32 #include "lwlib-Xaw.h"
33
34 #include <X11/StringDefs.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/CoreP.h>
37 #include <X11/Shell.h>
38
39 #ifdef HAVE_XAW3D
40 #include <X11/Xaw3d/Scrollbar.h>
41 #include <X11/Xaw3d/Paned.h>
42 #include <X11/Xaw3d/Dialog.h>
43 #include <X11/Xaw3d/Form.h>
44 #include <X11/Xaw3d/Command.h>
45 #include <X11/Xaw3d/Label.h>
46 #else /* !HAVE_XAW3D */
47 #include <X11/Xaw/Scrollbar.h>
48 #include <X11/Xaw/Paned.h>
49 #include <X11/Xaw/Dialog.h>
50 #include <X11/Xaw/Form.h>
51 #include <X11/Xaw/Command.h>
52 #include <X11/Xaw/Label.h>
53 #endif /* HAVE_XAW3D */
54
55 #include <X11/Xatom.h>
56
57 #ifdef HAVE_XFT
58 #include <X11/Xft/Xft.h>
59
60 struct widget_xft_data
61 {
62 Widget widget;
63 XftFont *xft_font;
64 XftDraw *xft_draw;
65 XftColor xft_fg, xft_bg;
66 int p_width, p_height;
67 Pixmap p;
68 };
69
70
71 #endif
72
73 static void xaw_generic_callback (Widget widget,
74 XtPointer closure,
75 XtPointer call_data);
76
77
78 Boolean
79 lw_xaw_widget_p (Widget widget)
80 {
81 return (XtIsSubclass (widget, scrollbarWidgetClass) ||
82 XtIsSubclass (widget, dialogWidgetClass));
83 }
84
85
86 #ifdef HAVE_XFT
87 static void
88 fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font)
89 {
90 Pixel bg, fg;
91 XColor colors[2];
92
93 data->widget = widget;
94 data->xft_font = font;
95 XtVaGetValues (widget,
96 XtNbackground, &bg,
97 XtNforeground, &fg,
98 NULL);
99
100 colors[0].pixel = data->xft_fg.pixel = fg;
101 colors[1].pixel = data->xft_bg.pixel = bg;
102 XQueryColors (XtDisplay (widget),
103 DefaultColormapOfScreen (XtScreen (widget)),
104 colors, 2);
105
106 data->xft_fg.color.alpha = 0xFFFF;
107 data->xft_fg.color.red = colors[0].red;
108 data->xft_fg.color.green = colors[0].green;
109 data->xft_fg.color.blue = colors[0].blue;
110 data->xft_bg.color.alpha = 0xFFFF;
111 data->xft_bg.color.red = colors[1].red;
112 data->xft_bg.color.green = colors[1].green;
113 data->xft_bg.color.blue = colors[1].blue;
114
115 data->p = None;
116 data->xft_draw = 0;
117 data->p_width = data->p_height = 0;
118 }
119
120 static XftFont*
121 openFont (Widget widget, char *name)
122 {
123 char *fname = name;
124 int screen = XScreenNumberOfScreen (XtScreen (widget));
125 int len = strlen (fname), i = len-1;
126 XftFont *fn;
127
128 /* Try to convert Gtk-syntax (Sans 9) to Xft syntax Sans-9. */
129 while (i > 0 && isdigit (fname[i]))
130 --i;
131 if (fname[i] == ' ')
132 {
133 fname = xstrdup (name);
134 fname[i] = '-';
135 }
136
137 fn = XftFontOpenName (XtDisplay (widget), screen, fname);
138 if (fname != name) free (fname);
139
140 return fn;
141 }
142
143 static int
144 get_text_width_and_height (Widget widget, char *text,
145 XftFont *xft_font,
146 int *height)
147 {
148 int w = 0, h = 0;
149 char *bp = text;
150
151 while (bp && *bp != '\0')
152 {
153 XGlyphInfo gi;
154 char *cp = strchr (bp, '\n');
155 XftTextExtentsUtf8 (XtDisplay (widget), xft_font,
156 (FcChar8 *) bp,
157 cp ? cp - bp : strlen (bp),
158 &gi);
159 bp = cp ? cp + 1 : NULL;
160 h += xft_font->height;
161 if (w < gi.width) w = gi.width;
162 }
163
164 *height = h;
165 return w;
166 }
167
168 static void
169 draw_text (struct widget_xft_data *data, char *lbl, int inverse)
170 {
171 Screen *sc = XtScreen (data->widget);
172 int screen = XScreenNumberOfScreen (sc);
173 int y = data->xft_font->ascent;
174 int x = inverse ? 0 : 2;
175 char *bp = lbl;
176
177 data->xft_draw = XftDrawCreate (XtDisplay (data->widget),
178 data->p,
179 DefaultVisual (XtDisplay (data->widget),
180 screen),
181 DefaultColormapOfScreen (sc));
182 XftDrawRect (data->xft_draw,
183 inverse ? &data->xft_fg : &data->xft_bg,
184 0, 0, data->p_width, data->p_height);
185
186 if (!inverse) y += 2;
187 while (bp && *bp != '\0')
188 {
189 char *cp = strchr (bp, '\n');
190 XftDrawStringUtf8 (data->xft_draw,
191 inverse ? &data->xft_bg : &data->xft_fg,
192 data->xft_font, x, y,
193 (FcChar8 *) bp,
194 cp ? cp - bp : strlen (bp));
195 bp = cp ? cp + 1 : NULL;
196 /* 1.2 gives reasonable line spacing. */
197 y += data->xft_font->height * 1.2;
198 }
199
200 }
201
202
203 static void
204 set_text (struct widget_xft_data *data, Widget toplevel, char *lbl, int margin)
205 {
206 int width, height;
207
208 width = get_text_width_and_height (data->widget, lbl, data->xft_font,
209 &height);
210 data->p_width = width + margin;
211 data->p_height = height + margin;
212
213 data->p = XCreatePixmap (XtDisplay (data->widget),
214 XtWindow (toplevel),
215 data->p_width,
216 data->p_height,
217 DefaultDepthOfScreen (XtScreen (data->widget)));
218 draw_text (data, lbl, 0);
219 XtVaSetValues (data->widget, XtNbitmap, data->p, NULL);
220 }
221
222 static struct widget_xft_data *
223 find_xft_data (Widget widget)
224 {
225 widget_instance *inst = NULL;
226 Widget parent = XtParent (widget);
227 struct widget_xft_data *data = NULL;
228 int nr;
229 while (parent && !inst)
230 {
231 inst = lw_get_widget_instance (parent);
232 parent = XtParent (parent);
233 }
234 if (!inst || !inst->xft_data || !inst->xft_data[0].xft_font) return 0;
235
236 for (nr = 0; data == NULL && nr < inst->nr_xft_data; ++nr)
237 {
238 if (inst->xft_data[nr].widget == widget)
239 data = &inst->xft_data[nr];
240 }
241
242 return data;
243 }
244
245 static void
246 command_press (Widget widget,
247 XEvent* event,
248 String *params,
249 Cardinal *num_params)
250 {
251 struct widget_xft_data *data = find_xft_data (widget);
252 if (data)
253 {
254 char *lbl;
255 /* Since this isn't used for rectangle buttons, use it to for armed. */
256 XtVaSetValues (widget, XtNcornerRoundPercent, 1, NULL);
257
258 XtVaGetValues (widget, XtNlabel, &lbl, NULL);
259 draw_text (data, lbl, 1);
260 }
261 }
262
263 static void
264 command_reset (Widget widget,
265 XEvent* event,
266 String *params,
267 Cardinal *num_params)
268 {
269 struct widget_xft_data *data = find_xft_data (widget);
270 if (data)
271 {
272 Dimension cr;
273 XtVaGetValues (widget, XtNcornerRoundPercent, &cr, NULL);
274 if (cr == 1)
275 {
276 char *lbl;
277 XtVaSetValues (widget, XtNcornerRoundPercent, 0, NULL);
278 XtVaGetValues (widget, XtNlabel, &lbl, NULL);
279 draw_text (data, lbl, 0);
280 }
281 }
282 }
283
284
285 #endif
286
287 void
288 xaw_update_one_widget (widget_instance *instance,
289 Widget widget,
290 widget_value *val,
291 Boolean deep_p)
292 {
293 if (XtIsSubclass (widget, dialogWidgetClass))
294 {
295
296 #ifdef HAVE_XFT
297 if (instance->xft_data && instance->xft_data[0].xft_font)
298 {
299 set_text (&instance->xft_data[0], instance->parent,
300 val->contents->value, 10);
301 }
302 #endif
303 XtVaSetValues (widget, XtNlabel, val->contents->value, NULL);
304 }
305 else if (XtIsSubclass (widget, commandWidgetClass))
306 {
307 Dimension bw = 0;
308 Arg al[10];
309 int ac = 0;
310
311 XtVaGetValues (widget, XtNborderWidth, &bw, NULL);
312 if (bw == 0)
313 /* Don't let buttons end up with 0 borderwidth, that's ugly...
314 Yeah, all this should really be done through app-defaults files
315 or fallback resources, but that's a whole different can of worms
316 that I don't feel like opening right now. Making Athena widgets
317 not look like shit is just entirely too much work.
318 */
319 {
320 XtSetArg (al[0], XtNborderWidth, 1);
321 XtSetValues (widget, al, 1);
322 }
323
324 XtSetSensitive (widget, val->enabled);
325 XtSetArg (al[ac], XtNlabel, val->value);ac++;
326 /* Force centered button text. Se above. */
327 XtSetArg (al[ac], XtNjustify, XtJustifyCenter);ac++;
328 #ifdef HAVE_XFT
329 if (instance->xft_data && instance->xft_data[0].xft_font)
330 {
331 int th;
332 int nr;
333 for (nr = 0; nr < instance->nr_xft_data; ++nr)
334 if (instance->xft_data[nr].widget == widget)
335 break;
336 if (nr < instance->nr_xft_data)
337 {
338 set_text (&instance->xft_data[nr], instance->parent,
339 val->value, 6);
340
341 /* Must set internalHeight to twice the highlight thickness,
342 or else it gets overwritten by our pixmap. Probably a bug. */
343 XtVaGetValues (widget, XtNhighlightThickness, &th, NULL);
344 XtSetArg (al[ac], XtNinternalHeight, 2*th);ac++;
345 }
346 }
347 #endif
348 XtSetValues (widget, al, ac);
349 XtRemoveAllCallbacks (widget, XtNcallback);
350 XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance);
351 }
352 }
353
354 void
355 xaw_update_one_value (widget_instance *instance,
356 Widget widget,
357 widget_value *val)
358 {
359 /* This function is not used by the scrollbars and those are the only
360 Athena widget implemented at the moment so do nothing. */
361 return;
362 }
363
364 void
365 xaw_destroy_instance (widget_instance *instance)
366 {
367 #ifdef HAVE_XFT
368 if (instance->xft_data)
369 {
370 int i;
371 for (i = 0; i < instance->nr_xft_data; ++i)
372 {
373 if (instance->xft_data[i].xft_draw)
374 XftDrawDestroy (instance->xft_data[i].xft_draw);
375 if (instance->xft_data[i].p != None)
376 {
377 XtVaSetValues (instance->xft_data[i].widget, XtNbitmap, None,
378 NULL);
379 XFreePixmap (XtDisplay (instance->widget),
380 instance->xft_data[i].p);
381 }
382 }
383 if (instance->xft_data[0].xft_font)
384 XftFontClose (XtDisplay (instance->widget),
385 instance->xft_data[0].xft_font);
386 free (instance->xft_data);
387 }
388 #endif
389 if (XtIsSubclass (instance->widget, dialogWidgetClass))
390 /* Need to destroy the Shell too. */
391 XtDestroyWidget (XtParent (instance->widget));
392 else
393 XtDestroyWidget (instance->widget);
394 }
395
396 void
397 xaw_popup_menu (Widget widget, XEvent *event)
398 {
399 /* An Athena menubar has not been implemented. */
400 return;
401 }
402
403 void
404 xaw_pop_instance (widget_instance *instance, Boolean up)
405 {
406 Widget widget = instance->widget;
407
408 if (up)
409 {
410 if (XtIsSubclass (widget, dialogWidgetClass))
411 {
412 /* For dialogs, we need to call XtPopup on the parent instead
413 of calling XtManageChild on the widget.
414 Also we need to hack the shell's WM_PROTOCOLS to get it to
415 understand what the close box is supposed to do!!
416 */
417 Display *dpy = XtDisplay (widget);
418 Widget shell = XtParent (widget);
419 Atom props [2];
420 int i = 0;
421 props [i++] = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
422 XChangeProperty (dpy, XtWindow (shell),
423 XInternAtom (dpy, "WM_PROTOCOLS", False),
424 XA_ATOM, 32, PropModeAppend,
425 (unsigned char *) props, i);
426
427 /* Center the widget in its parent. Why isn't this kind of crap
428 done automatically? I thought toolkits were supposed to make
429 life easier?
430 */
431 {
432 unsigned int x, y, w, h;
433 Widget topmost = instance->parent;
434 Arg args[2];
435
436 w = shell->core.width;
437 h = shell->core.height;
438 while (topmost->core.parent && XtIsRealized (topmost->core.parent))
439 topmost = topmost->core.parent;
440 if (topmost->core.width < w) x = topmost->core.x;
441 else x = topmost->core.x + ((topmost->core.width - w) / 2);
442 if (topmost->core.height < h) y = topmost->core.y;
443 else y = topmost->core.y + ((topmost->core.height - h) / 2);
444 /* Using XtMoveWidget caused the widget to come
445 out in the wrong place with vtwm.
446 Question of virtual vs real coords, perhaps. */
447 XtSetArg (args[0], XtNx, x);
448 XtSetArg (args[1], XtNy, y);
449 XtSetValues (shell, args, 2);
450 }
451
452 /* Finally, pop it up. */
453 XtPopup (shell, XtGrabNonexclusive);
454 }
455 else
456 XtManageChild (widget);
457 }
458 else
459 {
460 if (XtIsSubclass (widget, dialogWidgetClass))
461 XtUnmanageChild (XtParent (widget));
462 else
463 XtUnmanageChild (widget);
464 }
465 }
466
467 \f
468 /* Dialog boxes */
469
470 static char overrideTrans[] =
471 "<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
472 /* Dialogs pop down on any key press */
473 static char dialogOverride[] =
474 "<KeyPress>Escape: lwlib_delete_dialog()";
475 static void wm_delete_window (Widget w,
476 XEvent *event,
477 String *params,
478 Cardinal *num_params);
479 static XtActionsRec xaw_actions [] = {
480 {"lwlib_delete_dialog", wm_delete_window}
481 };
482 static Boolean actions_initted = False;
483
484 #ifdef HAVE_XFT
485 static XtActionsRec button_actions[] =
486 {
487 { "my_reset", command_reset },
488 { "my_press", command_press },
489 };
490 char buttonTrans[] =
491 "<Leave>: reset() my_reset()\n"
492 "<Btn1Down>: set() my_press()\n"
493 "<Btn1Up>: my_reset() notify() unset()\n";
494 #endif
495
496 static Widget
497 make_dialog (char* name,
498 Widget parent,
499 Boolean pop_up_p,
500 char* shell_title,
501 char* icon_name,
502 Boolean text_input_slot,
503 Boolean radio_box,
504 Boolean list,
505 int left_buttons,
506 int right_buttons,
507 widget_instance *instance)
508 {
509 Arg av [20];
510 int ac = 0;
511 int i, bc;
512 char button_name [255];
513 Widget shell;
514 Widget dialog;
515 Widget button;
516 XtTranslations override;
517 #ifdef HAVE_XFT
518 XftFont *xft_font = 0;
519 XtTranslations button_override;
520 #endif
521
522 if (! pop_up_p) abort (); /* not implemented */
523 if (text_input_slot) abort (); /* not implemented */
524 if (radio_box) abort (); /* not implemented */
525 if (list) abort (); /* not implemented */
526
527 if (! actions_initted)
528 {
529 XtAppContext app = XtWidgetToApplicationContext (parent);
530 XtAppAddActions (app, xaw_actions,
531 sizeof (xaw_actions) / sizeof (xaw_actions[0]));
532 #ifdef HAVE_XFT
533 XtAppAddActions (app, button_actions,
534 sizeof (button_actions) / sizeof (button_actions[0]));
535 #endif
536 actions_initted = True;
537 }
538
539 override = XtParseTranslationTable (overrideTrans);
540
541 ac = 0;
542 XtSetArg (av[ac], XtNtitle, shell_title); ac++;
543 XtSetArg (av[ac], XtNallowShellResize, True); ac++;
544
545 /* Don't allow any geometry request from the user. */
546 XtSetArg (av[ac], XtNgeometry, 0); ac++;
547
548 shell = XtCreatePopupShell ("dialog", transientShellWidgetClass,
549 parent, av, ac);
550 XtOverrideTranslations (shell, override);
551
552 ac = 0;
553 dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac);
554 override = XtParseTranslationTable (dialogOverride);
555 XtOverrideTranslations (dialog, override);
556
557 #ifdef HAVE_XFT
558 {
559 int num;
560 Widget *ch = NULL;
561 Widget w = 0;
562 XtVaGetValues (dialog,
563 XtNnumChildren, &num,
564 XtNchildren, &ch, NULL);
565 for (i = 0; i < num; ++i)
566 {
567 if (!XtIsSubclass (ch[i], commandWidgetClass)
568 && XtIsSubclass (ch[i], labelWidgetClass))
569 {
570 w = ch[i];
571 break;
572 }
573 }
574 instance->xft_data = 0;
575 instance->nr_xft_data = 0;
576 if (w)
577 {
578 XtResource rec[] =
579 { { "faceName", "FaceName", XtRString, sizeof(String), 0, XtRString,
580 (XtPointer)"Sans-14" }};
581 char *faceName;
582 XtVaGetSubresources (dialog, &faceName, "Dialog", "dialog",
583 rec, 1, (String)NULL);
584 if (strcmp ("none", faceName) != 0)
585 xft_font = openFont (dialog, faceName);
586 if (xft_font)
587 {
588 instance->nr_xft_data = left_buttons + right_buttons + 1;
589 instance->xft_data = calloc (instance->nr_xft_data,
590 sizeof(*instance->xft_data));
591
592 fill_xft_data (&instance->xft_data[0], w, xft_font);
593 }
594 }
595
596 button_override = XtParseTranslationTable (buttonTrans);
597 }
598 #endif
599
600 bc = 0;
601 button = 0;
602 for (i = 0; i < left_buttons; i++)
603 {
604 ac = 0;
605 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
606 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
607 XtSetArg (av [ac], XtNright, XtChainLeft); ac++;
608 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
609 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
610 XtSetArg (av [ac], XtNresizable, True); ac++;
611 #ifdef HAVE_XAW3D
612 if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16)
613 {
614 /* Turn of dithered shadow if we can. Looks bad */
615 XtSetArg (av [ac], "beNiceToColormap", False); ac++;
616 }
617 #endif
618 sprintf (button_name, "button%d", ++bc);
619 button = XtCreateManagedWidget (button_name, commandWidgetClass,
620 dialog, av, ac);
621 #ifdef HAVE_XFT
622 if (xft_font)
623 {
624 fill_xft_data (&instance->xft_data[bc], button, xft_font);
625 XtOverrideTranslations (button, button_override);
626 }
627 #endif
628 }
629
630 for (i = 0; i < right_buttons; i++)
631 {
632 ac = 0;
633 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
634 if (i == 0)
635 {
636 /* Separator to the other buttons. */
637 XtSetArg (av [ac], XtNhorizDistance, 30); ac++;
638 }
639 XtSetArg (av [ac], XtNleft, XtChainRight); ac++;
640 XtSetArg (av [ac], XtNright, XtChainRight); ac++;
641 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
642 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
643 XtSetArg (av [ac], XtNresizable, True); ac++;
644 #ifdef HAVE_XAW3D
645 if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16)
646 {
647 /* Turn of dithered shadow if we can. Looks bad */
648 XtSetArg (av [ac], "beNiceToColormap", False); ac++;
649 }
650 #endif
651 sprintf (button_name, "button%d", ++bc);
652 button = XtCreateManagedWidget (button_name, commandWidgetClass,
653 dialog, av, ac);
654 #ifdef HAVE_XFT
655 if (xft_font)
656 {
657 fill_xft_data (&instance->xft_data[bc], button, xft_font);
658 XtOverrideTranslations (button, button_override);
659 }
660 #endif
661 }
662
663 return dialog;
664 }
665
666 Widget
667 xaw_create_dialog (widget_instance *instance)
668 {
669 char *name = instance->info->type;
670 Widget parent = instance->parent;
671 Widget widget;
672 Boolean pop_up_p = instance->pop_up_p;
673 char *shell_name = 0;
674 char *icon_name = 0;
675 Boolean text_input_slot = False;
676 Boolean radio_box = False;
677 Boolean list = False;
678 int total_buttons;
679 int left_buttons = 0;
680 int right_buttons = 1;
681
682 switch (name [0]) {
683 case 'E': case 'e':
684 icon_name = "dbox-error";
685 shell_name = "Error";
686 break;
687
688 case 'I': case 'i':
689 icon_name = "dbox-info";
690 shell_name = "Information";
691 break;
692
693 case 'L': case 'l':
694 list = True;
695 icon_name = "dbox-question";
696 shell_name = "Prompt";
697 break;
698
699 case 'P': case 'p':
700 text_input_slot = True;
701 icon_name = "dbox-question";
702 shell_name = "Prompt";
703 break;
704
705 case 'Q': case 'q':
706 icon_name = "dbox-question";
707 shell_name = "Question";
708 break;
709 }
710
711 total_buttons = name [1] - '0';
712
713 if (name [3] == 'T' || name [3] == 't')
714 {
715 text_input_slot = False;
716 radio_box = True;
717 }
718 else if (name [3])
719 right_buttons = name [4] - '0';
720
721 left_buttons = total_buttons - right_buttons;
722
723 widget = make_dialog (name, parent, pop_up_p,
724 shell_name, icon_name, text_input_slot, radio_box,
725 list, left_buttons, right_buttons, instance);
726 return widget;
727 }
728
729
730 static void
731 xaw_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
732 {
733 widget_instance *instance = (widget_instance *) closure;
734 Widget instance_widget;
735 LWLIB_ID id;
736 XtPointer user_data;
737
738 lw_internal_update_other_instances (widget, closure, call_data);
739
740 if (! instance)
741 return;
742 if (widget->core.being_destroyed)
743 return;
744
745 instance_widget = instance->widget;
746 if (!instance_widget)
747 return;
748
749 id = instance->info->id;
750
751 /* Damn! Athena doesn't give us a way to hang our own data on the
752 buttons, so we have to go find it... I guess this assumes that
753 all instances of a button have the same call data. */
754 {
755 widget_value *val = instance->info->val->contents;
756 char *name = XtName (widget);
757 while (val)
758 {
759 if (val->name && !strcmp (val->name, name))
760 break;
761 val = val->next;
762 }
763 if (! val) abort ();
764 user_data = val->call_data;
765 }
766
767 if (instance->info->selection_cb)
768 instance->info->selection_cb (widget, id, user_data);
769 }
770
771 static void
772 wm_delete_window (Widget w,
773 XEvent *event,
774 String *params,
775 Cardinal *num_params)
776 {
777 LWLIB_ID id;
778 Cardinal nkids;
779 int i;
780 Widget *kids = 0;
781 Widget widget = 0, shell;
782
783 if (XtIsSubclass (w, dialogWidgetClass))
784 shell = XtParent (w);
785 else
786 shell = w;
787
788 if (! XtIsSubclass (shell, shellWidgetClass))
789 abort ();
790 XtVaGetValues (shell, XtNnumChildren, &nkids, NULL);
791 XtVaGetValues (shell, XtNchildren, &kids, NULL);
792 if (!kids || !*kids)
793 abort ();
794 for (i = 0; i < nkids; i++)
795 {
796 widget = kids[i];
797 if (XtIsSubclass (widget, dialogWidgetClass))
798 break;
799 }
800 if (! widget) return;
801
802 id = lw_get_widget_id (widget);
803 if (! id) abort ();
804
805 {
806 widget_info *info = lw_get_widget_info (id);
807 if (! info) abort ();
808 if (info->selection_cb)
809 info->selection_cb (widget, id, (XtPointer) -1);
810 }
811
812 lw_destroy_all_widgets (id);
813 }
814
815 \f
816
817 static Widget
818 xaw_create_main (widget_instance *instance)
819 {
820 Arg al[1];
821 int ac;
822
823 /* Create a vertical Paned to hold menubar */
824 ac = 0;
825 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
826 return XtCreateWidget (instance->info->name, panedWidgetClass,
827 instance->parent, al, ac);
828 }
829
830 widget_creation_entry
831 xaw_creation_table [] =
832 {
833 {"main", xaw_create_main},
834 {NULL, NULL}
835 };
836