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