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