XEmacs 21.2-b1
[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 <limits.h>
24
25 #include "lwlib-Xlw.h"
26 #include <X11/StringDefs.h>
27 #include <X11/IntrinsicP.h>
28 #include <X11/ObjectP.h>
29 #include <X11/CompositeP.h>
30 #include <X11/Shell.h>
31 #ifdef LWLIB_MENUBARS_LUCID
32 #include "xlwmenu.h"
33 #endif
34 #ifdef LWLIB_SCROLLBARS_LUCID
35 #include "xlwscrollbar.h"
36 #endif
37
38 \f
39
40 #ifdef LWLIB_MENUBARS_LUCID
41
42 /* Menu callbacks */
43
44 static void
45 pre_hook (Widget w, XtPointer client_data, XtPointer call_data)
46 {
47   widget_instance* instance = (widget_instance*)client_data;
48   widget_value* val;
49   
50   if (w->core.being_destroyed)
51     return;
52
53   val = lw_get_widget_value_for_widget (instance, w);
54 #if 0
55   /* #### - this code used to (for some random back_asswards reason) pass
56   the expression below in the call_data slot.  For incremental menu
57   construction, this needs to go.  I can't even figure out why it was done
58   this way in the first place...it's just a historical weirdism. --Stig */
59   call_data = (val ? val->call_data : NULL);
60 #endif 
61   if (val && val->call_data)
62     abort();                    /* #### - the call_data for the top_level
63                                    "menubar" widget_value used to be passed
64                                    back to the pre_hook. */
65
66   if (instance->info->pre_activate_cb)
67     instance->info->pre_activate_cb (w, instance->info->id, call_data);
68 }
69
70 static void
71 pick_hook (Widget w, XtPointer client_data, XtPointer call_data)
72 {
73   widget_instance* instance = (widget_instance*)client_data;
74   widget_value* contents_val = (widget_value*)call_data;
75   widget_value* widget_val;
76   XtPointer widget_arg;
77   LWLIB_ID id;
78   lw_callback post_activate_cb;
79
80   if (w->core.being_destroyed)
81     return;
82
83   /* Grab these values before running any functions, in case running
84      the selection_cb causes the widget to be destroyed. */
85   id = instance->info->id;
86   post_activate_cb = instance->info->post_activate_cb;
87
88   widget_val = lw_get_widget_value_for_widget (instance, w);
89   widget_arg = widget_val ? widget_val->call_data : NULL;
90
91   if (instance->info->selection_cb &&
92       contents_val &&
93       contents_val->enabled &&
94       !contents_val->contents)
95     instance->info->selection_cb (w, id, contents_val->call_data);
96
97   if (post_activate_cb)
98     post_activate_cb (w, id, widget_arg);
99 }
100
101 \f
102
103 /* creation functions */
104 static Widget
105 xlw_create_menubar (widget_instance* instance)
106 {
107   Arg al [1];
108   Widget widget;
109   
110   XtSetArg (al [0], XtNmenu, instance->info->val);
111   widget = XtCreateWidget (instance->info->name, xlwMenuWidgetClass,
112                            instance->parent, al, 1);
113   XtAddCallback (widget, XtNopen,   pre_hook,  (XtPointer)instance);
114   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
115   return widget;
116 }
117
118 static Widget
119 xlw_create_popup_menu (widget_instance* instance)
120 {
121   Arg al [2];
122   Widget popup_shell, widget;
123   
124   popup_shell = XtCreatePopupShell (instance->info->name,
125                                     overrideShellWidgetClass,
126                                     instance->parent, NULL, 0);
127   XtSetArg (al [0], XtNmenu, instance->info->val);
128   XtSetArg (al [1], XtNhorizontal, False);
129   widget = XtCreateManagedWidget ("popup", xlwMenuWidgetClass,
130                                   popup_shell, al, 2);
131   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
132
133   return popup_shell;
134 }
135 #endif /* LWLIB_MENUBARS_LUCID */
136
137 #ifdef LWLIB_SCROLLBARS_LUCID
138 static void
139 xlw_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data)
140 {
141   widget_instance *instance = (widget_instance *) closure;
142   LWLIB_ID id;
143   XlwScrollBarCallbackStruct *data =
144     (XlwScrollBarCallbackStruct *) call_data;
145   scroll_event event_data;
146   scrollbar_values *val =
147     (scrollbar_values *) instance->info->val->scrollbar_data;
148   double percent;
149
150   if (!instance || widget->core.being_destroyed)
151     return;
152
153   id = instance->info->id;
154
155   percent = (double) (data->value - 1) / (double) (INT_MAX - 1);
156   event_data.slider_value =
157     (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum;
158
159   if (event_data.slider_value > val->maximum - val->slider_size)
160       event_data.slider_value = val->maximum - val->slider_size;
161   else if (event_data.slider_value < val->minimum)
162            event_data.slider_value = val->minimum;
163
164   if (data->event)
165     {
166       switch (data->event->type)
167         {
168         case KeyPress:
169         case KeyRelease:
170           event_data.time = data->event->xkey.time;
171           break;
172         case ButtonPress:
173         case ButtonRelease:
174           event_data.time = data->event->xbutton.time;
175           break;
176         case MotionNotify:
177           event_data.time = data->event->xmotion.time;
178           break;
179         case EnterNotify:
180         case LeaveNotify:
181           event_data.time = data->event->xcrossing.time;
182           break;
183         default:
184           event_data.time = 0;
185           break;
186         }
187     }
188   else
189     event_data.time = 0;
190
191   switch (data->reason)
192     {
193     case XmCR_DECREMENT:        event_data.action = SCROLLBAR_LINE_UP;   break;
194     case XmCR_INCREMENT:        event_data.action = SCROLLBAR_LINE_DOWN; break;
195     case XmCR_PAGE_DECREMENT:   event_data.action = SCROLLBAR_PAGE_UP;   break;
196     case XmCR_PAGE_INCREMENT:   event_data.action = SCROLLBAR_PAGE_DOWN; break;
197     case XmCR_TO_TOP:           event_data.action = SCROLLBAR_TOP;       break;
198     case XmCR_TO_BOTTOM:        event_data.action = SCROLLBAR_BOTTOM;    break;
199     case XmCR_DRAG:             event_data.action = SCROLLBAR_DRAG;      break;
200     case XmCR_VALUE_CHANGED:    event_data.action = SCROLLBAR_CHANGE;    break;
201     default:                    event_data.action = SCROLLBAR_CHANGE;    break;
202     }
203
204   if (instance->info->pre_activate_cb)
205     instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
206 }
207
208 #define add_scrollbar_callback(resource) \
209 XtAddCallback (scrollbar, resource, xlw_scrollbar_callback, (XtPointer) instance)
210
211 /* #### Does not yet support horizontal scrollbars. */
212 static Widget
213 xlw_create_scrollbar (widget_instance *instance, int vertical)
214 {
215   Arg al[20];
216   int ac = 0;
217   static XtCallbackRec callbacks[2] =
218   { {xlw_scrollbar_callback, NULL}, {NULL, NULL} };
219
220   callbacks[0].closure  = (XtPointer) instance;
221
222   XtSetArg (al[ac], XmNminimum,       1); ac++;
223   XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++;
224   XtSetArg (al[ac], XmNincrement,     1); ac++;
225   XtSetArg (al[ac], XmNpageIncrement, 1); ac++;
226   XtSetArg (al[ac], XmNorientation, (vertical ? XmVERTICAL : XmHORIZONTAL)); ac++;
227
228   XtSetArg (al[ac], XmNdecrementCallback,       callbacks); ac++;
229   XtSetArg (al[ac], XmNdragCallback,            callbacks); ac++;
230   XtSetArg (al[ac], XmNincrementCallback,       callbacks); ac++;
231   XtSetArg (al[ac], XmNpageDecrementCallback,   callbacks); ac++;
232   XtSetArg (al[ac], XmNpageIncrementCallback,   callbacks); ac++;
233   XtSetArg (al[ac], XmNtoBottomCallback,        callbacks); ac++;
234   XtSetArg (al[ac], XmNtoTopCallback,           callbacks); ac++;
235   XtSetArg (al[ac], XmNvalueChangedCallback,    callbacks); ac++;
236
237   return XtCreateWidget (instance->info->name, xlwScrollBarWidgetClass,
238                          instance->parent, al, ac);
239 }
240
241 static Widget
242 xlw_create_vertical_scrollbar (widget_instance *instance)
243 {
244   return xlw_create_scrollbar (instance, 1);
245 }
246
247 static Widget
248 xlw_create_horizontal_scrollbar (widget_instance *instance)
249 {
250   return xlw_create_scrollbar (instance, 0);
251 }
252
253 static void
254 xlw_update_scrollbar (widget_instance *instance, Widget widget,
255                       widget_value *val)
256 {
257   if (val->scrollbar_data)
258     {
259       scrollbar_values *data = val->scrollbar_data;
260       int widget_sliderSize, widget_val;
261       int new_sliderSize, new_value;
262       double percent;
263       Arg al [4];
264
265       /* First size and position the scrollbar widget. */
266       XtSetArg (al [0], XtNx,      data->scrollbar_x);
267       XtSetArg (al [1], XtNy,      data->scrollbar_y);
268       XtSetArg (al [2], XtNwidth,  data->scrollbar_width);
269       XtSetArg (al [3], XtNheight, data->scrollbar_height);
270       XtSetValues (widget, al, 4);
271
272       /* Now size the scrollbar's slider. */
273       XtSetArg (al [0], XmNsliderSize, &widget_sliderSize);
274       XtSetArg (al [1], XmNvalue,      &widget_val);
275       XtGetValues (widget, al, 2);
276
277       percent = (double) data->slider_size /
278         (double) (data->maximum - data->minimum);
279       percent = (percent > 1.0 ? 1.0 : percent);
280       new_sliderSize = (int) ((double) (INT_MAX - 1) * percent);
281
282       percent = (double) (data->slider_position - data->minimum) /
283         (double) (data->maximum - data->minimum);
284       percent = (percent > 1.0 ? 1.0 : percent);
285       new_value = (int) ((double) (INT_MAX - 1) * percent);
286
287       if (new_sliderSize > INT_MAX - 1)
288         new_sliderSize = INT_MAX - 1;
289       else if (new_sliderSize < 1)
290         new_sliderSize = 1;
291
292       if (new_value > (INT_MAX - new_sliderSize))
293         new_value = INT_MAX - new_sliderSize;
294       else if (new_value < 1)
295         new_value = 1;
296
297       if (new_sliderSize != widget_sliderSize || new_value != widget_val)
298         XlwScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1, False);
299     }
300 }
301
302 #endif /* LWLIB_SCROLLBARS_LUCID */
303
304 widget_creation_entry 
305 xlw_creation_table [] =
306 {
307 #ifdef LWLIB_MENUBARS_LUCID
308   {"menubar", xlw_create_menubar},
309   {"popup", xlw_create_popup_menu},
310 #endif
311 #ifdef LWLIB_SCROLLBARS_LUCID
312   {"vertical-scrollbar",        xlw_create_vertical_scrollbar},
313   {"horizontal-scrollbar",      xlw_create_horizontal_scrollbar},
314 #endif
315   {NULL, NULL}
316 };
317
318 Boolean
319 lw_lucid_widget_p (Widget widget)
320 {
321   WidgetClass the_class = XtClass (widget);
322 #ifdef LWLIB_MENUBARS_LUCID
323   if (the_class == xlwMenuWidgetClass)
324     return True;
325 #endif
326 #ifdef LWLIB_SCROLLBARS_LUCID
327   if (the_class == xlwScrollBarWidgetClass)
328     return True;
329 #endif
330 #ifdef LWLIB_MENUBARS_LUCID
331   if (the_class == overrideShellWidgetClass)
332     return
333       XtClass (((CompositeWidget)widget)->composite.children [0])
334         == xlwMenuWidgetClass;
335 #endif
336   return False;
337 }
338
339 void
340 xlw_update_one_widget (widget_instance* instance, Widget widget,
341                        widget_value* val, Boolean deep_p)
342 {
343   WidgetClass class;
344
345   class = XtClass (widget);
346
347   if (0)
348     ;
349 #ifdef LWLIB_MENUBARS_LUCID
350   else if (class == xlwMenuWidgetClass)
351     {
352       XlwMenuWidget mw;
353       Arg al [1];
354       if (XtIsShell (widget))
355         mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
356       else
357         mw = (XlwMenuWidget)widget;
358       XtSetArg (al [0], XtNmenu, val);
359       XtSetValues (widget, al, 1);
360     }
361 #endif
362 #ifdef LWLIB_SCROLLBARS_LUCID
363   else if (class == xlwScrollBarWidgetClass)
364     {
365       xlw_update_scrollbar (instance, widget, val);
366     }
367 #endif
368 }
369
370 void
371 xlw_update_one_value (widget_instance* instance, Widget widget,
372                       widget_value* val)
373 {
374   return;
375 }
376
377 void
378 xlw_pop_instance (widget_instance* instance, Boolean up)
379 {
380 }
381
382 #ifdef LWLIB_MENUBARS_LUCID
383 void
384 xlw_popup_menu (Widget widget, XEvent *event)
385 {
386   XlwMenuWidget mw;
387
388   if (!XtIsShell (widget))
389     return;
390
391   if (event->type == ButtonPress || event->type == ButtonRelease)
392     {
393       mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
394       xlw_pop_up_menu (mw, (XButtonPressedEvent *)event);
395     }
396   else
397     abort ();
398 }
399 #endif /* LWLIB_MENUBARS_LUCID */
400
401 \f/* Destruction of instances */
402 void
403 xlw_destroy_instance (widget_instance* instance)
404 {
405   if (instance->widget)
406     XtDestroyWidget (instance->widget);
407 }