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