1 /*
2  *  Copyright (C) 1995, 1996  Karl-Johan Johnsson.
3  */
4 
5 #include <X11/IntrinsicP.h>
6 #include <X11/StringDefs.h>
7 
8 #include "Compat.h"
9 #include "Manager.h"
10 #include "ScrollableP.h"
11 #include "Util.h"
12 
13 static XtResource resources[] = {
14 #define offset(field) XtOffsetOf(ScrollableRec, scrollable.field)
15     {XtNhBar, XtCScrBar, XtRWidget, sizeof(Widget),
16      offset(h_bar), XtRImmediate, (XtPointer)NULL},
17     {XtNvBar, XtCScrBar, XtRWidget, sizeof(Widget),
18      offset(v_bar), XtRImmediate, (XtPointer)NULL},
19 #undef offset
20 };
21 
22 static void	ClassPartInitialize(WidgetClass);
23 static void	Initialize(Widget, Widget, ArgList, Cardinal*);
24 static void	Resize(Widget);
25 static void	Realize(Widget, XtValueMask*, XSetWindowAttributes*);
26 static Boolean	SetValues(Widget, Widget, Widget, ArgList, Cardinal*);
27 static void	SetHPos(ScrollableWidget, long);
28 static void	SetVPos(ScrollableWidget, long);
29 
30 ScrollableClassRec scrollableClassRec = {
31     { /* core_class fields */
32 	(WidgetClass) &shadowClassRec,	/* superclass			*/
33 	"Scrollable",			/* class_name			*/
34 	sizeof(ScrollableRec),		/* widget_size			*/
35 	NULL,				/* class_initialize		*/
36 	ClassPartInitialize,		/* class_part_initialize	*/
37 	FALSE,				/* class_inited			*/
38 	Initialize,			/* initialize			*/
39 	NULL,				/* initialize_hook		*/
40 	Realize,			/* realize			*/
41 	NULL,				/* actions			*/
42 	0,				/* num_actions			*/
43 	resources,			/* resources			*/
44 	XtNumber(resources),		/* num_resources		*/
45 	NULLQUARK,			/* xrm_class			*/
46 	TRUE,				/* compress_motion		*/
47 	TRUE,				/* compress_exposure		*/
48 	TRUE,				/* compress_enterleave		*/
49 	FALSE,				/* visible_interest		*/
50 	NULL,				/* destroy			*/
51 	Resize,				/* resize			*/
52 	NULL,				/* expose			*/
53 	SetValues,			/* set_values			*/
54 	NULL,				/* set_values_hook		*/
55 	XtInheritSetValuesAlmost,	/* set_values_almost		*/
56 	NULL,				/* get_values_hook		*/
57 	NULL,				/* accept_focus			*/
58 	XtVersion,			/* version			*/
59 	NULL,				/* callback_private		*/
60 	NULL,				/* tm_table			*/
61 	XtInheritQueryGeometry,		/* query_geometry		*/
62 	XtInheritDisplayAccelerator,	/* display_accelerator		*/
63 	NULL				/* extension			*/
64     },
65     {					/* shadow fields		*/
66 	XtInheritPixelOffset,		/* pixel_offset */
67 	False,				/* use_arm_for_background	*/
68 	XtInheritAllocShadowColors,	/* alloc_shadow_colors		*/
69 	XtInheritAllocShadowPixmaps,	/* alloc_shadow_pixmaps		*/
70 	XtInheritAllocArmColor,		/* alloc_arm_color		*/
71 	XtInheritAllocArmPixmap,	/* alloc_arm_pixmap		*/
72 	XtInheritAllocGCs,		/* alloc_gcs			*/
73 	NULL,				/* extension			*/
74     },
75     {					/* scrollable fields		*/
76 	SetHPos,			/* set_hpos			*/
77 	SetVPos,			/* set_vpos			*/
78 	NULL,				/* suspend_hook			*/
79 	NULL,				/* extension			*/
80     }
81 };
82 
83 WidgetClass scrollableWidgetClass = (WidgetClass)&scrollableClassRec;
84 
85 /*************************************************************************/
86 
hbar_callback(Widget scr_bar,XtPointer client_data,XtPointer call_data)87 static void hbar_callback(Widget    scr_bar,
88 			  XtPointer client_data,
89 			  XtPointer call_data)
90 {
91     ScrollReport		*rep  = (ScrollReport *)call_data;
92     ScrollableWidget		w     = (ScrollableWidget)client_data;
93     ScrollableWidgetClass	class = (ScrollableWidgetClass)XtClass(w);
94     long			n_pos, n_shown, n_size;
95 
96     if (!w->core.managed)
97 	return;
98 
99     class->scrollable_class.set_hpos(w, rep->pos);
100     n_pos   = w->scrollable.pos_x;
101     n_shown = w->scrollable.shown_x;
102     n_size  = w->scrollable.width;
103     if (rep->pos != n_pos || rep->shown != n_shown || rep->size != n_size)
104 	ScrBarSetLengthsAndPos(scr_bar, n_size, n_shown, n_pos);
105 }
106 
vbar_callback(Widget scr_bar,XtPointer client_data,XtPointer call_data)107 static void vbar_callback(Widget    scr_bar,
108 			  XtPointer client_data,
109 			  XtPointer call_data)
110 {
111     ScrollReport		*rep  = (ScrollReport *)call_data;
112     ScrollableWidget		w     = (ScrollableWidget)client_data;
113     ScrollableWidgetClass	class = (ScrollableWidgetClass)XtClass(w);
114     long			n_pos, n_shown, n_size;
115 
116     if (!w->core.managed)
117 	return;
118 
119     class->scrollable_class.set_vpos(w, rep->pos);
120     n_pos   = w->scrollable.pos_y;
121     n_shown = w->scrollable.shown_y;
122     n_size  = w->scrollable.height;
123     if (rep->pos != n_pos || rep->shown != n_shown || rep->size != n_size)
124 	ScrBarSetLengthsAndPos(scr_bar, n_size, n_shown, n_pos);
125 }
126 
remove_callback(ScrollableWidget w,Widget scr_bar,XtCallbackProc callback)127 static void remove_callback(ScrollableWidget w,
128 			    Widget           scr_bar,
129 			    XtCallbackProc   callback)
130 {
131     if (scr_bar)
132 	XtRemoveCallback(scr_bar, XtNscrollCallback, callback, (XtPointer)w);
133 }
134 
add_callback(ScrollableWidget w,Widget scr_bar,XtCallbackProc callback)135 static void add_callback(ScrollableWidget w,
136 			 Widget           scr_bar,
137 			 XtCallbackProc   callback)
138 {
139     if (scr_bar)
140 	XtAddCallback(scr_bar, XtNscrollCallback, callback, (XtPointer)w);
141 }
142 
call_suspend_hook(ScrollableWidget w)143 static void call_suspend_hook(ScrollableWidget w)
144 {
145     ScrollableWidgetClass	class = (ScrollableWidgetClass)XtClass(w);
146 
147     if (class->scrollable_class.suspend_hook)
148 	class->scrollable_class.suspend_hook(w);
149 }
150 
parent_resize_callback(Widget parent,XtPointer client_data,XtPointer call_data)151 static void parent_resize_callback(Widget	parent,
152 				   XtPointer	client_data,
153 				   XtPointer	call_data)
154 {
155     Widget	w = (Widget)client_data;
156 
157     if (XtIsManaged(w) && w->core.widget_class->core_class.resize)
158 	w->core.widget_class->core_class.resize(w);
159 }
160 
161 /*************************************************************************/
162 
ClassPartInitialize(WidgetClass gclass)163 static void ClassPartInitialize(WidgetClass gclass)
164 {
165     ScrollableWidgetClass	class, super;
166 
167     class = (ScrollableWidgetClass)gclass;
168     super = (ScrollableWidgetClass)class->core_class.superclass;
169 
170     if (class->scrollable_class.set_hpos == XtInheritScrollableSetPos)
171 	class->scrollable_class.set_hpos = super->scrollable_class.set_hpos;
172     if (class->scrollable_class.set_vpos == XtInheritScrollableSetPos)
173 	class->scrollable_class.set_vpos = super->scrollable_class.set_vpos;
174     if (class->scrollable_class.suspend_hook == XtInheritScrollableSuspendHook)
175 	class->scrollable_class.suspend_hook =
176 	    super->scrollable_class.suspend_hook;
177 }
178 
Initialize(Widget grequest,Widget gnew,ArgList args,Cardinal * num_args)179 static void Initialize(Widget grequest, Widget gnew,
180 		       ArgList args, Cardinal *num_args)
181 {
182     ScrollableWidget	new    = (ScrollableWidget)gnew;
183     Widget		parent = XtParent(new);
184 
185     new->scrollable.pos_x   = 0;
186     new->scrollable.shown_x = 0;
187     new->scrollable.width   = 0;
188     new->scrollable.pos_y   = 0;
189     new->scrollable.shown_y = 0;
190     new->scrollable.height  = 0;
191     new->scrollable.suspended = False;
192     add_callback(new, new->scrollable.h_bar, hbar_callback);
193     add_callback(new, new->scrollable.v_bar, vbar_callback);
194     if (XtIsSubclass(parent, managerWidgetClass))
195 	XtAddCallback(parent, XtNresizeCallback,
196 		      parent_resize_callback, (XtPointer)new);
197 }
198 
Resize(Widget gw)199 static void Resize(Widget gw)
200 {
201     ScrollableWidget	w = (ScrollableWidget)gw;
202 
203     ScrollableHFromGeometry(w);
204     ScrollableVFromGeometry(w);
205     ScrollableFitHBar(w);
206     ScrollableFitVBar(w);
207 }
208 
SetHPos(ScrollableWidget w,long x)209 static void SetHPos(ScrollableWidget w, long x)
210 {
211     Arg		arg;
212 
213     XtSetArg(arg, XtNx, - x);
214     XtSetValues((Widget)w, &arg, 1);
215     ScrollableHFromGeometry(w);
216 }
217 
SetVPos(ScrollableWidget w,long y)218 static void SetVPos(ScrollableWidget w, long y)
219 {
220     Arg		arg;
221 
222     XtSetArg(arg, XtNy, - y);
223     XtSetValues((Widget)w, &arg, 1);
224     ScrollableVFromGeometry(w);
225 }
226 
Realize(Widget gw,XtValueMask * mask,XSetWindowAttributes * attributes)227 static void Realize(Widget gw, XtValueMask *mask,
228 		    XSetWindowAttributes *attributes)
229 {
230     ScrollableWidget	w = (ScrollableWidget)gw;
231 
232     ScrollableFitHBar(w);
233     ScrollableFitVBar(w);
234     shadowWidgetClass->core_class.realize((Widget)w, mask, attributes);
235 }
236 
SetValues(Widget gcurrent,Widget grequest,Widget gnew,ArgList args,Cardinal * num_args)237 static Boolean SetValues(Widget gcurrent,
238 			 Widget grequest,
239 			 Widget gnew,
240 			 ArgList args,
241 			 Cardinal *num_args)
242 {
243     ScrollableWidget	new     = (ScrollableWidget)gnew;
244     ScrollableWidget	current = (ScrollableWidget)gcurrent;
245 
246     if (new->scrollable.h_bar != current->scrollable.h_bar) {
247 	remove_callback(new, current->scrollable.h_bar, hbar_callback);
248 	add_callback(new, new->scrollable.h_bar, hbar_callback);
249 	ScrollableFitHBar(new);
250     }
251 
252     if (new->scrollable.v_bar != current->scrollable.v_bar) {
253 	remove_callback(new, current->scrollable.v_bar, vbar_callback);
254 	add_callback(new, new->scrollable.v_bar, vbar_callback);
255 	ScrollableFitVBar(new);
256     }
257 
258     return False;
259 }
260 
261 /*************************************************************************/
262 
ScrollableSetHBar(Widget gw,Widget h_bar)263 void ScrollableSetHBar(Widget gw, Widget h_bar)
264 {
265     ScrollableWidget	w = (ScrollableWidget)gw;
266 
267     remove_callback(w, w->scrollable.h_bar, hbar_callback);
268     w->scrollable.h_bar = h_bar;
269     add_callback(w, w->scrollable.h_bar, hbar_callback);
270     if (!w->scrollable.suspended)
271 	ScrollableFitHBar(w);
272 }
273 
ScrollableSetVBar(Widget gw,Widget v_bar)274 void ScrollableSetVBar(Widget gw, Widget v_bar)
275 {
276     ScrollableWidget	w = (ScrollableWidget)gw;
277 
278     remove_callback(w, w->scrollable.v_bar, vbar_callback);
279     w->scrollable.v_bar = v_bar;
280     add_callback(w, w->scrollable.v_bar, vbar_callback);
281     if (!w->scrollable.suspended)
282 	ScrollableFitVBar(w);
283 }
284 
ScrollableSuspend(Widget gw)285 void ScrollableSuspend(Widget gw)
286 {
287     ScrollableWidget	w = (ScrollableWidget)gw;
288 
289     w->scrollable.suspended = True;
290     call_suspend_hook(w);
291 }
292 
ScrollableResume(Widget gw)293 void ScrollableResume(Widget gw)
294 {
295     ScrollableWidget	w = (ScrollableWidget)gw;
296 
297     w->scrollable.suspended = False;
298     call_suspend_hook(w);
299     ScrollableFitHBar(w);
300     ScrollableFitVBar(w);
301 }
302 
ScrollableFitHBar(ScrollableWidget w)303 void ScrollableFitHBar(ScrollableWidget w)
304 {
305     if (!w->scrollable.h_bar || w->scrollable.suspended)
306 	return;
307     ScrBarSetLengthsAndPos(w->scrollable.h_bar,
308 			   w->scrollable.width,
309 			   w->scrollable.shown_x,
310 			   w->scrollable.pos_x);
311 }
312 
ScrollableFitVBar(ScrollableWidget w)313 void ScrollableFitVBar(ScrollableWidget w)
314 {
315     if (!w->scrollable.v_bar || w->scrollable.suspended)
316 	return;
317     ScrBarSetLengthsAndPos(w->scrollable.v_bar,
318 			   w->scrollable.height,
319 			   w->scrollable.shown_y,
320 			   w->scrollable.pos_y);
321 }
322 
ScrollableHFromGeometry(ScrollableWidget w)323 void ScrollableHFromGeometry(ScrollableWidget w)
324 {
325     w->scrollable.pos_x   = -w->core.x;
326     w->scrollable.shown_x = XtParent(w)->core.width;
327     w->scrollable.width   = w->core.width;
328 }
329 
ScrollableVFromGeometry(ScrollableWidget w)330 void ScrollableVFromGeometry(ScrollableWidget w)
331 {
332     w->scrollable.pos_y   = -w->core.y;
333     w->scrollable.shown_y = XtParent(w)->core.height;
334     w->scrollable.height  = w->core.height;
335 }
336 
ScrollableSetHPos(Widget gw,long pos_x)337 void ScrollableSetHPos(Widget gw, long pos_x)
338 {
339     ScrollableWidget		w = (ScrollableWidget)gw;
340     ScrollableWidgetClass	class = (ScrollableWidgetClass)XtClass(w);
341 
342     class->scrollable_class.set_hpos(w, pos_x);
343     ScrollableFitHBar(w);
344 }
345 
ScrollableSetVPos(Widget gw,long pos_y)346 void ScrollableSetVPos(Widget gw, long pos_y)
347 {
348     ScrollableWidget		w = (ScrollableWidget)gw;
349     ScrollableWidgetClass	class = (ScrollableWidgetClass)XtClass(w);
350 
351     class->scrollable_class.set_vpos(w, pos_y);
352     ScrollableFitVBar(w);
353 }
354 
ScrollableGetVPos(Widget gw)355 long ScrollableGetVPos(Widget gw)
356 {
357     ScrollableWidget		w = (ScrollableWidget)gw;
358 
359     return w->scrollable.pos_y;
360 }
361 
ScrollableGetVSize(Widget gw)362 long ScrollableGetVSize(Widget gw)
363 {
364     ScrollableWidget		w = (ScrollableWidget)gw;
365 
366     return w->scrollable.height;
367 }
368 
ScrollableGetVShown(Widget gw)369 long ScrollableGetVShown(Widget gw)
370 {
371     ScrollableWidget		w = (ScrollableWidget)gw;
372 
373     return w->scrollable.shown_y;
374 }
375 
ScrollablePage(Widget gw,float amount)376 void ScrollablePage(Widget gw, float amount)
377 {
378     ScrollableWidget	w = (ScrollableWidget)gw;
379 
380     ScrollableSetVPos((Widget)w,
381 		      w->scrollable.pos_y + amount * w->scrollable.shown_y);
382 }
383