Sync up with XEmacs 21.4.17.
[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     (scrollbar_values *) instance->info->val->scrollbar_data;
168   double percent;
169
170   if (!instance || widget->core.being_destroyed)
171     return;
172
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 static void
335 xlw_tab_control_callback (Widget w, XtPointer client_data, XtPointer call_data)
336 {
337   /* call data is the topmost widget */
338   widget_instance* instance = (widget_instance*)client_data;
339   Widget top = (Widget)call_data;
340   char *name = XtName (top);
341   widget_value* widget_val;
342   XtPointer widget_arg;
343   LWLIB_ID id;
344   lw_callback post_activate_cb;
345
346   if (w->core.being_destroyed)
347     return;
348
349   /* Grab these values before running any functions, in case running
350      the selection_cb causes the widget to be destroyed. */
351   id = instance->info->id;
352   post_activate_cb = instance->info->post_activate_cb;
353
354   /* search for the widget_val for the selected tab */
355   for (widget_val = instance->info->val->contents; widget_val; 
356        widget_val = widget_val->next)
357     {
358       if (!strcmp (widget_val->name, name))
359         break;
360     }
361
362   widget_arg = widget_val ? widget_val->call_data : NULL;
363
364   if (instance->info->selection_cb &&
365       widget_val &&
366       widget_val->enabled &&
367       !widget_val->contents)
368     instance->info->selection_cb (w, id, widget_arg);
369
370   if (post_activate_cb)
371     post_activate_cb (w, id, widget_arg);
372 }
373
374 static Widget
375 xlw_create_tab_control (widget_instance *instance)
376 {
377   Arg al[20];
378   int ac = 0;
379   Widget tab = 0;
380   widget_value* val = instance->info->val;
381
382   XtSetArg (al [ac], XtNsensitive, val->enabled);               ac++;
383   XtSetArg (al [ac], XtNmappedWhenManaged, FALSE);      ac++;
384   XtSetArg (al [ac], XtNorientation, XtorientHorizontal);       ac++;
385   XtSetArg (al [ac], XtNresizable, False);                      ac++;
386
387   /* add any args the user supplied for creation time */
388   lw_add_value_args_to_args (val, al, &ac);
389
390   tab = XtCreateManagedWidget (val->name, tabsWidgetClass,
391                                instance->parent, al, ac);
392   XtRemoveAllCallbacks (tab, XtNcallback);
393   XtAddCallback (tab, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
394
395   XtManageChild (tab);
396
397   return tab;
398 }
399
400 static void build_tabs_in_widget (widget_instance* instance, Widget widget, 
401                                   widget_value* val)
402 {
403   widget_value* cur = val;
404   for (cur = val; cur; cur = cur->next)
405     {
406       if (cur->value)
407         {
408 #ifdef LWLIB_WIDGETS_MOTIF
409           xm_create_label (widget, cur);
410 #else
411           xaw_create_label (widget, cur);
412 #endif
413         }
414       cur->change = NO_CHANGE;
415     }
416 }
417
418 static void
419 xlw_update_tab_control (widget_instance* instance, Widget widget, widget_value* val)
420 {
421   Widget* children;
422   unsigned int num_children;
423   int i;
424   widget_value *cur = 0;
425
426   XtRemoveAllCallbacks (widget, XtNcallback);
427   XtAddCallback (widget, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
428
429   if (val->change == STRUCTURAL_CHANGE
430       ||
431       (val->contents && val->contents->change == STRUCTURAL_CHANGE))
432     {
433       destroy_all_children (widget);
434       build_tabs_in_widget (instance, widget, val->contents);
435     }
436
437   children = XtCompositeChildren (widget, &num_children);
438   if (children)
439     {
440       for (i = 0, cur = val->contents; i < num_children; i++)
441         {
442           if (!cur)
443             abort ();
444           if (children [i]->core.being_destroyed
445               || strcmp (XtName (children [i]), cur->name))
446             continue;
447 #ifdef NEED_MOTIF
448           if (lw_motif_widget_p (children [i]))
449             xm_update_one_widget (instance, children [i], cur, False);
450 #endif
451 #ifdef NEED_ATHENA
452           if (lw_xaw_widget_p (children [i]))
453             xaw_update_one_widget (instance, children [i], cur, False);
454 #endif
455           cur = cur->next;
456         }
457       XtFree ((char *) children);
458     }
459   if (cur)
460     abort ();
461 }
462 #endif /* LWLIB_TABS_LUCID */
463
464 #ifdef HAVE_WIDGETS
465 static Widget
466 xlw_create_clip_window (widget_instance *instance)
467 {
468   Arg al[20];
469   int ac = 0;
470   Widget clip = 0;
471   widget_value* val = instance->info->val;
472
473   XtSetArg (al [ac], XtNmappedWhenManaged, FALSE);      ac++;
474   XtSetArg (al [ac], XtNsensitive, TRUE);               ac++;
475   /* add any args the user supplied for creation time */
476   lw_add_value_args_to_args (val, al, &ac);
477
478   /* Create a clip window to contain the subwidget. Incredibly the
479      XEmacs manager seems to be the most appropriate widget for
480      this. Nothing else is simple enough and yet does what is
481      required. */
482   clip = XtCreateManagedWidget (val->name,
483                                 emacsManagerWidgetClass,
484                                 instance->parent, al, ac);
485
486   return clip;
487 }
488 #endif
489
490 const widget_creation_entry 
491 xlw_creation_table [] =
492 {
493 #ifdef LWLIB_MENUBARS_LUCID
494   {"menubar", xlw_create_menubar},
495   {"popup", xlw_create_popup_menu},
496 #endif
497 #ifdef LWLIB_SCROLLBARS_LUCID
498   {"vertical-scrollbar",        xlw_create_vertical_scrollbar},
499   {"horizontal-scrollbar",      xlw_create_horizontal_scrollbar},
500 #endif
501 #ifdef LWLIB_TABS_LUCID
502   {"tab-control",       xlw_create_tab_control},
503 #endif
504 #ifdef HAVE_WIDGETS
505   {"clip-window", xlw_create_clip_window},
506 #endif
507   {NULL, NULL}
508 };
509
510 Boolean
511 lw_lucid_widget_p (Widget widget)
512 {
513   WidgetClass the_class = XtClass (widget);
514 #ifdef LWLIB_MENUBARS_LUCID
515   if (the_class == xlwMenuWidgetClass)
516     return True;
517 #endif
518 #ifdef LWLIB_SCROLLBARS_LUCID
519   if (the_class == xlwScrollBarWidgetClass)
520     return True;
521 #endif
522 #ifdef LWLIB_TABS_LUCID
523   if (the_class == tabsWidgetClass)
524     return True;
525 #endif
526 #ifdef LWLIB_MENUBARS_LUCID
527   if (the_class == overrideShellWidgetClass)
528     return
529       XtClass (((CompositeWidget)widget)->composite.children [0])
530         == xlwMenuWidgetClass;
531 #endif
532 #ifdef HAVE_WIDGETS
533   if (the_class == emacsManagerWidgetClass)
534     return True;
535 #endif
536   return False;
537 }
538
539 void
540 xlw_update_one_widget (widget_instance* instance, Widget widget,
541                        widget_value* val, Boolean deep_p)
542 {
543   WidgetClass class = XtClass (widget);
544
545   if (0)
546     ;
547 #ifdef LWLIB_MENUBARS_LUCID
548   else if (class == xlwMenuWidgetClass)
549     {
550       XlwMenuWidget mw;
551       Arg al [1];
552       if (XtIsShell (widget))
553         mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
554       else
555         mw = (XlwMenuWidget)widget;
556       XtSetArg (al [0], XtNmenu, val);
557       XtSetValues (widget, al, 1); /* #### mw unused! */
558     }
559 #endif
560 #ifdef LWLIB_SCROLLBARS_LUCID
561   else if (class == xlwScrollBarWidgetClass)
562     {
563       xlw_update_scrollbar (instance, widget, val);
564     }
565 #endif
566 #ifdef LWLIB_TABS_LUCID
567   else if (class == tabsWidgetClass)
568     {
569       xlw_update_tab_control (instance, widget, val);
570     }
571 #endif
572   /* Lastly update our global arg values. */
573   if (val->args && val->args->nargs)
574     XtSetValues (widget, val->args->args, val->args->nargs);
575 }
576
577 void
578 xlw_update_one_value (widget_instance* instance, Widget widget,
579                       widget_value* val)
580 {
581   return;
582 }
583
584 void
585 xlw_pop_instance (widget_instance* instance, Boolean up)
586 {
587 }
588
589 #ifdef LWLIB_MENUBARS_LUCID
590 void
591 xlw_popup_menu (Widget widget, XEvent *event)
592 {
593   XlwMenuWidget mw;
594
595   if (!XtIsShell (widget))
596     return;
597
598   if (event->type == ButtonPress || event->type == ButtonRelease)
599     {
600       mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
601       xlw_pop_up_menu (mw, (XButtonPressedEvent *)event);
602     }
603   else
604     abort ();
605 }
606 #endif /* LWLIB_MENUBARS_LUCID */
607
608 \f/* Destruction of instances */
609 void
610 xlw_destroy_instance (widget_instance* instance)
611 {
612   if (instance->widget)
613     XtDestroyWidget (instance->widget);
614 }