update.
[chise/xemacs-chise.git.1] / lwlib / lwlib-Xlw.c
1 /* The lwlib interface to "xlwmenu" menus.
2    Copyright (C) 1992, 1994 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or 
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include <config.h>
22 #include <stdlib.h> /* for abort () */
23 #include <stdio.h> /* for abort () */
24 #include <limits.h>
25
26 #include "lwlib-Xlw.h"
27 #include "lwlib-utils.h"
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CompositeP.h>
32 #include <X11/Shell.h>
33 #ifdef HAVE_WIDGETS
34 #include "../src/EmacsManager.h"
35 #endif
36 #ifdef LWLIB_MENUBARS_LUCID
37 #include "xlwmenu.h"
38 #endif
39 #ifdef LWLIB_SCROLLBARS_LUCID
40 #include "xlwscrollbar.h"
41 #endif
42 #ifdef LWLIB_TABS_LUCID
43 #ifdef NEED_MOTIF
44 #include "lwlib-Xm.h"
45 #endif
46 #ifdef NEED_ATHENA
47 #include "lwlib-Xaw.h"
48 #endif
49 #include "../src/xmu.h"
50 #include "xlwtabs.h"
51 #endif
52 \f
53
54 #include <X11/Intrinsic.h>
55 #include <X11/StringDefs.h>
56 #include <X11/Shell.h>
57 #include <X11/Xaw/Form.h>
58 #include <X11/Xaw/Command.h>
59
60
61 #ifdef LWLIB_MENUBARS_LUCID
62
63 /* Menu callbacks */
64
65 static void
66 pre_hook (Widget w, XtPointer client_data, XtPointer call_data)
67 {
68   widget_instance* instance = (widget_instance*)client_data;
69   widget_value* val;
70   
71   if (w->core.being_destroyed)
72     return;
73
74   val = lw_get_widget_value_for_widget (instance, w);
75 #if 0
76   /* #### - this code used to (for some random back_asswards reason) pass
77   the expression below in the call_data slot.  For incremental menu
78   construction, this needs to go.  I can't even figure out why it was done
79   this way in the first place...it's just a historical weirdism. --Stig */
80   call_data = (val ? val->call_data : NULL);
81 #endif 
82   if (val && val->call_data)
83     abort();                    /* #### - the call_data for the top_level
84                                    "menubar" widget_value used to be passed
85                                    back to the pre_hook. */
86
87   if (instance->info->pre_activate_cb)
88     instance->info->pre_activate_cb (w, instance->info->id, call_data);
89 }
90
91 static void
92 pick_hook (Widget w, XtPointer client_data, XtPointer call_data)
93 {
94   widget_instance* instance = (widget_instance*)client_data;
95   widget_value* contents_val = (widget_value*)call_data;
96   widget_value* widget_val;
97   XtPointer widget_arg;
98   LWLIB_ID id;
99   lw_callback post_activate_cb;
100
101   if (w->core.being_destroyed)
102     return;
103
104   /* Grab these values before running any functions, in case running
105      the selection_cb causes the widget to be destroyed. */
106   id = instance->info->id;
107   post_activate_cb = instance->info->post_activate_cb;
108
109   widget_val = lw_get_widget_value_for_widget (instance, w);
110   widget_arg = widget_val ? widget_val->call_data : NULL;
111
112   if (instance->info->selection_cb &&
113       contents_val &&
114       contents_val->enabled &&
115       !contents_val->contents)
116     instance->info->selection_cb (w, id, contents_val->call_data);
117
118   if (post_activate_cb)
119     post_activate_cb (w, id, widget_arg);
120 }
121
122 \f
123
124 /* creation functions */
125 static Widget
126 xlw_create_menubar (widget_instance* instance)
127 {
128   Arg al [1];
129   Widget widget;
130   
131   XtSetArg (al [0], XtNmenu, instance->info->val);
132   widget = XtCreateWidget (instance->info->name, xlwMenuWidgetClass,
133                            instance->parent, al, 1);
134   XtAddCallback (widget, XtNopen,   pre_hook,  (XtPointer)instance);
135   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
136   return widget;
137 }
138
139 static Widget
140 xlw_create_popup_menu (widget_instance* instance)
141 {
142   Arg al [2];
143   Widget popup_shell, widget;
144   
145   popup_shell = XtCreatePopupShell (instance->info->name,
146                                     overrideShellWidgetClass,
147                                     instance->parent, NULL, 0);
148   XtSetArg (al [0], XtNmenu, instance->info->val);
149   XtSetArg (al [1], XtNhorizontal, False);
150   widget = XtCreateManagedWidget ("popup", xlwMenuWidgetClass,
151                          popup_shell, al, 2);
152   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);  
153   return popup_shell;
154 }
155 #endif /* LWLIB_MENUBARS_LUCID */
156
157 #ifdef LWLIB_SCROLLBARS_LUCID
158 static void
159 xlw_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data)
160 {
161   widget_instance *instance = (widget_instance *) closure;
162   LWLIB_ID id;
163   XlwScrollBarCallbackStruct *data =
164     (XlwScrollBarCallbackStruct *) call_data;
165   scroll_event event_data;
166   scrollbar_values *val;
167   double percent;
168
169   if (!instance || widget->core.being_destroyed)
170     return;
171
172   val = (scrollbar_values *) instance->info->val->scrollbar_data;
173   id = instance->info->id;
174
175   percent = (double) (data->value - 1) / (double) (INT_MAX - 1);
176   event_data.slider_value =
177     (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum;
178
179   if (event_data.slider_value > val->maximum - val->slider_size)
180       event_data.slider_value = val->maximum - val->slider_size;
181   else if (event_data.slider_value < val->minimum)
182            event_data.slider_value = val->minimum;
183
184   if (data->event)
185     {
186       switch (data->event->type)
187         {
188         case KeyPress:
189         case KeyRelease:
190           event_data.time = data->event->xkey.time;
191           break;
192         case ButtonPress:
193         case ButtonRelease:
194           event_data.time = data->event->xbutton.time;
195           break;
196         case MotionNotify:
197           event_data.time = data->event->xmotion.time;
198           break;
199         case EnterNotify:
200         case LeaveNotify:
201           event_data.time = data->event->xcrossing.time;
202           break;
203         default:
204           event_data.time = 0;
205           break;
206         }
207     }
208   else
209     event_data.time = 0;
210
211   switch (data->reason)
212     {
213     case XmCR_DECREMENT:        event_data.action = SCROLLBAR_LINE_UP;   break;
214     case XmCR_INCREMENT:        event_data.action = SCROLLBAR_LINE_DOWN; break;
215     case XmCR_PAGE_DECREMENT:   event_data.action = SCROLLBAR_PAGE_UP;   break;
216     case XmCR_PAGE_INCREMENT:   event_data.action = SCROLLBAR_PAGE_DOWN; break;
217     case XmCR_TO_TOP:           event_data.action = SCROLLBAR_TOP;       break;
218     case XmCR_TO_BOTTOM:        event_data.action = SCROLLBAR_BOTTOM;    break;
219     case XmCR_DRAG:             event_data.action = SCROLLBAR_DRAG;      break;
220     case XmCR_VALUE_CHANGED:    event_data.action = SCROLLBAR_CHANGE;    break;
221     default:                    event_data.action = SCROLLBAR_CHANGE;    break;
222     }
223
224   if (instance->info->pre_activate_cb)
225     instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
226 }
227
228 #define add_scrollbar_callback(resource) \
229 XtAddCallback (scrollbar, resource, xlw_scrollbar_callback, (XtPointer) instance)
230
231 /* #### Does not yet support horizontal scrollbars. */
232 static Widget
233 xlw_create_scrollbar (widget_instance *instance, int vertical)
234 {
235   Arg al[20];
236   int ac = 0;
237   static XtCallbackRec callbacks[2] =
238   { {xlw_scrollbar_callback, NULL}, {NULL, NULL} };
239
240   callbacks[0].closure  = (XtPointer) instance;
241
242   XtSetArg (al[ac], XmNminimum,       1); ac++;
243   XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++;
244   XtSetArg (al[ac], XmNincrement,     1); ac++;
245   XtSetArg (al[ac], XmNpageIncrement, 1); ac++;
246   XtSetArg (al[ac], XmNorientation, (vertical ? XmVERTICAL : XmHORIZONTAL)); ac++;
247
248   XtSetArg (al[ac], XmNdecrementCallback,       callbacks); ac++;
249   XtSetArg (al[ac], XmNdragCallback,            callbacks); ac++;
250   XtSetArg (al[ac], XmNincrementCallback,       callbacks); ac++;
251   XtSetArg (al[ac], XmNpageDecrementCallback,   callbacks); ac++;
252   XtSetArg (al[ac], XmNpageIncrementCallback,   callbacks); ac++;
253   XtSetArg (al[ac], XmNtoBottomCallback,        callbacks); ac++;
254   XtSetArg (al[ac], XmNtoTopCallback,           callbacks); ac++;
255   XtSetArg (al[ac], XmNvalueChangedCallback,    callbacks); ac++;
256
257   return XtCreateWidget (instance->info->name, xlwScrollBarWidgetClass,
258                          instance->parent, al, ac);
259 }
260
261 static Widget
262 xlw_create_vertical_scrollbar (widget_instance *instance)
263 {
264   return xlw_create_scrollbar (instance, 1);
265 }
266
267 static Widget
268 xlw_create_horizontal_scrollbar (widget_instance *instance)
269 {
270   return xlw_create_scrollbar (instance, 0);
271 }
272
273 static void
274 xlw_update_scrollbar (widget_instance *instance, Widget widget,
275                       widget_value *val)
276 {
277   if (val->scrollbar_data)
278     {
279       scrollbar_values *data = val->scrollbar_data;
280       int widget_sliderSize, widget_val;
281       int new_sliderSize, new_value;
282       double percent;
283       Arg al [4];
284
285       /* First size and position the scrollbar widget. */
286       XtSetArg (al [0], XtNx,      data->scrollbar_x);
287       XtSetArg (al [1], XtNy,      data->scrollbar_y);
288       XtSetArg (al [2], XtNwidth,  data->scrollbar_width);
289       XtSetArg (al [3], XtNheight, data->scrollbar_height);
290       XtSetValues (widget, al, 4);
291
292       /* Now size the scrollbar's slider. */
293       XtSetArg (al [0], XmNsliderSize, &widget_sliderSize);
294       XtSetArg (al [1], XmNvalue,      &widget_val);
295       XtGetValues (widget, al, 2);
296
297       percent = (double) data->slider_size /
298         (double) (data->maximum - data->minimum);
299       percent = (percent > 1.0 ? 1.0 : percent);
300       new_sliderSize = (int) ((double) (INT_MAX - 1) * percent);
301
302       percent = (double) (data->slider_position - data->minimum) /
303         (double) (data->maximum - data->minimum);
304       percent = (percent > 1.0 ? 1.0 : percent);
305       new_value = (int) ((double) (INT_MAX - 1) * percent);
306
307       if (new_sliderSize > INT_MAX - 1)
308         new_sliderSize = INT_MAX - 1;
309       else if (new_sliderSize < 1)
310         new_sliderSize = 1;
311
312       if (new_value > (INT_MAX - new_sliderSize))
313         new_value = INT_MAX - new_sliderSize;
314       else if (new_value < 1)
315         new_value = 1;
316
317       if (new_sliderSize != widget_sliderSize || new_value != widget_val)
318         XlwScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1, False);
319     }
320 }
321
322 #endif /* LWLIB_SCROLLBARS_LUCID */
323
324 #ifdef LWLIB_TABS_LUCID
325 /* tab control
326    
327    [[ lwlib is such an incredible hairy crock. I just cannot believe
328    it! There are random dependencies between functions, there is a
329    total lack of genericity, even though it initially appears to be
330    generic. It should all be junked and begun again. Building tabs are
331    an example - in theory we should be able to reuse a lot of the
332    general stuff because we want to put labels of whatever toolkit we
333    are using in the tab. Instead we have to hack it by hand. ]]
334    While lwlib is a hairy crock, whoever wrote that seems to misunderstand
335    Falk's tab control widget.  The tab control widget has *two* kinds of
336    children: *widgets*, which all occupy a *single* pane below the row of
337    tabs---this is where the labels created in build_tabs_in_widget go, and
338    *gadgets*, the tabs themselves, which do *not* draw themselves, but
339    rather are drawn by the control.  In fact, in XEmacs the true widget
340    children are *never* visible!  So this case is not a problem in the
341    design of lwlib, but rather of Falk's widget. -- sjt */
342 static void
343 xlw_tab_control_callback (Widget w, XtPointer client_data, XtPointer call_data)
344 {
345   /* call data is the topmost widget */
346   widget_instance* instance = (widget_instance*)client_data;
347   Widget top = (Widget)call_data;
348   char *name = XtName (top);
349   widget_value* widget_val;
350   XtPointer widget_arg;
351   LWLIB_ID id;
352   lw_callback post_activate_cb;
353
354   if (w->core.being_destroyed)
355     return;
356
357   /* Grab these values before running any functions, in case running
358      the selection_cb causes the widget to be destroyed. */
359   id = instance->info->id;
360   post_activate_cb = instance->info->post_activate_cb;
361
362   /* search for the widget_val for the selected tab */
363   for (widget_val = instance->info->val->contents; widget_val; 
364        widget_val = widget_val->next)
365     {
366       if (!strcmp (widget_val->name, name))
367         break;
368     }
369
370   widget_arg = widget_val ? widget_val->call_data : NULL;
371
372   if (instance->info->selection_cb &&
373       widget_val &&
374       widget_val->enabled &&
375       !widget_val->contents)
376     instance->info->selection_cb (w, id, widget_arg);
377
378   if (post_activate_cb)
379     post_activate_cb (w, id, widget_arg);
380 }
381
382 static Widget
383 xlw_create_tab_control (widget_instance *instance)
384 {
385   Arg al[20];
386   int ac = 0;
387   Widget tab = 0;
388   widget_value* val = instance->info->val;
389
390   XtSetArg (al [ac], XtNsensitive, val->enabled);               ac++;
391   XtSetArg (al [ac], XtNmappedWhenManaged, False);              ac++;
392   XtSetArg (al [ac], XtNorientation, XtorientHorizontal);       ac++;
393
394   /* add any args the user supplied for creation time */
395   lw_add_value_args_to_args (val, al, &ac);
396
397   tab = XtCreateManagedWidget (val->name, tabsWidgetClass,
398                                instance->parent, al, ac);
399   XtRemoveAllCallbacks (tab, XtNcallback);
400   XtAddCallback (tab, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
401
402   XtManageChild (tab);
403
404   return tab;
405 }
406
407 static void build_tabs_in_widget (widget_instance* instance, Widget widget, 
408                                   widget_value* val)
409 {
410   widget_value* cur = val;
411   Arg al[1];
412
413   /* Children are always invisible, don't permit resizing. */
414   XtSetArg (al[0], XtNresizable, False);
415
416   for (cur = val; cur; cur = cur->next)
417     {
418       if (cur->value)
419         {
420           Widget w;
421 #ifdef LWLIB_WIDGETS_MOTIF
422           w = xm_create_label (widget, cur);
423 #else
424           w = xaw_create_label (widget, cur);
425 #endif
426           XtSetValues (w, al, 1);
427         }
428       cur->change = NO_CHANGE;
429     }
430 }
431
432 static void
433 xlw_update_tab_control (widget_instance* instance, Widget widget, widget_value* val)
434 {
435   Widget* children;
436   unsigned int num_children;
437   int i;
438   widget_value *cur = 0;
439
440   XtRemoveAllCallbacks (widget, XtNcallback);
441   XtAddCallback (widget, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
442
443   if (val->change == STRUCTURAL_CHANGE
444       ||
445       (val->contents && val->contents->change == STRUCTURAL_CHANGE))
446     {
447       destroy_all_children (widget);
448       build_tabs_in_widget (instance, widget, val->contents);
449     }
450
451   children = XtCompositeChildren (widget, &num_children);
452   if (children)
453     {
454       for (i = 0, cur = val->contents; i < num_children; i++)
455         {
456           if (!cur)
457             abort ();
458           if (children [i]->core.being_destroyed
459               || strcmp (XtName (children [i]), cur->name))
460             continue;
461 #ifdef NEED_MOTIF
462           if (lw_motif_widget_p (children [i]))
463             xm_update_one_widget (instance, children [i], cur, False);
464 #endif
465 #ifdef NEED_ATHENA
466           if (lw_xaw_widget_p (children [i]))
467             xaw_update_one_widget (instance, children [i], cur, False);
468 #endif
469           cur = cur->next;
470         }
471       XtFree ((char *) children);
472     }
473   if (cur)
474     abort ();
475 }
476 #endif /* LWLIB_TABS_LUCID */
477
478 #ifdef HAVE_WIDGETS
479 static Widget
480 xlw_create_clip_window (widget_instance *instance)
481 {
482   Arg al[20];
483   int ac = 0;
484   Widget clip = 0;
485   widget_value* val = instance->info->val;
486
487   XtSetArg (al [ac], XtNmappedWhenManaged, FALSE);      ac++;
488   XtSetArg (al [ac], XtNsensitive, TRUE);               ac++;
489   /* add any args the user supplied for creation time */
490   lw_add_value_args_to_args (val, al, &ac);
491
492   /* Create a clip window to contain the subwidget. Incredibly the
493      XEmacs manager seems to be the most appropriate widget for
494      this. Nothing else is simple enough and yet does what is
495      required. */
496   clip = XtCreateManagedWidget (val->name,
497                                 emacsManagerWidgetClass,
498                                 instance->parent, al, ac);
499
500   return clip;
501 }
502 #endif
503
504 const widget_creation_entry 
505 xlw_creation_table [] =
506 {
507 #ifdef LWLIB_MENUBARS_LUCID
508   {"menubar", xlw_create_menubar},
509   {"popup", xlw_create_popup_menu},
510 #endif
511 #ifdef LWLIB_SCROLLBARS_LUCID
512   {"vertical-scrollbar",        xlw_create_vertical_scrollbar},
513   {"horizontal-scrollbar",      xlw_create_horizontal_scrollbar},
514 #endif
515 #ifdef LWLIB_TABS_LUCID
516   {"tab-control",       xlw_create_tab_control},
517 #endif
518 #ifdef HAVE_WIDGETS
519   {"clip-window", xlw_create_clip_window},
520 #endif
521   {NULL, NULL}
522 };
523
524 Boolean
525 lw_lucid_widget_p (Widget widget)
526 {
527   WidgetClass the_class = XtClass (widget);
528 #ifdef LWLIB_MENUBARS_LUCID
529   if (the_class == xlwMenuWidgetClass)
530     return True;
531 #endif
532 #ifdef LWLIB_SCROLLBARS_LUCID
533   if (the_class == xlwScrollBarWidgetClass)
534     return True;
535 #endif
536 #ifdef LWLIB_TABS_LUCID
537   if (the_class == tabsWidgetClass)
538     return True;
539 #endif
540 #ifdef LWLIB_MENUBARS_LUCID
541   if (the_class == overrideShellWidgetClass)
542     return
543       XtClass (((CompositeWidget)widget)->composite.children [0])
544         == xlwMenuWidgetClass;
545 #endif
546 #ifdef HAVE_WIDGETS
547   if (the_class == emacsManagerWidgetClass)
548     return True;
549 #endif
550   return False;
551 }
552
553 void
554 xlw_update_one_widget (widget_instance* instance, Widget widget,
555                        widget_value* val, Boolean deep_p)
556 {
557   WidgetClass class = XtClass (widget);
558
559   if (0)
560     ;
561 #ifdef LWLIB_MENUBARS_LUCID
562   else if (class == xlwMenuWidgetClass)
563     {
564       XlwMenuWidget mw;
565       Arg al [1];
566       if (XtIsShell (widget))
567         mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
568       else
569         mw = (XlwMenuWidget)widget;
570       XtSetArg (al [0], XtNmenu, val);
571       XtSetValues (widget, al, 1); /* #### mw unused! */
572     }
573 #endif
574 #ifdef LWLIB_SCROLLBARS_LUCID
575   else if (class == xlwScrollBarWidgetClass)
576     {
577       xlw_update_scrollbar (instance, widget, val);
578     }
579 #endif
580 #ifdef LWLIB_TABS_LUCID
581   else if (class == tabsWidgetClass)
582     {
583       xlw_update_tab_control (instance, widget, val);
584     }
585 #endif
586   /* Lastly update our global arg values. */
587   if (val->args && val->args->nargs)
588     XtSetValues (widget, val->args->args, val->args->nargs);
589 }
590
591 void
592 xlw_update_one_value (widget_instance* instance, Widget widget,
593                       widget_value* val)
594 {
595   return;
596 }
597
598 void
599 xlw_pop_instance (widget_instance* instance, Boolean up)
600 {
601 }
602
603 #ifdef LWLIB_MENUBARS_LUCID
604 void
605 xlw_popup_menu (Widget widget, XEvent *event)
606 {
607   XlwMenuWidget mw;
608
609   if (!XtIsShell (widget))
610     return;
611
612   if (event->type == ButtonPress || event->type == ButtonRelease)
613     {
614       mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
615       xlw_pop_up_menu (mw, (XButtonPressedEvent *)event);
616     }
617   else
618     abort ();
619 }
620 #endif /* LWLIB_MENUBARS_LUCID */
621
622 \f/* Destruction of instances */
623 void
624 xlw_destroy_instance (widget_instance* instance)
625 {
626   if (instance->widget)
627     XtDestroyWidget (instance->widget);
628 }