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