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