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