]> code.delx.au - gnu-emacs/blob - lwlib/lwlib-Xaw.c
Merge from emacs-23; up to 2010-06-12T11:17:12Z!eliz@gnu.org.
[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 { { "font", "Font", XtRString, sizeof(String), 0, XtRString,
581 (XtPointer)"Sans-10" }};
582 char *fontName = NULL;
583 XtVaGetSubresources (dialog, &fontName, "Dialog", "dialog",
584 rec, 1, (String)NULL);
585 if (fontName)
586 {
587 XFontStruct *xfn = XLoadQueryFont (XtDisplay (dialog), fontName);
588 if (!xfn)
589 xft_font = openFont (dialog, fontName);
590 else
591 XFreeFont (XtDisplay (dialog), xfn);
592 }
593
594 if (xft_font)
595 {
596 instance->nr_xft_data = left_buttons + right_buttons + 1;
597 instance->xft_data = calloc (instance->nr_xft_data,
598 sizeof(*instance->xft_data));
599
600 fill_xft_data (&instance->xft_data[0], w, xft_font);
601 }
602 }
603
604 button_override = XtParseTranslationTable (buttonTrans);
605 }
606 #endif
607
608 bc = 0;
609 button = 0;
610 for (i = 0; i < left_buttons; i++)
611 {
612 ac = 0;
613 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
614 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
615 XtSetArg (av [ac], XtNright, XtChainLeft); ac++;
616 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
617 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
618 XtSetArg (av [ac], XtNresizable, True); ac++;
619 #ifdef HAVE_XAW3D
620 if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16)
621 {
622 /* Turn of dithered shadow if we can. Looks bad */
623 XtSetArg (av [ac], "beNiceToColormap", False); ac++;
624 }
625 #endif
626 sprintf (button_name, "button%d", ++bc);
627 button = XtCreateManagedWidget (button_name, commandWidgetClass,
628 dialog, av, ac);
629 #ifdef HAVE_XFT
630 if (xft_font)
631 {
632 fill_xft_data (&instance->xft_data[bc], button, xft_font);
633 XtOverrideTranslations (button, button_override);
634 }
635 #endif
636 }
637
638 for (i = 0; i < right_buttons; i++)
639 {
640 ac = 0;
641 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
642 if (i == 0)
643 {
644 /* Separator to the other buttons. */
645 XtSetArg (av [ac], XtNhorizDistance, 30); ac++;
646 }
647 XtSetArg (av [ac], XtNleft, XtChainRight); ac++;
648 XtSetArg (av [ac], XtNright, XtChainRight); ac++;
649 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
650 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
651 XtSetArg (av [ac], XtNresizable, True); ac++;
652 #ifdef HAVE_XAW3D
653 if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16)
654 {
655 /* Turn of dithered shadow if we can. Looks bad */
656 XtSetArg (av [ac], "beNiceToColormap", False); ac++;
657 }
658 #endif
659 sprintf (button_name, "button%d", ++bc);
660 button = XtCreateManagedWidget (button_name, commandWidgetClass,
661 dialog, av, ac);
662 #ifdef HAVE_XFT
663 if (xft_font)
664 {
665 fill_xft_data (&instance->xft_data[bc], button, xft_font);
666 XtOverrideTranslations (button, button_override);
667 }
668 #endif
669 }
670
671 return dialog;
672 }
673
674 Widget
675 xaw_create_dialog (widget_instance *instance)
676 {
677 char *name = instance->info->type;
678 Widget parent = instance->parent;
679 Widget widget;
680 Boolean pop_up_p = instance->pop_up_p;
681 char *shell_name = 0;
682 char *icon_name = 0;
683 Boolean text_input_slot = False;
684 Boolean radio_box = False;
685 Boolean list = False;
686 int total_buttons;
687 int left_buttons = 0;
688 int right_buttons = 1;
689
690 switch (name [0]) {
691 case 'E': case 'e':
692 icon_name = "dbox-error";
693 shell_name = "Error";
694 break;
695
696 case 'I': case 'i':
697 icon_name = "dbox-info";
698 shell_name = "Information";
699 break;
700
701 case 'L': case 'l':
702 list = True;
703 icon_name = "dbox-question";
704 shell_name = "Prompt";
705 break;
706
707 case 'P': case 'p':
708 text_input_slot = True;
709 icon_name = "dbox-question";
710 shell_name = "Prompt";
711 break;
712
713 case 'Q': case 'q':
714 icon_name = "dbox-question";
715 shell_name = "Question";
716 break;
717 }
718
719 total_buttons = name [1] - '0';
720
721 if (name [3] == 'T' || name [3] == 't')
722 {
723 text_input_slot = False;
724 radio_box = True;
725 }
726 else if (name [3])
727 right_buttons = name [4] - '0';
728
729 left_buttons = total_buttons - right_buttons;
730
731 widget = make_dialog (name, parent, pop_up_p,
732 shell_name, icon_name, text_input_slot, radio_box,
733 list, left_buttons, right_buttons, instance);
734 return widget;
735 }
736
737
738 static void
739 xaw_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
740 {
741 widget_instance *instance = (widget_instance *) closure;
742 Widget instance_widget;
743 LWLIB_ID id;
744 XtPointer user_data;
745
746 lw_internal_update_other_instances (widget, closure, call_data);
747
748 if (! instance)
749 return;
750 if (widget->core.being_destroyed)
751 return;
752
753 instance_widget = instance->widget;
754 if (!instance_widget)
755 return;
756
757 id = instance->info->id;
758
759 /* Damn! Athena doesn't give us a way to hang our own data on the
760 buttons, so we have to go find it... I guess this assumes that
761 all instances of a button have the same call data. */
762 {
763 widget_value *val = instance->info->val->contents;
764 char *name = XtName (widget);
765 while (val)
766 {
767 if (val->name && !strcmp (val->name, name))
768 break;
769 val = val->next;
770 }
771 if (! val) abort ();
772 user_data = val->call_data;
773 }
774
775 if (instance->info->selection_cb)
776 instance->info->selection_cb (widget, id, user_data);
777 }
778
779 static void
780 wm_delete_window (Widget w,
781 XEvent *event,
782 String *params,
783 Cardinal *num_params)
784 {
785 LWLIB_ID id;
786 Cardinal nkids;
787 int i;
788 Widget *kids = 0;
789 Widget widget = 0, shell;
790
791 if (XtIsSubclass (w, dialogWidgetClass))
792 shell = XtParent (w);
793 else
794 shell = w;
795
796 if (! XtIsSubclass (shell, shellWidgetClass))
797 abort ();
798 XtVaGetValues (shell, XtNnumChildren, &nkids, NULL);
799 XtVaGetValues (shell, XtNchildren, &kids, NULL);
800 if (!kids || !*kids)
801 abort ();
802 for (i = 0; i < nkids; i++)
803 {
804 widget = kids[i];
805 if (XtIsSubclass (widget, dialogWidgetClass))
806 break;
807 }
808 if (! widget) return;
809
810 id = lw_get_widget_id (widget);
811 if (! id) abort ();
812
813 {
814 widget_info *info = lw_get_widget_info (id);
815 if (! info) abort ();
816 if (info->selection_cb)
817 info->selection_cb (widget, id, (XtPointer) -1);
818 }
819
820 lw_destroy_all_widgets (id);
821 }
822
823 \f
824
825 static Widget
826 xaw_create_main (widget_instance *instance)
827 {
828 Arg al[1];
829 int ac;
830
831 /* Create a vertical Paned to hold menubar */
832 ac = 0;
833 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
834 return XtCreateWidget (instance->info->name, panedWidgetClass,
835 instance->parent, al, ac);
836 }
837
838 widget_creation_entry
839 xaw_creation_table [] =
840 {
841 {"main", xaw_create_main},
842 {NULL, NULL}
843 };