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