Merge from emacs--rel--22
[emacs.git] / lwlib / lwlib-Xaw.c
blob5a2acf2eccfbe3d02f23a291a66d1efe3dec64ea
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 Free Software Foundation, Inc.
6 This file is part of the Lucid Widget Library.
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.
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.
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. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdio.h>
29 #include "../src/lisp.h"
31 #include "lwlib-Xaw.h"
33 #include <X11/StringDefs.h>
34 #include <X11/IntrinsicP.h>
35 #include <X11/CoreP.h>
36 #include <X11/Shell.h>
38 #ifdef HAVE_XAW3D
39 #include <X11/Xaw3d/Scrollbar.h>
40 #include <X11/Xaw3d/Paned.h>
41 #include <X11/Xaw3d/Dialog.h>
42 #include <X11/Xaw3d/Form.h>
43 #include <X11/Xaw3d/Command.h>
44 #include <X11/Xaw3d/Label.h>
45 #else /* !HAVE_XAW3D */
46 #include <X11/Xaw/Scrollbar.h>
47 #include <X11/Xaw/Paned.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Form.h>
50 #include <X11/Xaw/Command.h>
51 #include <X11/Xaw/Label.h>
52 #endif /* HAVE_XAW3D */
54 #include <X11/Xatom.h>
56 static void xaw_generic_callback (/*Widget, XtPointer, XtPointer*/);
59 Boolean
60 lw_xaw_widget_p (widget)
61 Widget widget;
63 return (XtIsSubclass (widget, scrollbarWidgetClass) ||
64 XtIsSubclass (widget, dialogWidgetClass));
67 #if 0
68 static void
69 xaw_update_scrollbar (instance, widget, val)
70 widget_instance *instance;
71 Widget widget;
72 widget_value *val;
74 if (val->scrollbar_data)
76 scrollbar_values *data = val->scrollbar_data;
77 Dimension height, width;
78 Dimension pos_x, pos_y;
79 int widget_shown, widget_topOfThumb;
80 float new_shown, new_topOfThumb;
82 XtVaGetValues (widget,
83 XtNheight, &height,
84 XtNwidth, &width,
85 XtNx, &pos_x,
86 XtNy, &pos_y,
87 XtNtopOfThumb, &widget_topOfThumb,
88 XtNshown, &widget_shown,
89 NULL);
92 * First size and position the scrollbar widget.
93 * We need to position it to second-guess the Paned widget's notion
94 * of what should happen when the WMShell gets resized.
96 if (height != data->scrollbar_height || pos_y != data->scrollbar_pos)
98 XtConfigureWidget (widget, pos_x, data->scrollbar_pos,
99 width, data->scrollbar_height, 0);
101 XtVaSetValues (widget,
102 XtNlength, data->scrollbar_height,
103 XtNthickness, width,
104 NULL);
108 * Now the size the scrollbar's slider.
110 new_shown = (float) data->slider_size /
111 (float) (data->maximum - data->minimum);
113 new_topOfThumb = (float) (data->slider_position - data->minimum) /
114 (float) (data->maximum - data->minimum);
116 if (new_shown > 1.0)
117 new_shown = 1.0;
118 if (new_shown < 0)
119 new_shown = 0;
121 if (new_topOfThumb > 1.0)
122 new_topOfThumb = 1.0;
123 if (new_topOfThumb < 0)
124 new_topOfThumb = 0;
126 if (new_shown != widget_shown || new_topOfThumb != widget_topOfThumb)
127 XawScrollbarSetThumb (widget, new_topOfThumb, new_shown);
130 #endif
132 void
133 #ifdef PROTOTYPES
134 xaw_update_one_widget (widget_instance *instance, Widget widget,
135 widget_value *val, Boolean deep_p)
136 #else
137 xaw_update_one_widget (instance, widget, val, deep_p)
138 widget_instance *instance;
139 Widget widget;
140 widget_value *val;
141 Boolean deep_p;
142 #endif
144 #if 0
145 if (XtIsSubclass (widget, scrollbarWidgetClass))
147 xaw_update_scrollbar (instance, widget, val);
149 #endif
150 if (XtIsSubclass (widget, dialogWidgetClass))
152 Arg al[1];
153 int ac = 0;
154 XtSetArg (al[ac], XtNlabel, val->contents->value); ac++;
155 XtSetValues (widget, al, ac);
157 else if (XtIsSubclass (widget, commandWidgetClass))
159 Dimension bw = 0;
160 Arg al[3];
162 XtVaGetValues (widget, XtNborderWidth, &bw, NULL);
163 if (bw == 0)
164 /* Don't let buttons end up with 0 borderwidth, that's ugly...
165 Yeah, all this should really be done through app-defaults files
166 or fallback resources, but that's a whole different can of worms
167 that I don't feel like opening right now. Making Athena widgets
168 not look like shit is just entirely too much work.
171 XtSetArg (al[0], XtNborderWidth, 1);
172 XtSetValues (widget, al, 1);
175 XtSetSensitive (widget, val->enabled);
176 XtSetArg (al[0], XtNlabel, val->value);
177 /* Force centered button text. Se above. */
178 XtSetArg (al[1], XtNjustify, XtJustifyCenter);
179 XtSetValues (widget, al, 2);
180 XtRemoveAllCallbacks (widget, XtNcallback);
181 XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance);
185 void
186 xaw_update_one_value (instance, widget, val)
187 widget_instance *instance;
188 Widget widget;
189 widget_value *val;
191 /* This function is not used by the scrollbars and those are the only
192 Athena widget implemented at the moment so do nothing. */
193 return;
196 void
197 xaw_destroy_instance (instance)
198 widget_instance *instance;
200 if (XtIsSubclass (instance->widget, dialogWidgetClass))
201 /* Need to destroy the Shell too. */
202 XtDestroyWidget (XtParent (instance->widget));
203 else
204 XtDestroyWidget (instance->widget);
207 void
208 xaw_popup_menu (widget, event)
209 Widget widget;
210 XEvent *event;
212 /* An Athena menubar has not been implemented. */
213 return;
216 void
217 #ifdef PROTOTYPES
218 xaw_pop_instance (widget_instance *instance, Boolean up)
219 #else
220 xaw_pop_instance (instance, up)
221 widget_instance *instance;
222 Boolean up;
223 #endif
225 Widget widget = instance->widget;
227 if (up)
229 if (XtIsSubclass (widget, dialogWidgetClass))
231 /* For dialogs, we need to call XtPopup on the parent instead
232 of calling XtManageChild on the widget.
233 Also we need to hack the shell's WM_PROTOCOLS to get it to
234 understand what the close box is supposed to do!!
236 Display *dpy = XtDisplay (widget);
237 Widget shell = XtParent (widget);
238 Atom props [2];
239 int i = 0;
240 props [i++] = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
241 XChangeProperty (dpy, XtWindow (shell),
242 XInternAtom (dpy, "WM_PROTOCOLS", False),
243 XA_ATOM, 32, PropModeAppend,
244 (unsigned char *) props, i);
246 /* Center the widget in its parent. Why isn't this kind of crap
247 done automatically? I thought toolkits were supposed to make
248 life easier?
251 unsigned int x, y, w, h;
252 Widget topmost = instance->parent;
253 Arg args[2];
255 w = shell->core.width;
256 h = shell->core.height;
257 while (topmost->core.parent && XtIsRealized (topmost->core.parent))
258 topmost = topmost->core.parent;
259 if (topmost->core.width < w) x = topmost->core.x;
260 else x = topmost->core.x + ((topmost->core.width - w) / 2);
261 if (topmost->core.height < h) y = topmost->core.y;
262 else y = topmost->core.y + ((topmost->core.height - h) / 2);
263 /* Using XtMoveWidget caused the widget to come
264 out in the wrong place with vtwm.
265 Question of virtual vs real coords, perhaps. */
266 XtSetArg (args[0], XtNx, x);
267 XtSetArg (args[1], XtNy, y);
268 XtSetValues (shell, args, 2);
271 /* Finally, pop it up. */
272 XtPopup (shell, XtGrabNonexclusive);
274 else
275 XtManageChild (widget);
277 else
279 if (XtIsSubclass (widget, dialogWidgetClass))
280 XtUnmanageChild (XtParent (widget));
281 else
282 XtUnmanageChild (widget);
287 /* Dialog boxes */
289 static char overrideTrans[] =
290 "<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
291 /* Dialogs pop down on any key press */
292 static char dialogOverride[] =
293 "<KeyPress>Escape: lwlib_delete_dialog()";
294 static void wm_delete_window();
295 static XtActionsRec xaw_actions [] = {
296 {"lwlib_delete_dialog", wm_delete_window}
298 static Boolean actions_initted = False;
300 static Widget
301 make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, radio_box, list, left_buttons, right_buttons)
302 char* name;
303 Widget parent;
304 Boolean pop_up_p;
305 char* shell_title;
306 char* icon_name;
307 Boolean text_input_slot;
308 Boolean radio_box;
309 Boolean list;
310 int left_buttons;
311 int right_buttons;
313 Arg av [20];
314 int ac = 0;
315 int i, bc;
316 char button_name [255];
317 Widget shell;
318 Widget dialog;
319 Widget button;
320 XtTranslations override;
322 if (! pop_up_p) abort (); /* not implemented */
323 if (text_input_slot) abort (); /* not implemented */
324 if (radio_box) abort (); /* not implemented */
325 if (list) abort (); /* not implemented */
327 if (! actions_initted)
329 XtAppContext app = XtWidgetToApplicationContext (parent);
330 XtAppAddActions (app, xaw_actions,
331 sizeof (xaw_actions) / sizeof (xaw_actions[0]));
332 actions_initted = True;
335 override = XtParseTranslationTable (overrideTrans);
337 ac = 0;
338 XtSetArg (av[ac], XtNtitle, shell_title); ac++;
339 XtSetArg (av[ac], XtNallowShellResize, True); ac++;
341 /* Don't allow any geometry request from the user. */
342 XtSetArg (av[ac], XtNgeometry, 0); ac++;
344 shell = XtCreatePopupShell ("dialog", transientShellWidgetClass,
345 parent, av, ac);
346 XtOverrideTranslations (shell, override);
348 ac = 0;
349 dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac);
350 override = XtParseTranslationTable (dialogOverride);
351 XtOverrideTranslations (dialog, override);
353 bc = 0;
354 button = 0;
355 for (i = 0; i < left_buttons; i++)
357 ac = 0;
358 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
359 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
360 XtSetArg (av [ac], XtNright, XtChainLeft); ac++;
361 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
362 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
363 XtSetArg (av [ac], XtNresizable, True); ac++;
364 sprintf (button_name, "button%d", ++bc);
365 button = XtCreateManagedWidget (button_name, commandWidgetClass,
366 dialog, av, ac);
368 if (right_buttons)
370 /* Create a separator
372 I want the separator to take up the slack between the buttons on
373 the right and the buttons on the left (that is I want the buttons
374 after the separator to be packed against the right edge of the
375 window) but I can't seem to make it do it.
377 ac = 0;
378 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
379 /* XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */
380 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
381 XtSetArg (av [ac], XtNright, XtChainRight); ac++;
382 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
383 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
384 XtSetArg (av [ac], XtNlabel, ""); ac++;
385 XtSetArg (av [ac], XtNwidth, 30); ac++; /* #### aaack!! */
386 XtSetArg (av [ac], XtNborderWidth, 0); ac++;
387 XtSetArg (av [ac], XtNshapeStyle, XmuShapeRectangle); ac++;
388 XtSetArg (av [ac], XtNresizable, False); ac++;
389 XtSetArg (av [ac], XtNsensitive, False); ac++;
390 button = XtCreateManagedWidget ("separator",
391 /* labelWidgetClass, */
392 /* This has to be Command to fake out
393 the Dialog widget... */
394 commandWidgetClass,
395 dialog, av, ac);
397 for (i = 0; i < right_buttons; i++)
399 ac = 0;
400 XtSetArg (av [ac], XtNfromHoriz, button); ac++;
401 XtSetArg (av [ac], XtNleft, XtChainRight); ac++;
402 XtSetArg (av [ac], XtNright, XtChainRight); ac++;
403 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
404 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
405 XtSetArg (av [ac], XtNresizable, True); ac++;
406 sprintf (button_name, "button%d", ++bc);
407 button = XtCreateManagedWidget (button_name, commandWidgetClass,
408 dialog, av, ac);
411 return dialog;
414 Widget
415 xaw_create_dialog (instance)
416 widget_instance* instance;
418 char *name = instance->info->type;
419 Widget parent = instance->parent;
420 Widget widget;
421 Boolean pop_up_p = instance->pop_up_p;
422 char *shell_name = 0;
423 char *icon_name = 0;
424 Boolean text_input_slot = False;
425 Boolean radio_box = False;
426 Boolean list = False;
427 int total_buttons;
428 int left_buttons = 0;
429 int right_buttons = 1;
431 switch (name [0]) {
432 case 'E': case 'e':
433 icon_name = "dbox-error";
434 shell_name = "Error";
435 break;
437 case 'I': case 'i':
438 icon_name = "dbox-info";
439 shell_name = "Information";
440 break;
442 case 'L': case 'l':
443 list = True;
444 icon_name = "dbox-question";
445 shell_name = "Prompt";
446 break;
448 case 'P': case 'p':
449 text_input_slot = True;
450 icon_name = "dbox-question";
451 shell_name = "Prompt";
452 break;
454 case 'Q': case 'q':
455 icon_name = "dbox-question";
456 shell_name = "Question";
457 break;
460 total_buttons = name [1] - '0';
462 if (name [3] == 'T' || name [3] == 't')
464 text_input_slot = False;
465 radio_box = True;
467 else if (name [3])
468 right_buttons = name [4] - '0';
470 left_buttons = total_buttons - right_buttons;
472 widget = make_dialog (name, parent, pop_up_p,
473 shell_name, icon_name, text_input_slot, radio_box,
474 list, left_buttons, right_buttons);
476 return widget;
480 static void
481 xaw_generic_callback (widget, closure, call_data)
482 Widget widget;
483 XtPointer closure;
484 XtPointer call_data;
486 widget_instance *instance = (widget_instance *) closure;
487 Widget instance_widget;
488 LWLIB_ID id;
489 XtPointer user_data;
491 lw_internal_update_other_instances (widget, closure, call_data);
493 if (! instance)
494 return;
495 if (widget->core.being_destroyed)
496 return;
498 instance_widget = instance->widget;
499 if (!instance_widget)
500 return;
502 id = instance->info->id;
504 #if 0
505 user_data = NULL;
506 XtVaGetValues (widget, XtNuserData, &user_data, NULL);
507 #else
508 /* Damn! Athena doesn't give us a way to hang our own data on the
509 buttons, so we have to go find it... I guess this assumes that
510 all instances of a button have the same call data. */
512 widget_value *val = instance->info->val->contents;
513 char *name = XtName (widget);
514 while (val)
516 if (val->name && !strcmp (val->name, name))
517 break;
518 val = val->next;
520 if (! val) abort ();
521 user_data = val->call_data;
523 #endif
525 if (instance->info->selection_cb)
526 instance->info->selection_cb (widget, id, user_data);
529 static void
530 wm_delete_window (w, closure, call_data)
531 Widget w;
532 XtPointer closure;
533 XtPointer call_data;
535 LWLIB_ID id;
536 Cardinal nkids;
537 int i;
538 Widget *kids = 0;
539 Widget widget, shell;
541 if (XtIsSubclass (w, dialogWidgetClass))
542 shell = XtParent (w);
543 else
544 shell = w;
546 if (! XtIsSubclass (shell, shellWidgetClass))
547 abort ();
548 XtVaGetValues (shell, XtNnumChildren, &nkids, NULL);
549 XtVaGetValues (shell, XtNchildren, &kids, NULL);
550 if (!kids || !*kids)
551 abort ();
552 for (i = 0; i < nkids; i++)
554 widget = kids[i];
555 if (XtIsSubclass (widget, dialogWidgetClass))
556 break;
558 id = lw_get_widget_id (widget);
559 if (! id) abort ();
562 widget_info *info = lw_get_widget_info (id);
563 if (! info) abort ();
564 if (info->selection_cb)
565 info->selection_cb (widget, id, (XtPointer) -1);
568 lw_destroy_all_widgets (id);
572 /* Scrollbars */
574 #if 0
575 static void
576 xaw_scrollbar_scroll (widget, closure, call_data)
577 Widget widget;
578 XtPointer closure;
579 XtPointer call_data;
581 widget_instance *instance = (widget_instance *) closure;
582 LWLIB_ID id;
583 scroll_event event_data;
585 if (!instance || widget->core.being_destroyed)
586 return;
588 id = instance->info->id;
589 event_data.slider_value = 0;
590 event_data.time = 0;
592 if ((int) call_data > 0)
593 event_data.action = SCROLLBAR_PAGE_DOWN;
594 else
595 event_data.action = SCROLLBAR_PAGE_UP;
597 if (instance->info->pre_activate_cb)
598 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
600 #endif
602 #if 0
603 static void
604 xaw_scrollbar_jump (widget, closure, call_data)
605 Widget widget;
606 XtPointer closure;
607 XtPointer call_data;
609 widget_instance *instance = (widget_instance *) closure;
610 LWLIB_ID id;
611 scroll_event event_data;
612 scrollbar_values *val =
613 (scrollbar_values *) instance->info->val->scrollbar_data;
614 float percent;
616 if (!instance || widget->core.being_destroyed)
617 return;
619 id = instance->info->id;
621 percent = * (float *) call_data;
622 event_data.slider_value =
623 (int) (percent * (float) (val->maximum - val->minimum)) + val->minimum;
625 event_data.time = 0;
626 event_data.action = SCROLLBAR_DRAG;
628 if (instance->info->pre_activate_cb)
629 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
631 #endif
633 static Widget
634 xaw_create_scrollbar (instance)
635 widget_instance *instance;
637 #if 0
638 Arg av[20];
639 int ac = 0;
640 Dimension width;
641 Widget scrollbar;
643 XtVaGetValues (instance->parent, XtNwidth, &width, NULL);
645 XtSetArg (av[ac], XtNshowGrip, 0); ac++;
646 XtSetArg (av[ac], XtNresizeToPreferred, 1); ac++;
647 XtSetArg (av[ac], XtNallowResize, True); ac++;
648 XtSetArg (av[ac], XtNskipAdjust, True); ac++;
649 XtSetArg (av[ac], XtNwidth, width); ac++;
650 XtSetArg (av[ac], XtNmappedWhenManaged, True); ac++;
652 scrollbar =
653 XtCreateWidget (instance->info->name, scrollbarWidgetClass,
654 instance->parent, av, ac);
656 /* We have to force the border width to be 0 otherwise the
657 geometry manager likes to start looping for awhile... */
658 XtVaSetValues (scrollbar, XtNborderWidth, 0, NULL);
660 XtRemoveAllCallbacks (scrollbar, "jumpProc");
661 XtRemoveAllCallbacks (scrollbar, "scrollProc");
663 XtAddCallback (scrollbar, "jumpProc", xaw_scrollbar_jump,
664 (XtPointer) instance);
665 XtAddCallback (scrollbar, "scrollProc", xaw_scrollbar_scroll,
666 (XtPointer) instance);
668 return scrollbar;
669 #else
670 return NULL;
671 #endif
674 static Widget
675 xaw_create_main (instance)
676 widget_instance *instance;
678 Arg al[1];
679 int ac;
681 /* Create a vertical Paned to hold menubar */
682 ac = 0;
683 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
684 return XtCreateWidget (instance->info->name, panedWidgetClass,
685 instance->parent, al, ac);
688 widget_creation_entry
689 xaw_creation_table [] =
691 {"scrollbar", xaw_create_scrollbar},
692 {"main", xaw_create_main},
693 {NULL, NULL}
696 /* arch-tag: fbbd3589-ae1c-41a0-9142-f628cfee6564
697 (do not change this comment) */