Do not ispell-kill-ispell over and over when spellchecking minibuffer contents.
[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
79140ef0 73static void xaw_generic_callback (/*Widget, XtPointer, XtPointer*/);
b70cfce2
FP
74
75
76Boolean
e14e13a4
FP
77lw_xaw_widget_p (widget)
78 Widget widget;
b70cfce2
FP
79{
80 return (XtIsSubclass (widget, scrollbarWidgetClass) ||
81 XtIsSubclass (widget, dialogWidgetClass));
82}
83
abf0cb21 84#if 0
b70cfce2 85static void
e14e13a4
FP
86xaw_update_scrollbar (instance, widget, val)
87 widget_instance *instance;
88 Widget widget;
89 widget_value *val;
b70cfce2 90{
b70cfce2
FP
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,
8dd095ee 106 NULL);
b70cfce2
FP
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,
8dd095ee 121 NULL);
b70cfce2
FP
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 }
b70cfce2 146}
abf0cb21 147#endif
b70cfce2 148
1ecb2d3f
JD
149#ifdef HAVE_XFT
150static void
151fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font)
152{
1ecb2d3f
JD
153 Pixel bg, fg;
154 XColor colors[2];
155 int screen = XScreenNumberOfScreen (XtScreen (widget));
156
c632dfda
JD
157 data->widget = widget;
158 data->xft_font = font;
1ecb2d3f
JD
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
184static XftFont*
185openFont (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
207static int
208get_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
232static void
233draw_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
265static void
266set_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
285static struct widget_xft_data *
286find_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
308static void
309command_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
326static void
327command_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
b70cfce2 350void
207c13a7
DL
351#ifdef PROTOTYPES
352xaw_update_one_widget (widget_instance *instance, Widget widget,
353 widget_value *val, Boolean deep_p)
354#else
e14e13a4
FP
355xaw_update_one_widget (instance, widget, val, deep_p)
356 widget_instance *instance;
357 Widget widget;
358 widget_value *val;
359 Boolean deep_p;
207c13a7 360#endif
b70cfce2 361{
13162c0e 362#if 0
b70cfce2
FP
363 if (XtIsSubclass (widget, scrollbarWidgetClass))
364 {
365 xaw_update_scrollbar (instance, widget, val);
366 }
13162c0e
RS
367#endif
368 if (XtIsSubclass (widget, dialogWidgetClass))
b70cfce2 369 {
1ecb2d3f
JD
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);
b70cfce2
FP
379 }
380 else if (XtIsSubclass (widget, commandWidgetClass))
381 {
382 Dimension bw = 0;
1ecb2d3f
JD
383 Arg al[10];
384 int ac = 0;
13162c0e 385
8dd095ee 386 XtVaGetValues (widget, XtNborderWidth, &bw, NULL);
b70cfce2
FP
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 */
13162c0e
RS
394 {
395 XtSetArg (al[0], XtNborderWidth, 1);
396 XtSetValues (widget, al, 1);
397 }
b70cfce2 398
2a73ab60 399 XtSetSensitive (widget, val->enabled);
1ecb2d3f 400 XtSetArg (al[ac], XtNlabel, val->value);ac++;
13162c0e 401 /* Force centered button text. Se above. */
1ecb2d3f
JD
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);
b70cfce2
FP
424 XtRemoveAllCallbacks (widget, XtNcallback);
425 XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance);
426 }
427}
428
429void
e14e13a4
FP
430xaw_update_one_value (instance, widget, val)
431 widget_instance *instance;
432 Widget widget;
433 widget_value *val;
b70cfce2
FP
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
440void
e14e13a4
FP
441xaw_destroy_instance (instance)
442 widget_instance *instance;
b70cfce2 443{
1ecb2d3f
JD
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
b70cfce2
FP
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
473void
4374c6b0 474xaw_popup_menu (widget, event)
e14e13a4 475 Widget widget;
4374c6b0 476 XEvent *event;
b70cfce2
FP
477{
478 /* An Athena menubar has not been implemented. */
479 return;
480}
481
482void
207c13a7
DL
483#ifdef PROTOTYPES
484xaw_pop_instance (widget_instance *instance, Boolean up)
485#else
e14e13a4
FP
486xaw_pop_instance (instance, up)
487 widget_instance *instance;
488 Boolean up;
207c13a7 489#endif
b70cfce2
FP
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 {
e363091e 517 unsigned int x, y, w, h;
b70cfce2 518 Widget topmost = instance->parent;
2af91681
PR
519 Arg args[2];
520
b70cfce2
FP
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);
2af91681
PR
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);
b70cfce2
FP
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
555static char overrideTrans[] =
556 "<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
244c93fe
JD
557/* Dialogs pop down on any key press */
558static char dialogOverride[] =
4e6e2184 559 "<KeyPress>Escape: lwlib_delete_dialog()";
b70cfce2
FP
560static void wm_delete_window();
561static XtActionsRec xaw_actions [] = {
562 {"lwlib_delete_dialog", wm_delete_window}
563};
564static Boolean actions_initted = False;
565
1ecb2d3f
JD
566#ifdef HAVE_XFT
567static XtActionsRec button_actions[] =
568 {
569 { "my_reset", command_reset },
570 { "my_press", command_press },
571 };
572char buttonTrans[] =
573 "<Leave>: reset() my_reset()\n"
574 "<Btn1Down>: set() my_press()\n"
575 "<Btn1Up>: my_reset() notify() unset()\n";
576#endif
577
b70cfce2 578static Widget
1ecb2d3f
JD
579make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot,
580 radio_box, list, left_buttons, right_buttons, instance)
e14e13a4
FP
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;
1ecb2d3f 591 widget_instance *instance;
b70cfce2
FP
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;
1ecb2d3f
JD
601#ifdef HAVE_XFT
602 XftFont *xft_font = 0;
603 XtTranslations button_override;
604#endif
b70cfce2
FP
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]));
1ecb2d3f
JD
616#ifdef HAVE_XFT
617 XtAppAddActions (app, button_actions,
618 sizeof (button_actions) / sizeof (button_actions[0]));
619#endif
b70cfce2
FP
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++;
dc49df96
FP
628
629 /* Don't allow any geometry request from the user. */
630 XtSetArg (av[ac], XtNgeometry, 0); ac++;
631
b70cfce2
FP
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);
244c93fe
JD
638 override = XtParseTranslationTable (dialogOverride);
639 XtOverrideTranslations (dialog, override);
b70cfce2 640
1ecb2d3f
JD
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, 0, 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
b70cfce2
FP
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++;
1ecb2d3f
JD
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
b70cfce2
FP
702 sprintf (button_name, "button%d", ++bc);
703 button = XtCreateManagedWidget (button_name, commandWidgetClass,
704 dialog, av, ac);
1ecb2d3f
JD
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
b70cfce2 712 }
b70cfce2 713
b70cfce2
FP
714 for (i = 0; i < right_buttons; i++)
715 {
716 ac = 0;
717 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
1ecb2d3f
JD
718 if (i == 0)
719 {
720 /* Separator to the other buttons. */
721 XtSetArg (av [ac], XtNhorizDistance, 30); ac++;
722 }
b70cfce2
FP
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++;
1ecb2d3f
JD
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
b70cfce2
FP
735 sprintf (button_name, "button%d", ++bc);
736 button = XtCreateManagedWidget (button_name, commandWidgetClass,
737 dialog, av, ac);
1ecb2d3f
JD
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
b70cfce2
FP
745 }
746
747 return dialog;
748}
749
750Widget
e14e13a4
FP
751xaw_create_dialog (instance)
752 widget_instance* instance;
b70cfce2
FP
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;
ca79970e 759 char *icon_name = 0;
b70cfce2
FP
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 }
177c0ea7 795
b70cfce2
FP
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';
177c0ea7 805
b70cfce2 806 left_buttons = total_buttons - right_buttons;
177c0ea7 807
b70cfce2
FP
808 widget = make_dialog (name, parent, pop_up_p,
809 shell_name, icon_name, text_input_slot, radio_box,
1ecb2d3f 810 list, left_buttons, right_buttons, instance);
b70cfce2
FP
811 return widget;
812}
813
814
815static void
e14e13a4
FP
816xaw_generic_callback (widget, closure, call_data)
817 Widget widget;
818 XtPointer closure;
819 XtPointer call_data;
b70cfce2
FP
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;
8dd095ee 841 XtVaGetValues (widget, XtNuserData, &user_data, NULL);
b70cfce2
FP
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
864static void
244c93fe
JD
865wm_delete_window (w, closure, call_data)
866 Widget w;
e14e13a4
FP
867 XtPointer closure;
868 XtPointer call_data;
b70cfce2
FP
869{
870 LWLIB_ID id;
8dce2ddc
RS
871 Cardinal nkids;
872 int i;
b70cfce2 873 Widget *kids = 0;
244c93fe
JD
874 Widget widget, shell;
875
876 if (XtIsSubclass (w, dialogWidgetClass))
877 shell = XtParent (w);
878 else
879 shell = w;
880
b70cfce2
FP
881 if (! XtIsSubclass (shell, shellWidgetClass))
882 abort ();
8dd095ee
GM
883 XtVaGetValues (shell, XtNnumChildren, &nkids, NULL);
884 XtVaGetValues (shell, XtNchildren, &kids, NULL);
b70cfce2
FP
885 if (!kids || !*kids)
886 abort ();
8dce2ddc
RS
887 for (i = 0; i < nkids; i++)
888 {
889 widget = kids[i];
890 if (XtIsSubclass (widget, dialogWidgetClass))
891 break;
892 }
b70cfce2
FP
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
abf0cb21 909#if 0
b70cfce2 910static void
e14e13a4
FP
911xaw_scrollbar_scroll (widget, closure, call_data)
912 Widget widget;
913 XtPointer closure;
914 XtPointer call_data;
b70cfce2 915{
b70cfce2
FP
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);
b70cfce2 934}
abf0cb21 935#endif
b70cfce2 936
abf0cb21 937#if 0
b70cfce2 938static void
e14e13a4
FP
939xaw_scrollbar_jump (widget, closure, call_data)
940 Widget widget;
941 XtPointer closure;
942 XtPointer call_data;
b70cfce2 943{
b70cfce2
FP
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);
b70cfce2 965}
abf0cb21 966#endif
b70cfce2
FP
967
968static Widget
e14e13a4
FP
969xaw_create_scrollbar (instance)
970 widget_instance *instance;
b70cfce2
FP
971{
972#if 0
973 Arg av[20];
974 int ac = 0;
975 Dimension width;
976 Widget scrollbar;
977
8dd095ee 978 XtVaGetValues (instance->parent, XtNwidth, &width, NULL);
177c0ea7 979
b70cfce2
FP
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... */
8dd095ee 993 XtVaSetValues (scrollbar, XtNborderWidth, 0, NULL);
b70cfce2
FP
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;
21dd28d4
GM
1004#else
1005 return NULL;
b70cfce2
FP
1006#endif
1007}
1008
2af91681
PR
1009static Widget
1010xaw_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
b70cfce2
FP
1023widget_creation_entry
1024xaw_creation_table [] =
1025{
1026 {"scrollbar", xaw_create_scrollbar},
2af91681 1027 {"main", xaw_create_main},
b70cfce2
FP
1028 {NULL, NULL}
1029};
ab5796a9
MB
1030
1031/* arch-tag: fbbd3589-ae1c-41a0-9142-f628cfee6564
1032 (do not change this comment) */