1 /*
2 **
3 ** Scrollbar.c
4 **
5 ** Copyright (C) 1994, 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING.  If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author:   Johannes Plass (plass@thep.physik.uni-mainz.de)
24 **           Department of Physics
25 **           Johannes Gutenberg-University
26 **           Mainz, Germany
27 **
28 **           Jose E. Marchesi (jemarch@gnu.org)
29 **           GNU Project
30 **
31 */
32 
33 #include "ac_config.h"
34 /*
35 #define MESSAGES
36 */
37 #include "message.h"
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <math.h>
42 
43 #include <inttypes.h>
44 
45 #include "paths.h"
46 #include INC_X11(IntrinsicP.h)
47 #include INC_X11(StringDefs.h)
48 #include INC_XAW(XawInit.h)
49 #include INC_XMU(Drawing.h)
50 #include "ScrollbarP.h"
51 #include "actions.h"
52 
53 
54 /* Private definitions. */
55 
56 static char defaultTranslations[] =
57     "<Btn1Down>:   NotifyScroll()\n\
58      <Btn2Down>:   MoveThumb() NotifyThumb() \n\
59      <Btn3Down>:   NotifyScroll()\n\
60      <Btn1Motion>: HandleThumb() HandleAutoscroll() \n\
61      <Btn2Motion>: MoveThumb() NotifyThumb() \n\
62      <Btn3Motion>: HandleThumb() \n\
63      <BtnUp>:      EndScroll()";
64 
65 static float floatZero = 0.0;
66 
67 #define Offset(field) XtOffsetOf(ScrollbarRec, scrollbar.field)
68 static XtResource resources[] = {
69   {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
70        Offset(length), XtRImmediate, (XtPointer) 1},
71   {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
72        Offset(thickness), XtRImmediate, (XtPointer) 14},
73   {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
74       Offset(orientation), XtRImmediate, (XtPointer) XtorientVertical},
75   {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
76        Offset(scrollProc), XtRCallback, NULL},
77   {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
78        Offset(thumbProc), XtRCallback, NULL},
79   {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
80        Offset(jumpProc), XtRCallback, NULL},
81   {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
82        Offset(top), XtRFloat, (XtPointer)&floatZero},
83   {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
84        Offset(thumb), XtRImmediate, (XtPointer) None},
85   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
86        Offset(foreground), XtRString, XtDefaultForeground},
87   {XtNshown, XtCShown, XtRFloat, sizeof(float),
88        Offset(shown), XtRFloat, (XtPointer)&floatZero},
89   {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
90        Offset(min_thumb), XtRImmediate, (XtPointer) 7},
91   {XtNshowArrows, XtCShowArrows, XtRBoolean, sizeof(Boolean),
92        Offset(show_arrows), XtRImmediate, (XtPointer) TRUE},
93   {XtNthumbTopIndent, XtCThumbTopIndent, XtRDimension, sizeof(Dimension),
94        Offset(thumb_top_indent), XtRImmediate, (XtPointer) 1},
95   {XtNthumbSideIndent, XtCThumbSideIndent, XtRDimension, sizeof(Dimension),
96        Offset(thumb_side_indent), XtRImmediate, (XtPointer) 0},
97   {XtNarrowTopIndent, XtCArrowTopIndent, XtRDimension, sizeof(Dimension),
98        Offset(arrow_top_indent), XtRImmediate, (XtPointer) 0},
99   {XtNarrowSideIndent, XtCArrowSideIndent, XtRDimension, sizeof(Dimension),
100        Offset(arrow_side_indent), XtRImmediate, (XtPointer) 0},
101   {XtNuseDynamic, XtCUseDynamic, XtRBoolean, sizeof(Boolean),
102        Offset(use_dynamic), XtRImmediate, (XtPointer) TRUE},
103   {XtNinterval, XtCInterval, XtRInt, sizeof(int),
104        Offset(interval), XtRImmediate, (XtPointer) 100},
105   {XtNdelay, XtCDelay, XtRInt, sizeof(int),
106        Offset(delay), XtRImmediate, (XtPointer) 300},
107 };
108 #undef Offset
109 
110 static void ClassInitialize(void);
111 static void Initialize(Widget,Widget,ArgList,Cardinal*);
112 static void Destroy(Widget);
113 static void Realize(Widget,XtValueMask*,XSetWindowAttributes*);
114 static void Resize(Widget);
115 static void Redisplay(Widget,XEvent*,Region);
116 static Boolean SetValues(Widget,Widget,Widget,ArgList,Cardinal*);
117 
118 static void HandleThumb(Widget,XEvent*,String*,Cardinal*);
119 static void HandleAutoscroll(Widget,XEvent*,String*,Cardinal*);
120 static void MoveThumb(Widget,XEvent*,String*,Cardinal*);
121 static void NotifyThumb(Widget,XEvent*,String*,Cardinal*);
122 static void NotifyScroll(Widget,XEvent*,String*,Cardinal*);
123 static void EndScroll(Widget,XEvent*,String*,Cardinal*);
124 
125 static XtActionsRec actions[] = {
126     {"HandleThumb",	HandleThumb},
127     {"HandleAutoscroll",HandleAutoscroll},
128     {"MoveThumb",	MoveThumb},
129     {"NotifyThumb",	NotifyThumb},
130     {"NotifyScroll",	NotifyScroll},
131     {"EndScroll",	EndScroll}
132 };
133 
134 ScrollbarClassRec scrollbarClassRec = {
135   { /* core fields */
136     /* superclass       */	(WidgetClass) &threeDClassRec,
137     /* class_name       */	"Scrollbar",
138     /* size             */	sizeof(ScrollbarRec),
139     /* class_initialize	*/	ClassInitialize,
140     /* class_part_init  */	NULL,
141     /* class_inited	*/	FALSE,
142     /* initialize       */	Initialize,
143     /* initialize_hook  */	NULL,
144     /* realize          */	Realize,
145     /* actions          */	actions,
146     /* num_actions	*/	XtNumber(actions),
147     /* resources        */	resources,
148     /* num_resources    */	XtNumber(resources),
149     /* xrm_class        */	NULLQUARK,
150     /* compress_motion	*/	TRUE,
151     /* compress_exposure*/	TRUE,
152     /* compress_enterleave*/	TRUE,
153     /* visible_interest */	FALSE,
154     /* destroy          */	Destroy,
155     /* resize           */	Resize,
156     /* expose           */	Redisplay,
157     /* set_values       */	SetValues,
158     /* set_values_hook  */	NULL,
159     /* set_values_almost*/	XtInheritSetValuesAlmost,
160     /* get_values_hook  */	NULL,
161     /* accept_focus     */	NULL,
162     /* version          */	XtVersion,
163     /* callback_private */	NULL,
164     /* tm_table         */	defaultTranslations,
165     /* query_geometry	*/	XtInheritQueryGeometry,
166     /* display_accelerator*/	XtInheritDisplayAccelerator,
167     /* extension        */	NULL
168   },
169   { /* simple fields */
170     /* change_sensitive	*/	XtInheritChangeSensitive
171   },
172   { /* threeD fields */
173     /* shadowdraw	*/	XtInheritXaw3dShadowDraw
174   },
175   { /* scrollbar fields */
176     /* ignore		*/	0 /*###jp### changed 21.10.94*/
177   }
178 
179 };
180 
181 WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
182 
183 /*###############################################################################
184     PREPROCESSOR INSTRUCTIONS
185 ###############################################################################*/
186 
187 #if defined(MIN)
188 #   undef MIN
189 #endif
190 #if defined(MAX)
191 #   undef MAX
192 #endif
193 #define MIN(_x_,_y_)	((_x_)<(_y_)?(_x_):(_y_))
194 #define MAX(_x_,_y_)	((_x_)>(_y_)?(_x_):(_y_))
195 #define PUT_IN_RANGE(min,num,max) MAX((min),MIN((num),(max)))
196 
197 #define SCROLLBARWIDGET		ScrollbarWidget sbw = (ScrollbarWidget)
198 
199 #define IS_REALIZED		(XtIsRealized((Widget)sbw)) /*###jp### changed 21.10.94*/
200 #define IS_HORIZONTAL		(sbw->scrollbar.orientation == XtorientHorizontal)
201 #define IS_VERTICAL		(sbw->scrollbar.orientation == XtorientVertical)
202 #define DISPLAY			XtDisplay(sbw)
203 #define WINDOW			XtWindow(sbw)
204 
205 #define SBW			sbw
206 /* public */
207 #define WIDTH			sbw->core.width
208 #define HEIGHT			sbw->core.height
209 #define BACKGROUND_PIXEL	sbw->core.background_pixel
210 #define CURSOR_NAME		sbw->simple.cursor_name
211 #define SHADOW			sbw->threeD.shadow_width
212 #define BOT_SHADOW_GC		sbw->threeD.bot_shadow_GC
213 #define TOP_SHADOW_GC		sbw->threeD.top_shadow_GC
214 
215 #define FOREGROUND		sbw->scrollbar.foreground
216 #define MIN_THUMB		sbw->scrollbar.min_thumb
217 #define SCROLLBAR_GC		sbw->scrollbar.gc
218 #define THUMB			sbw->scrollbar.thumb
219 #define LENGTH			sbw->scrollbar.length
220 #define SHOWN			sbw->scrollbar.shown
221 #define SHOWNLENGTH		sbw->scrollbar.shownLength
222 #define TOP			sbw->scrollbar.top
223 #define TOPLOC			sbw->scrollbar.topLoc
224 #define THICKNESS		sbw->scrollbar.thickness
225 #define THUMB_SIDE_INDENT	sbw->scrollbar.thumb_side_indent
226 #define THUMB_TOP_INDENT	sbw->scrollbar.thumb_top_indent
227 #define SHOW_ARROWS		sbw->scrollbar.show_arrows
228 #define ARROW_TOP_INDENT	sbw->scrollbar.arrow_top_indent
229 #define ARROW_SIDE_INDENT	sbw->scrollbar.arrow_side_indent
230 #define INTERVAL		sbw->scrollbar.interval
231 #define DELAY			sbw->scrollbar.delay
232 
233 /* private */
234 #define TIMER			sbw->scrollbar.timer_id
235 #define DYNAMIC			sbw->scrollbar.dynamic
236 #define SCROLLMODE		sbw->scrollbar.scroll_mode
237 #define SHADOW_BASE		sbw->scrollbar.shadow_base
238 #define ARROW_WIDTH		sbw->scrollbar.arrow_width
239 #define ARROW_HEIGHT		sbw->scrollbar.arrow_height
240 #define ARROW_TOP_TO_BORDER	sbw->scrollbar.arrow_top_to_border
241 #define ARROW_TO_BORDER		sbw->scrollbar.arrow_to_border
242 #define ARROW_SHADOW		sbw->scrollbar.arrow_shadow
243 #define THUMB_SHADOW		sbw->scrollbar.thumb_shadow
244 #define THUMB_TO_ARROW		sbw->scrollbar.thumb_to_arrow
245 #define THUMB_TO_BORDER		sbw->scrollbar.thumb_to_border
246 #define USE_DYNAMIC		sbw->scrollbar.use_dynamic
247 
248 #define USE_FILL		Display *dpy = DISPLAY; Window wndw = WINDOW
249 #define FILL(point,count,gc)       XFillPolygon(dpy,wndw,gc,point,count,Complex,CoordModeOrigin)
250 #define FILLrect(xc,yc,wid,hei,gc) XFillRectangle(dpy,wndw,gc,(int)(xc),(int)(yc),(unsigned int)(wid),(unsigned int)(hei))
251 #define DRAWline(xs,ys,xe,ye,gc)   XDrawLine(dpy,wndw,gc,(int)(xs),(int)(ys),(int)(xe),(int)(ye))
252 #define DRAWlines(point,count,gc)  XDrawLines(dpy,wndw,gc,point,count,CoordModeOrigin)
253 #define CLEAR(xc,yc,wid,hei)       XClearArea(dpy,wndw,(int)(xc),(int)(yc),(unsigned int)(wid),(unsigned int)(hei),FALSE)
254 
255 #define SET_TIMER(widget,interval)                                  \
256   	TIMER = XtAppAddTimeOut (                                   \
257                   XtWidgetToApplicationContext(((Widget)(widget))), \
258                   ((unsigned long)(interval)),                      \
259                   RepeatNotify,                                     \
260                   ((XtPointer)((Widget)(widget)))                   \
261                 )
262 #define DISABLED	((XtIntervalId) 0)
263 #define DESTROY_TIMER	if (TIMER) { XtRemoveTimeOut(TIMER); TIMER = DISABLED; }
264 
265 #define CALLscrollProc(widget,data) \
266            XtCallCallbacks ( ((Widget)(widget)),XtNscrollProc,((XtPointer)(intptr_t)(data)))
267 
268 #define POINT(name,xcoord,ycoord)  name.x=(short)(xcoord);name.y=(short)(ycoord)
269 
270 /*### Definitions related to the Scrollbar Geometry ###########################*/
271 
272 #define  NICE_DIMENSION			5
273 
274 #define _SCROLL_THICKNESS_		((int)THICKNESS-2*THUMB_TO_BORDER)
275 #define _SCROLL_LENGTH_			((int)LENGTH-2*(ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)-1)
276 
277 #define _RIGHT_END_OF_SCROLL_REGION_	((int)THICKNESS-1-THUMB_TO_BORDER)
278 #define _LEFT_START_OF_SCROLL_REGION_	(THUMB_TO_BORDER)
279 #define _START_OF_SCROLL_REGION_	(ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)
280 #define _END_OF_SCROLL_REGION_		((int)LENGTH-1-ARROW_TOP_TO_BORDER-ARROW_HEIGHT-THUMB_TO_ARROW)
281 
282 /*### Identificational Definitions ############################################*/
283 
284 /* Scroll Mode */
285 #define NOSCROLL	0
286 #define CONTINUOUS	2
287 #define ARROW_UP	1
288 #define ARROW_DOWN	3
289 #define PAGE_UP		4
290 #define PAGE_DOWN	5
291 
292 /* identifies upper/left, lower/right */
293 #define UPPER_PART	1
294 #define LOWER_PART	0
295 
296 /* arrow identifier */
297 #define  UPPER_ARROW	0
298 #define  LOWER_ARROW	1
299 #define  BOTH_ARROWS	2
300 #define  NORMAL_ARROW	1
301 #define  INVERTED_ARROW	0
302 
303 #define _SC_INIT_VALUE_ 9999
304 
305 /*### Options at Compiling Time ###############################################*/
306 
307 #define MIN_INTERVAL	8
308 #define MAX_INTERVAL	800
309 #define DYNAMIC_REGION	40.0
310 #define MIN_DELAY	10    /* the minimum delay between clicking on an arrow and */
311                               /* the start of the autoscroll action                 */
312 
313 #define ARROW_SCROLL_AMOUNT (MAX(100,LENGTH)/20)
314 #define PAGE_SCROLL_AMOUNT  LENGTH
315 
316 /*###############################################################################
317     EraseThumbRegion
318 ###############################################################################*/
319 
EraseThumbRegion(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr)320 static void EraseThumbRegion(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr)
321 {
322    USE_FILL;
323 
324    BEGINMESSAGE(EraseThumbRegion)
325    if (IS_VERTICAL) { CLEAR(xl,yt,xr-xl+1,yb-yt+1); }
326    else             { CLEAR(yt,xl,yb-yt+1,xr-xl+1); }
327    ENDMESSAGE(EraseThumbRegion)
328 }
329 
330 /*###############################################################################
331     PaintThumbCover
332 ###############################################################################*/
333 
PaintThumbCover(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr)334 static void PaintThumbCover(ScrollbarWidget SBW, Dimension yt, Dimension yb,Dimension xl,Dimension xr)
335 {
336    USE_FILL;
337 
338    BEGINMESSAGE(PaintThumbCover)
339    if (IS_VERTICAL) FILLrect(xl,yt,xr+1-xl,yb-yt+1,SCROLLBAR_GC);
340    else             FILLrect(yt,xl,yb-yt+1,xr+1-xl,SCROLLBAR_GC);
341    ENDMESSAGE(PaintThumbCover)
342 }
343 
344 /*###############################################################################
345     PaintShadowAtSidesOfThumb
346 ###############################################################################*/
347 
PaintShadowAtSidesOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)348 static void PaintShadowAtSidesOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
349 {
350    USE_FILL;
351 
352    BEGINMESSAGE(PaintShadowAtSidesOfThumb)
353    if (IS_VERTICAL) {
354       FILLrect(xl,yt,s+1,yb-yt+1,TOP_SHADOW_GC); FILLrect(xr+1-s,yt,s,yb-yt+1,BOT_SHADOW_GC);
355    }  else {
356       FILLrect(yt,xl,yb-yt+1,s+1,TOP_SHADOW_GC); FILLrect(yt,xr+1-s,yb-yt+1,s,BOT_SHADOW_GC);
357    }
358    ENDMESSAGE(PaintShadowAtSidesOfThumb)
359 }
360 
361 /*###############################################################################
362     PaintShadowAtEndOfThumb
363 ###############################################################################*/
364 
PaintShadowAtEndOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s,int part)365 static void PaintShadowAtEndOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s, int part)
366 {
367    XPoint shadowPT[4];
368    USE_FILL;
369 
370    BEGINMESSAGE(PaintShadowAtEndOfThumb)
371 
372    if (IS_VERTICAL) {
373       if (part==UPPER_PART) {
374          POINT(shadowPT[3],xl,yt);                POINT(shadowPT[2],xr+1,yt);
375               POINT(shadowPT[0],xl+s,yb);  POINT(shadowPT[1],xr-s+1,yb);
376       } else {
377               POINT(shadowPT[3],xl+s,yt+1);  POINT(shadowPT[2],xr-s+1,yt+1);
378          POINT(shadowPT[0],xl,yb+1);                POINT(shadowPT[1],xr+1,yb+1);
379       }
380    } else {
381       if (part==UPPER_PART) {
382          POINT(shadowPT[0],yt,xl);
383               POINT(shadowPT[1],yb,xl+s);
384               POINT(shadowPT[2],yb,xr-s+1);
385          POINT(shadowPT[3],yt,xr+1);
386       } else {
387               POINT(shadowPT[0],yb+1,xl);
388          POINT(shadowPT[1],yt+1,xl+s);
389          POINT(shadowPT[2],yt+1,xr-s+1);
390               POINT(shadowPT[3],yb+1,xr+1);
391       }
392    }
393    if (part==UPPER_PART) { FILL(shadowPT,4,TOP_SHADOW_GC); }
394    else                  { FILL(shadowPT,4,BOT_SHADOW_GC); }
395 
396    ENDMESSAGE(PaintShadowAtEndOfThumb)
397 }
398 
399 /*###############################################################################
400     PaintWholeThumb
401 ###############################################################################*/
402 
PaintWholeThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)403 static void PaintWholeThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
404 {
405    BEGINMESSAGE(PaintWholeThumb)
406    if (s) {
407       PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
408       PaintShadowAtEndOfThumb(SBW,yt,yt+s,xl,xr,s,UPPER_PART);
409       PaintShadowAtEndOfThumb(SBW,yb-s,yb,xl,xr,s,LOWER_PART);
410    }
411    PaintThumbCover(SBW,yt+s,yb-s,xl+s,xr-s);
412    ENDMESSAGE(PaintWholeThumb)
413 }
414 
415 /*###############################################################################
416     PaintMiddleOfThumb
417 ###############################################################################*/
418 
PaintMiddleOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)419 static void PaintMiddleOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
420 {
421    BEGINMESSAGE(PaintMiddleOfThumb)
422    if ((int)s) PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
423    PaintThumbCover(SBW,yt,yb,xl+s,xr-s);
424    ENDMESSAGE(PaintMiddleOfThumb)
425 }
426 
427 /*###############################################################################
428     PaintEndOfThumb
429 ###############################################################################*/
430 
PaintEndOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s,int part)431 static void PaintEndOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s, int part)
432 {
433    BEGINMESSAGE(PaintEndOfThumb)
434    if (part==UPPER_PART) {
435       if (s) {
436          PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
437          PaintShadowAtEndOfThumb(SBW,yt,yt+s,xl,xr,s,UPPER_PART);
438       }
439       PaintThumbCover(SBW,yt+s,yb,xl+s,xr-s);
440    } else {
441       if (s) {
442          PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
443          PaintShadowAtEndOfThumb(SBW,yb-s,yb,xl,xr,s,LOWER_PART);
444       }
445       PaintThumbCover(SBW,yt,yb-s,xl+s,xr-s);
446    }
447    ENDMESSAGE(PaintEndOfThumb)
448 }
449 
450 /*###############################################################################
451     GetRelativeThumbLocation
452 ###############################################################################*/
453 
GetRelativeThumbLocation(ScrollbarWidget SBW,Dimension * newtop,Dimension * newbot)454 static void GetRelativeThumbLocation(ScrollbarWidget SBW, Dimension *newtop, Dimension *newbot)
455 {
456    Dimension scroll_length = (Dimension) _SCROLL_LENGTH_-MIN_THUMB;
457    Dimension end_of_scroll_region = (Dimension) _END_OF_SCROLL_REGION_;
458 
459    BEGINMESSAGE(GetRelativeThumbLocation)
460    *newtop = (Dimension) (_START_OF_SCROLL_REGION_+scroll_length*TOP);
461    *newtop = MIN(*newtop,end_of_scroll_region);
462    *newbot = (Dimension)(*newtop+scroll_length*SHOWN);
463    *newbot = MAX(*newbot,(Dimension)(*newtop+MIN_THUMB));
464    *newbot = MIN(*newbot,end_of_scroll_region);
465    IIMESSAGE(*newtop,*newbot)
466    ENDMESSAGE(GetRelativeThumbLocation)
467 }
468 
469 /*###############################################################################
470     AdjustThumbShadow
471 ###############################################################################*/
472 
AdjustThumbShadow(ScrollbarWidget SBW,Dimension newtop,Dimension newbot)473 static Boolean AdjustThumbShadow(ScrollbarWidget SBW, Dimension newtop, Dimension newbot)
474 {
475     Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
476     Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
477     int s;
478     Boolean changed = False;
479 
480     BEGINMESSAGE(AdjustThumbShadow)
481     IIMESSAGE(newtop,newbot) IIMESSAGE(xl,xr) IMESSAGE(THUMB_SHADOW)
482     s = MIN((int)(newbot-newtop+1),(int)(xr-xl+1))/2;
483     s = MAX(0,s); s = MIN(s,(int)SHADOW);
484     if (s != THUMB_SHADOW) {
485        THUMB_SHADOW = s;
486        INFIMESSAGE(had to adjust thumb shadow:,THUMB_SHADOW)
487        changed = True;
488     } else {
489        INFMESSAGE(thumb shadow is just nice)
490     }
491     ENDMESSAGE(AdjustThumbShadow)
492     return changed;
493 }
494 
495 /*###############################################################################
496     PaintThumb
497 ###############################################################################*/
498 
PaintThumb(ScrollbarWidget SBW)499 static void PaintThumb(ScrollbarWidget SBW)
500 {
501     Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
502     Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
503     Dimension oldtop, oldbot, newtop, newbot;
504 
505     BEGINMESSAGE(PaintThumb)
506 
507     if (!IS_REALIZED)                { INFMESSAGE(not realized)     ENDMESSAGE(PaintThumb) return; }
508     if ((LENGTH<1) || (THICKNESS<1)) { INFMESSAGE(not enough space) ENDMESSAGE(PaintThumb) return; }
509 
510     GetRelativeThumbLocation(SBW,&newtop,&newbot);
511     oldtop = TOPLOC; oldbot = oldtop + SHOWNLENGTH-1;
512     IIMESSAGE(newtop,oldtop) IIMESSAGE(newbot,oldbot)
513     IIMESSAGE(xr,xl) IMESSAGE(THUMB_SHADOW)
514 
515     if (AdjustThumbShadow(SBW,newtop,newbot)) {
516        INFMESSAGE(doing full repaint with adjusted thumb shadow)
517        if (oldbot>oldtop) EraseThumbRegion(SBW,oldtop,oldbot,xl,xr);
518        if (newbot>newtop) PaintWholeThumb(SBW,newtop,newbot,xl,xr,(Dimension)THUMB_SHADOW);
519     } else {
520        Dimension s = (Dimension) THUMB_SHADOW;
521        if ((newtop >= oldbot) || (newbot <= oldtop)) {
522           INFMESSAGE(doing full repaint)
523           if (oldbot>oldtop) EraseThumbRegion(SBW,oldtop,oldbot,xl,xr);
524           if (newbot>newtop) PaintWholeThumb(SBW,newtop,newbot,xl,xr,s);
525        } else {
526           INFMESSAGE(doing partial repaint)
527           if (newtop > oldtop) EraseThumbRegion(SBW,oldtop,newtop-1,xl,xr);
528           if (newbot < oldbot) EraseThumbRegion(SBW,newbot+1,oldbot,xl,xr);
529           if (newtop < oldtop) PaintMiddleOfThumb(SBW,newtop,MIN(newbot,oldtop+s),xl,xr,s);
530           if (newbot > oldbot) PaintMiddleOfThumb(SBW,MAX(newtop,oldbot-s),newbot,xl,xr,s);
531           if ((newtop!=oldtop)&&(s)) PaintShadowAtEndOfThumb(SBW,newtop,newtop+s,xl,xr,s,UPPER_PART);
532           if ((newbot!=oldbot)&&(s)) PaintShadowAtEndOfThumb(SBW,newbot-s,newbot,xl,xr,s,LOWER_PART);
533        }
534     }
535     TOPLOC = newtop;
536     SHOWNLENGTH = newbot-newtop+1;
537 
538     ENDMESSAGE(PaintThumb)
539 }
540 
541 /*###############################################################################
542     PaintArrows
543 ###############################################################################*/
544 
545 #define vPOLY_4(name,x0,y0,x1,y1,x2,y2,x3,y3)   \
546       name[0].x=(short)(x0);name[0].y=(short)(y0);\
547       name[1].x=(short)(x1);name[1].y=(short)(y1);\
548       name[2].x=(short)(x2);name[2].y=(short)(y2);\
549       name[3].x=(short)(x3);name[3].y=(short)(y3);\
550       name[4].x=(short)(x0);name[4].y=(short)(y0)
551 
552 #define hPOLY_4(name,x0,y0,x1,y1,x2,y2,x3,y3)   \
553       name[0].x=(short)(y0);name[0].y=(short)(x0);\
554       name[1].x=(short)(y1);name[1].y=(short)(x1);\
555       name[2].x=(short)(y2);name[2].y=(short)(x2);\
556       name[3].x=(short)(y3);name[3].y=(short)(x3);\
557       name[4].x=(short)(y0);name[4].y=(short)(x0)
558 
559 #define COORD(name,value) short name = (short) (value)
560 
PaintArrows(ScrollbarWidget SBW,int which,int mode)561 static void PaintArrows(ScrollbarWidget SBW, int which, int mode)
562 {
563    BEGINMESSAGE(PaintArrows)
564 
565    if ((!IS_REALIZED) || ((ARROW_HEIGHT<1) || (ARROW_WIDTH<1)) || (!SHOW_ARROWS)) {
566       ENDMESSAGE(PaintArrows)
567       return;
568    }
569 
570    {  GC 	ts_gc = ((mode==NORMAL_ARROW) ? TOP_SHADOW_GC : BOT_SHADOW_GC);
571       GC 	bs_gc = ((mode==NORMAL_ARROW) ? BOT_SHADOW_GC : TOP_SHADOW_GC);
572       XPoint	ls[5];
573       XPoint	rs[5];
574       XPoint	bs[5];
575       XPoint	cover[5];
576       USE_FILL;
577       int ATB  = ARROW_TO_BORDER;
578       int ATTB = ARROW_TOP_TO_BORDER;
579       int AH   = ARROW_HEIGHT-1;
580       int AW   = ARROW_WIDTH-1;
581       int AS   = ARROW_SHADOW;
582       int D_AS = (int) (1.5*ARROW_SHADOW);
583 
584       if (which==UPPER_ARROW || which==BOTH_ARROWS) {
585          if (IS_VERTICAL) {
586             COORD(y,ATTB);
587             COORD(yy,ATTB+2*AS);
588             COORD(yyy,ATTB+AH-AS);
589             COORD(yyyy,ATTB+AH);
590             COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
591             COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
592             vPOLY_4(cover,r,yy,rr,yyy,ll,yyy,l,yy);
593             if (AS) {
594                vPOLY_4(ls,l,y,lll,yyyy,ll,yyy,l,yy);
595                vPOLY_4(rs,r,y,rrr,yyyy,rr,yyy,r,yy);
596                vPOLY_4(bs,lll,yyyy+1,rrr,yyyy+1,rrr-AS,yyyy+1-AS,lll+AS,yyyy+1-AS);
597                FILL(bs,5,bs_gc);
598                if (AS==1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
599                FILL(ls,5,ts_gc);		DRAWlines(ls,5,ts_gc);
600                FILL(rs,5,bs_gc);		DRAWlines(rs,5,bs_gc);
601                if (AS!=1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
602             } else {
603                FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);
604             }
605          } else {
606             COORD(x,ATTB);
607             COORD(xx,ATTB+2*AS);
608             COORD(xxx,ATTB+AH-AS);
609             COORD(xxxx,ATTB+AH);
610             COORD(l,ATB+(AW+1)/2); COORD(ll,ATB+AW-D_AS); COORD(lll,ATB+AW);
611             COORD(r,ATB+AW/2); COORD(rr,ATB+D_AS); COORD(rrr,ATB);
612             hPOLY_4(cover,ll,xxx,rr,xxx,r,xx,l,xx);
613             if (AS) {
614                hPOLY_4(ls,lll,xxxx,ll,xxx,l,xx,l,x);
615                hPOLY_4(rs,rrr,xxxx,rr,xxx,r,xx,r,x);
616                hPOLY_4(bs,lll,xxxx,rrr,xxxx,rr,xxx,ll,xxx);
617                FILL(bs,5,bs_gc);		DRAWlines(bs,5,bs_gc);
618                FILL(ls,5,bs_gc);		DRAWlines(ls,5,bs_gc);
619                FILL(rs,5,ts_gc);		DRAWlines(rs,5,ts_gc);
620                FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);
621             } else {
622                FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);
623             }
624          }
625       }
626       if (which==LOWER_ARROW || which==BOTH_ARROWS) {
627          if (IS_VERTICAL) {
628             COORD(L,LENGTH-1);
629             COORD(y,L-ATTB);
630             COORD(yy,L-ATTB-2*AS);
631             COORD(yyy,L-ATTB-AH+AS);
632             COORD(yyyy,L-ATTB-AH);
633             COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
634             COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
635             vPOLY_4(cover,ll,yyy,l,yy,r,yy,rr,yyy);
636             if (AS) {
637                vPOLY_4(ls,lll,yyyy,l,y,l,yy,ll,yyy);
638                vPOLY_4(rs,rrr,yyyy,r,y,r,yy,rr,yyy);
639                vPOLY_4(bs,rrr,yyyy,rr,yyy,ll,yyy,lll,yyyy);
640                FILL(bs,5,ts_gc);		DRAWlines(bs,5,ts_gc);
641                FILL(ls,5,ts_gc);		DRAWlines(ls,5,ts_gc);
642                if (AS==1) { FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);}
643                FILL(rs,5,bs_gc);		DRAWlines(rs,5,bs_gc);
644                if (AS!=1) { FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);}
645             } else {
646                FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);
647             }
648          } else {
649             COORD(L,LENGTH-1);
650             COORD(x,L-ATTB);
651             COORD(xx,L-ATTB-2*AS);
652             COORD(xxx,L-ATTB-AH+AS);
653             COORD(xxxx,L-ATTB-AH);
654             COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
655             COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
656             hPOLY_4(cover,ll,xxx,rr,xxx,r,xx,l,xx);
657             if (AS) {
658                hPOLY_4(ls,lll,xxxx,ll,xxx,l,xx,l,x);
659                hPOLY_4(rs,rrr,xxxx,rr,xxx,r,xx,r,x);
660                hPOLY_4(bs,lll,xxxx,rrr,xxxx,rr,xxx,ll,xxx);
661                FILL(bs,5,ts_gc);		DRAWlines(bs,5,ts_gc);
662                if (AS==1) { FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);}
663                FILL(ls,5,ts_gc);		DRAWlines(ls,5,ts_gc);
664                FILL(rs,5,bs_gc);		DRAWlines(rs,5,bs_gc);
665                if (AS!=1) { FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);}
666             } else {
667                FILL(cover,5,SCROLLBAR_GC);	DRAWlines(cover,5,SCROLLBAR_GC);
668             }
669          }
670       }
671    }
672    ENDMESSAGE(PaintArrows)
673 }
674 
675 /*###############################################################################
676     CreateGC
677 ###############################################################################*/
678 
CreateGC(Widget w)679 static void CreateGC(Widget w)
680 {
681     SCROLLBARWIDGET w;
682     XGCValues gcValues;
683     XtGCMask mask;
684     unsigned int depth = 1;
685 
686     BEGINMESSAGE(CreateGC)
687     if (THUMB == XtUnspecifiedPixmap) {
688         THUMB = XmuCreateStippledPixmap (XtScreen(w),
689 					(Pixel) 1, (Pixel) 0, depth);
690     } else if (THUMB != None) {
691 	Window root;
692 	int x, y;
693 	unsigned int width, height, bw;
694 	if (XGetGeometry (XtDisplay(w), THUMB, &root, &x, &y,
695 			 &width, &height, &bw, &depth) == 0) {
696 	    XtAppError (XtWidgetToApplicationContext (w),
697 	       "Scrollbar Widget: Could not get geometry of thumb pixmap.");
698 	}
699     }
700 
701     gcValues.foreground = FOREGROUND;
702     gcValues.background = BACKGROUND_PIXEL;
703     mask = GCForeground | GCBackground;
704 
705     if (THUMB != None) {
706 	if (depth == 1) {
707 	    gcValues.fill_style = FillOpaqueStippled;
708 	    gcValues.stipple = SBW->scrollbar.thumb;
709 	    mask |= GCFillStyle | GCStipple;
710 	}
711 	else {
712 	    gcValues.fill_style = FillTiled;
713 	    gcValues.tile = SBW->scrollbar.thumb;
714 	    mask |= GCFillStyle | GCTile;
715 	}
716     }
717     /* the creation should be non-caching, because */
718     /* we now set and clear clip masks on the gc returned */
719     SCROLLBAR_GC = XtGetGC(w, mask, &gcValues);
720 
721     ENDMESSAGE(CreateGC)
722 }
723 
724 /*###############################################################################
725     SetDimensions
726 ###############################################################################*/
727 
SetDimensions(ScrollbarWidget SBW)728 static void SetDimensions(ScrollbarWidget SBW)
729 {
730    Dimension tmp;
731 
732    BEGINMESSAGE(SetDimensions)
733 
734    if (IS_VERTICAL) { LENGTH = HEIGHT; THICKNESS = WIDTH;  }
735    else             { LENGTH = WIDTH;  THICKNESS = HEIGHT; }
736 
737    IIMESSAGE(THICKNESS,LENGTH)
738 
739    INFMESSAGE(### shadow width #############)
740    if (SHADOW_BASE == _SC_INIT_VALUE_) SHADOW_BASE = SHADOW;
741    SHADOW = SHADOW_BASE;
742    tmp = MIN(THICKNESS,LENGTH);
743    if (tmp<4*SHADOW) {
744       if (tmp>=4) SHADOW = tmp/4; else SHADOW = tmp/2;
745       INFMESSAGE(adjusted shadow)
746    }
747    IMESSAGE(SHADOW)
748 
749    INFMESSAGE(### arrow geometry ###########)
750    if (SHOW_ARROWS) {
751       ARROW_TO_BORDER = (int) (SHADOW+ARROW_SIDE_INDENT);
752       ARROW_TOP_TO_BORDER  = (int) (SHADOW+ARROW_TOP_INDENT);
753       ARROW_WIDTH       = (int)THICKNESS-2*ARROW_TO_BORDER;
754       ARROW_HEIGHT      = ((int)LENGTH-(int)MIN_THUMB)/2-(int)THUMB_TOP_INDENT-ARROW_TOP_TO_BORDER;
755 
756       if ((ARROW_WIDTH < NICE_DIMENSION) && (ARROW_SIDE_INDENT)) {
757          while (ARROW_TO_BORDER>(int)SHADOW) {
758             --ARROW_TO_BORDER;
759             ARROW_WIDTH = ((int)THICKNESS-2*ARROW_TO_BORDER);
760             if (ARROW_WIDTH>=NICE_DIMENSION) break;
761          }
762          INFMESSAGE(adjusted arrow side indent)
763       }
764       if ((ARROW_HEIGHT<ARROW_WIDTH) && (ARROW_TOP_INDENT)) {
765          while (ARROW_TOP_TO_BORDER>(int)SHADOW) {
766             --ARROW_TOP_TO_BORDER;
767             ARROW_HEIGHT = ((int)LENGTH-(int)MIN_THUMB)/2-(int)THUMB_TOP_INDENT-ARROW_TOP_TO_BORDER;
768             if (ARROW_HEIGHT>=NICE_DIMENSION) break;
769          }
770          ARROW_HEIGHT = MAX(0,ARROW_HEIGHT);
771          INFMESSAGE(adjusted arrow top indent)
772       }
773       ARROW_WIDTH  = MIN(ARROW_WIDTH,ARROW_HEIGHT);
774       if ((ARROW_WIDTH+(int)THICKNESS)&1) --ARROW_WIDTH;
775       ARROW_HEIGHT = ARROW_WIDTH; if (ARROW_HEIGHT) ARROW_HEIGHT -= (1-(ARROW_WIDTH&1));
776       ARROW_TO_BORDER = ((int)THICKNESS - ARROW_WIDTH)/2;
777       ARROW_SHADOW = (ARROW_WIDTH-1)/3; ARROW_SHADOW = PUT_IN_RANGE(0,ARROW_SHADOW,(int)SHADOW);
778    } else {
779       ARROW_TO_BORDER = ARROW_TOP_TO_BORDER = (int) SHADOW;
780       ARROW_WIDTH = ARROW_HEIGHT = 0;
781    }
782    IIMESSAGE(ARROW_WIDTH,ARROW_HEIGHT)
783    IIMESSAGE(ARROW_TO_BORDER,ARROW_TOP_TO_BORDER) IMESSAGE(ARROW_SHADOW)
784 
785    INFMESSAGE(### thumb geometry ###########)
786    THUMB_SHADOW        = (int) SHADOW;
787    THUMB_TO_BORDER   = (int) (THUMB_SIDE_INDENT+SHADOW);
788    THUMB_TO_ARROW      = (int) (THUMB_TOP_INDENT);
789 
790    if ((int)THICKNESS-2*THUMB_TO_BORDER<NICE_DIMENSION) {
791       THUMB_TO_BORDER = ((int)THICKNESS-NICE_DIMENSION)/2;
792       THUMB_TO_BORDER = MAX(THUMB_TO_BORDER,(int)SHADOW);
793       INFMESSAGE(adjusted thumb side indent)
794    }
795    if (((int)LENGTH-2*(ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)<(int)MIN_THUMB) && (THUMB_TO_ARROW)) {
796       THUMB_TO_ARROW = ((int)LENGTH-(int)MIN_THUMB)/2-ARROW_TOP_TO_BORDER-ARROW_HEIGHT;
797       THUMB_TO_ARROW = MAX(0,THUMB_TO_ARROW);
798       INFMESSAGE(adjusted minimal distance thumb to arrow)
799    }
800    IMESSAGE(MIN_THUMB) IIMESSAGE(THUMB_TO_BORDER,THUMB_TO_ARROW)
801 
802    ENDMESSAGE(SetDimensions)
803 }
804 
805 /*###############################################################################
806     ClassInitialize
807 ###############################################################################*/
808 
ClassInitialize(void)809 static void ClassInitialize(void)
810 {
811     static Boolean initialized = FALSE;
812 
813     BEGINMESSAGE(ClassInitialize)
814     if (initialized) {INFMESSAGE(class already initialized) return; }
815     XawInitializeWidgetSet();
816     XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
817 		    (XtConvertArgList)NULL, (Cardinal) 0);
818     initialized = TRUE;
819     ENDMESSAGE(ClassInitialize)
820 }
821 
822 /*###############################################################################
823     Initialize
824 ###############################################################################*/
825 
Initialize(Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)826 static void Initialize(Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
827 /* request: what the client asked for */
828 /* new: what we're going to give him */
829 {
830     SCROLLBARWIDGET new;
831 
832     BEGINMESSAGE(Initialize)
833     CreateGC(new);
834     if (WIDTH == 0)  WIDTH  = (IS_VERTICAL)   ? THICKNESS : LENGTH;
835     if (HEIGHT == 0) HEIGHT = (IS_HORIZONTAL) ? THICKNESS : LENGTH;
836     SHADOW_BASE = _SC_INIT_VALUE_;
837     TOPLOC      = 0;
838     SHOWNLENGTH = 1;
839     INTERVAL    = MAX(INTERVAL,MIN_INTERVAL);
840     DELAY       = MAX(DELAY,MIN_DELAY);
841     SCROLLMODE  = NOSCROLL;
842     TIMER       = DISABLED;
843     DYNAMIC     = 0;
844     /*
845        how could we ever come away without the following line ...???
846        1/95 ###jp###
847     */
848     SetDimensions(SBW); /*#test#*/
849     ENDMESSAGE(Initialize)
850 }
851 
852 /*###############################################################################
853     Realize
854 ###############################################################################*/
855 
Realize(Widget w,Mask * valueMask,XSetWindowAttributes * attributes)856 static void Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
857 {
858     SCROLLBARWIDGET w;
859     BEGINMESSAGE(Realize)
860     if(CURSOR_NAME == NULL) XtVaSetValues(w, XtNcursorName, "top_left_arrow", NULL);
861     /* dont set the cursor of the window to anything */
862     *valueMask &= ~CWCursor;
863     /*
864      * The Simple widget actually stuffs the value in the valuemask.
865      */
866     (*scrollbarWidgetClass->core_class.superclass->core_class.realize) (w, valueMask, attributes);
867     ENDMESSAGE(Realize)
868 }
869 
870 /*###############################################################################
871     SetValues
872 ###############################################################################*/
873 
SetValues(Widget old,Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)874 static Boolean SetValues(Widget old, Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
875 {
876    SCROLLBARWIDGET 	new;
877    ScrollbarWidget 	old_sbw = (ScrollbarWidget) old;
878    Boolean 		redraw 	= FALSE;
879 
880    BEGINMESSAGE(SetValues)
881 
882    if (SHOWN < 0.0 || SHOWN > 1.0 || TOP < 0.0 || TOP > 1.0) {
883       INFMESSAGE(### bad values for thumb position/length ###)
884       FMESSAGE(SHOWN) FMESSAGE(TOP)
885       SHOWN = old_sbw->scrollbar.shown; TOP = old_sbw->scrollbar.top;
886       SHOWN = PUT_IN_RANGE(0.0,SHOWN,1.0);
887       TOP   = PUT_IN_RANGE(0.0,TOP,  1.0);
888       INFMESSAGE(corrected to)
889       FMESSAGE(SHOWN) FMESSAGE(TOP)
890    }
891    FMESSAGE(SHOWN) FMESSAGE(TOP)
892    if ((TOP != old_sbw->scrollbar.top) || (SHOWN != old_sbw->scrollbar.shown)) {
893       INFMESSAGE(thumb position/length has changed)
894       redraw = TRUE;
895    }
896 
897    if (FOREGROUND != old_sbw->scrollbar.foreground ||
898       BACKGROUND_PIXEL != old_sbw->core.background_pixel ||
899       THUMB != old_sbw->scrollbar.thumb) {
900       INFMESSAGE(GC has changed)
901       XtReleaseGC((Widget)SBW, SCROLLBAR_GC); /*###jp### changed 21.10.94*/
902       CreateGC(new);
903       redraw = TRUE;
904    }
905 
906    if ( (SHADOW != old_sbw->threeD.shadow_width)				||
907         (SHOW_ARROWS != old_sbw->scrollbar.show_arrows)			||
908         (ARROW_TOP_INDENT != old_sbw->scrollbar.arrow_top_indent)	||
909         (ARROW_SIDE_INDENT != old_sbw->scrollbar.arrow_side_indent)	||
910         (THUMB_SIDE_INDENT != old_sbw->scrollbar.thumb_side_indent)	||
911         (THUMB_TOP_INDENT != old_sbw->scrollbar.thumb_top_indent)	||
912         (MIN_THUMB != old_sbw->scrollbar.min_thumb)  ) {
913         INFMESSAGE(internal scrollbar geometry has changed)
914         SHADOW_BASE=_SC_INIT_VALUE_;
915         SetDimensions(SBW);
916         redraw =TRUE;
917    }
918    INTERVAL = MAX(INTERVAL,MIN_INTERVAL);
919    DELAY = MAX(DELAY,MIN_DELAY);
920 
921    if (!IS_REALIZED) { INFMESSAGE(not realized) redraw=FALSE; }
922 
923 #  ifdef MESSAGES
924       if (redraw) { INFMESSAGE(need redisplay) }
925       else        { INFMESSAGE(redisplay unnecessary) }
926 #  endif
927 
928    ENDMESSAGE(SetValues)
929    return redraw;
930 }
931 
932 /*###############################################################################
933    Resize
934 ###############################################################################*/
935 
Resize(Widget w)936 static void Resize(Widget w)
937 {
938    SCROLLBARWIDGET w;
939    XEvent event;
940 
941    BEGINMESSAGE(Resize)
942    SetDimensions(SBW);
943    event.xexpose.x = 0; event.xexpose.y = 0;
944    event.xexpose.width = WIDTH; event.xexpose.height = HEIGHT;
945    Redisplay(w, (XEvent *) &event, (Region)NULL);
946    ENDMESSAGE(Resize)
947 }
948 
949 /*###############################################################################
950    Redisplay
951    compress_exposure is TRUE, so 'event' contains the bounding box for the
952    'region' to be exposed. Graphics actions will be restricted to this
953    bounding box to minimize visual disturbances.
954 ###############################################################################*/
955 
Redisplay(Widget w,XEvent * event,Region region)956 static void Redisplay(Widget w, XEvent *event, Region region)
957 {
958    SCROLLBARWIDGET w;
959    ScrollbarWidgetClass swclass = (ScrollbarWidgetClass) XtClass (w);
960    Dimension s;
961    Dimension newtop, newbot;
962    Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
963    Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
964    Dimension yt,yb;
965 
966    BEGINMESSAGE(Redisplay)
967 
968    if (!IS_REALIZED) { INFMESSAGE(not realized) ENDMESSAGE(Redisplay) return; }
969    if ((LENGTH<1) || (THICKNESS<1)) {
970       INFMESSAGE(not enough space) ENDMESSAGE(Redisplay) return;
971    }
972 
973    if ((region) && (XRectInRegion(region,0,0,WIDTH,HEIGHT) == RectangleOut)) {
974       INFMESSAGE(request out of region) ENDMESSAGE(Redisplay)
975       return;
976    }
977 
978    GetRelativeThumbLocation(SBW,&newtop,&newbot);
979    AdjustThumbShadow(SBW,newtop,newbot);
980    s = (Dimension)(THUMB_SHADOW);
981    if (event) {
982       if (IS_HORIZONTAL) { yt=(Dimension)(event->xexpose.x); yb=(Dimension)(yt+event->xexpose.width);  }
983       else               { yt=(Dimension)(event->xexpose.y); yb=(Dimension)(yt+event->xexpose.height); }
984       if (SHOW_ARROWS) {
985          Dimension soar = (Dimension) (ARROW_TOP_TO_BORDER);
986          Dimension sosr = (Dimension) _START_OF_SCROLL_REGION_;
987          Dimension eosr = (Dimension) (_END_OF_SCROLL_REGION_+THUMB_TO_ARROW);
988          Dimension eoar = (Dimension) (LENGTH-1-soar);
989          if ((yb>=soar) && (yt<sosr))
990             PaintArrows(SBW,UPPER_ARROW,(SCROLLMODE==ARROW_UP)   ? INVERTED_ARROW : NORMAL_ARROW);
991          if ((yb>eosr) && (yt<=eoar))
992             PaintArrows(SBW,LOWER_ARROW,(SCROLLMODE==ARROW_DOWN) ? INVERTED_ARROW : NORMAL_ARROW);
993       }
994       if ((yb>=newtop) && (yt<=newbot)) {
995          if ((yt<=newtop+s) && (yb+s>=newbot))     PaintWholeThumb(SBW,newtop,newbot,xl,xr,s);
996          else if ((yt<=newtop+s) && (yb+s<newbot)) PaintEndOfThumb(SBW,newtop,yb,xl,xr,s,UPPER_PART);
997          else if ((yt>newtop+s) && (yb+s>=newbot)) PaintEndOfThumb(SBW,yt,newbot,xl,xr,s,LOWER_PART);
998          else if ((yt>newtop+s) && (yb+s<newbot))  PaintMiddleOfThumb(SBW,yt,yb,xl,xr,s);
999       }
1000    } else {
1001       /* should never come here */
1002       printf("  Scrollbarwidget: no event forced exit\n");
1003       clean_safe_tempdir();
1004       exit(0);
1005    }
1006    TOPLOC = newtop;
1007    SHOWNLENGTH = newbot-newtop+1;
1008 
1009    (*swclass->threeD_class.shadowdraw) (w, event, region, sbw->threeD.relief, FALSE);
1010 
1011    ENDMESSAGE(Redisplay)
1012 }
1013 
1014 /*###############################################################################
1015     Destroy
1016 ###############################################################################*/
1017 
Destroy(w)1018 static void Destroy (w)
1019     Widget w;
1020 {
1021     SCROLLBARWIDGET w;
1022     BEGINMESSAGE(Destroy)
1023     DESTROY_TIMER;
1024     XtReleaseGC (w, SCROLLBAR_GC);
1025     ENDMESSAGE(Destroy)
1026 }
1027 
1028 /*###############################################################################
1029    CompareEvents
1030 ###############################################################################*/
1031 
1032 #define CHECK(field) if (newEvent->field != oldEvent->field) return False;
1033 
CompareEvents(XEvent * oldEvent,XEvent * newEvent)1034 static Boolean CompareEvents (XEvent *oldEvent, XEvent *newEvent)
1035 {
1036     INFMESSAGE(executing Procedure: CompareEvents)
1037     CHECK(xany.display);
1038     CHECK(xany.type);
1039     CHECK(xany.window);
1040 
1041     switch (newEvent->type) {
1042     case MotionNotify:
1043 	CHECK(xmotion.state);
1044 	break;
1045     case ButtonPress:
1046     case ButtonRelease:
1047 	CHECK(xbutton.state);
1048 	CHECK(xbutton.button);
1049 	break;
1050     case KeyPress:
1051     case KeyRelease:
1052 	CHECK(xkey.state);
1053 	CHECK(xkey.keycode);
1054 	break;
1055     case EnterNotify:
1056     case LeaveNotify:
1057 	CHECK(xcrossing.mode);
1058 	CHECK(xcrossing.detail);
1059 	CHECK(xcrossing.state);
1060 	break;
1061     }
1062 
1063     return True;
1064 }
1065 
1066 /*###############################################################################
1067     PeekNotifyEvent
1068 ###############################################################################*/
1069 
1070 struct EventData {
1071    XEvent 	*oldEvent;
1072    int 		count;
1073 };
1074 
PeekNotifyEvent(Display * dpy,XEvent * event,char * args)1075 static Bool PeekNotifyEvent (Display *dpy, XEvent *event, char *args)
1076 {
1077    struct EventData *eventData = (struct EventData*)args;
1078    INFMESSAGE(executing Procedure: PeekNotifyEvent)
1079    return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */
1080    	    || CompareEvents(event, eventData->oldEvent));
1081 }
1082 
1083 /*###############################################################################
1084     LookAhead
1085 ###############################################################################*/
1086 
LookAhead(Widget w,XEvent * event)1087 static Boolean LookAhead (Widget w, XEvent *event)
1088 {
1089    XEvent 	newEvent;
1090    struct 	EventData eventData;
1091 
1092    BEGINMESSAGE(LookAhead)
1093    if (QLength (XtDisplay (w)) == 0) {
1094       INFMESSAGE(aborting) ENDMESSAGE(LookAhead)
1095       return False;
1096    }
1097 
1098    eventData.count = 0;
1099    eventData.oldEvent = event;
1100 
1101    XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
1102 
1103    ENDMESSAGE(LookAhead)
1104    return CompareEvents (event, &newEvent);
1105 }
1106 
1107 /*###############################################################################
1108     ExtractPosition
1109 ###############################################################################*/
1110 
1111 #define GET_EVENT_POS(kind) *position = (is_vertical) ? event->kind.y : event->kind.x
1112 
ExtractPosition(XEvent * event,Position * position,Boolean is_vertical)1113 static void ExtractPosition(XEvent *event, Position *position, Boolean is_vertical)
1114 {
1115    BEGINMESSAGE(ExtractPosition)
1116    switch( event->type ) {
1117    case MotionNotify:
1118       GET_EVENT_POS(xmotion);    break;
1119    case ButtonPress:
1120    case ButtonRelease:
1121       GET_EVENT_POS(xbutton);    break;
1122    case KeyPress:
1123    case KeyRelease:
1124       GET_EVENT_POS(xkey);       break;
1125    case EnterNotify:
1126    case LeaveNotify:
1127       GET_EVENT_POS(xcrossing);  break;
1128    default:
1129       *position = 0;
1130    }
1131    ENDMESSAGE(ExtractPosition)
1132 }
1133 
1134 /*###############################################################################
1135     HandleThumb
1136 ###############################################################################*/
1137 
HandleThumb(Widget w,XEvent * event,String * params,Cardinal * num_params)1138 static void HandleThumb (Widget w, XEvent *event, String *params, Cardinal *num_params)
1139 {
1140    SCROLLBARWIDGET w;
1141    Position position;
1142    Position teoar = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT-1;
1143    Position beoar = (Position) LENGTH-teoar+1;
1144 
1145    BEGINMESSAGE(HandleThumb)
1146    if ((SCROLLMODE != NOSCROLL) && (SCROLLMODE != CONTINUOUS)) {
1147       INFMESSAGE(aborting due to wrong scrollmode) ENDMESSAGE(HandleThumb)
1148       return;
1149    }
1150 
1151    ExtractPosition(event,&position,(IS_VERTICAL));
1152    if ( (SCROLLMODE==CONTINUOUS) ||
1153         ((position >= TOPLOC) && (position < TOPLOC + SHOWNLENGTH)
1154           && (position>teoar) && (position<beoar)) ) {
1155       XtCallActionProc(w, "MoveThumb", event, params, *num_params);
1156       XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
1157    }
1158    ENDMESSAGE(HandleThumb)
1159 }
1160 
1161 /*###############################################################################
1162     HandleAutoscroll
1163 ###############################################################################*/
1164 
HandleAutoscroll(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params)1165 static void HandleAutoscroll(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params)
1166 {
1167    SCROLLBARWIDGET w;
1168    static Position old_position;
1169    Position position;
1170    int diff;
1171    float rel_diff;
1172 
1173    BEGINMESSAGE(HandleAutoscroll)
1174 
1175    if ((SCROLLMODE != ARROW_UP) && (SCROLLMODE != ARROW_DOWN)) {
1176       INFMESSAGE(returning due to wrong scroll mode) ENDMESSAGE(HandleAutoscroll)
1177       return;
1178    }
1179    if (!USE_DYNAMIC) {
1180       DYNAMIC = INTERVAL;
1181       ENDMESSAGE(HandleAutoscroll)
1182       return;
1183    }
1184 
1185    ExtractPosition(event,&position,(IS_VERTICAL));
1186    if (*num_params == _SC_INIT_VALUE_) {
1187       INFMESSAGE(... initializing)
1188       old_position = position;
1189       ENDMESSAGE(HandleAutoscroll)
1190       return;
1191    }
1192 
1193    DYNAMIC = PUT_IN_RANGE(MIN_INTERVAL,DYNAMIC,MAX_INTERVAL);   IMESSAGE(DYNAMIC)
1194    diff = (SCROLLMODE==ARROW_UP) ? ((int)position)-((int)old_position):((int)old_position)-((int)position);
1195    rel_diff = PUT_IN_RANGE(-1.0,((float)diff)/DYNAMIC_REGION,1.0);
1196    if (rel_diff>0) DYNAMIC = INTERVAL + (Dimension)((MAX_INTERVAL-(int)INTERVAL)*rel_diff);
1197    else            DYNAMIC = INTERVAL + (Dimension)((MIN_INTERVAL-(int)INTERVAL)*(-rel_diff));
1198    IMESSAGE(DYNAMIC)
1199 
1200    ENDMESSAGE(HandleAutoscroll)
1201 }
1202 
1203 /*###############################################################################
1204     RepeatNotify
1205 ###############################################################################*/
1206 
RepeatNotify(XtPointer client_data,XtIntervalId * idp _GL_UNUSED)1207 static void RepeatNotify (XtPointer client_data, XtIntervalId *idp _GL_UNUSED)
1208 {
1209     SCROLLBARWIDGET client_data;
1210     int call_data=0;
1211 
1212     BEGINMESSAGE(RepeatNotify)
1213     if (SCROLLMODE == NOSCROLL || SCROLLMODE == CONTINUOUS) {
1214 	DESTROY_TIMER;
1215         INFMESSAGE(aborting due to wrong scroll_mode) ENDMESSAGE(RepeatNotify)
1216 	return;
1217     }
1218 
1219     switch (SCROLLMODE) {
1220        case ARROW_UP:
1221             call_data = -ARROW_SCROLL_AMOUNT;
1222             break;
1223        case ARROW_DOWN:
1224             call_data = ARROW_SCROLL_AMOUNT;
1225             break;
1226        case PAGE_UP:
1227             call_data = -PAGE_SCROLL_AMOUNT;
1228             break;
1229        case PAGE_DOWN:
1230             call_data = PAGE_SCROLL_AMOUNT;
1231             break;
1232     }
1233 
1234     CALLscrollProc(client_data,call_data);
1235     SET_TIMER( client_data, DYNAMIC);
1236 
1237     ENDMESSAGE(RepeatNotify)
1238 }
1239 
1240 /*###############################################################################
1241     NotifyScroll
1242 ###############################################################################*/
1243 
1244 
NotifyScroll(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1245 static void NotifyScroll(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1246 {
1247     SCROLLBARWIDGET w;
1248     Position tsoar = (Position) ARROW_TOP_TO_BORDER;
1249     Position teoar = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT-1;
1250     Position beoar = (Position) LENGTH-teoar+1;
1251     Position bsoar = (Position) LENGTH-tsoar-1;
1252     Position position;
1253     Cardinal init_num_params = _SC_INIT_VALUE_;
1254 
1255     BEGINMESSAGE(NotifyScroll)
1256 
1257     if (SCROLLMODE==CONTINUOUS) {
1258        INFMESSAGE(aborting since CONTINUOUS scroll in progress) ENDMESSAGE(NotifyScroll)
1259        return;
1260     }
1261 
1262     ExtractPosition(event,&position,(IS_VERTICAL));
1263     if ((position>=tsoar) && (position <= teoar)) {
1264         if (SHOW_ARROWS) {                              INFMESSAGE(handle upper/left arrow)
1265            PaintArrows(SBW,UPPER_ARROW,INVERTED_ARROW);
1266 	   SCROLLMODE = ARROW_UP;
1267            CALLscrollProc(w,((int)-ARROW_SCROLL_AMOUNT));
1268            DYNAMIC = INTERVAL;
1269            HandleAutoscroll(w, event, NULL, &init_num_params);
1270            SET_TIMER(w,DELAY);
1271         }
1272     } else if ((position >= beoar) && (position<=bsoar)) {
1273         if (SHOW_ARROWS) {                              INFMESSAGE(handle lower/right arrow)
1274            PaintArrows(SBW,LOWER_ARROW,INVERTED_ARROW);
1275 	   SCROLLMODE = ARROW_DOWN;
1276            CALLscrollProc(w,((int)ARROW_SCROLL_AMOUNT));
1277            DYNAMIC = INTERVAL;
1278            HandleAutoscroll(w, event, NULL, &init_num_params);
1279            SET_TIMER(w,DELAY);
1280         }
1281     } else if ((position>teoar) &&(position < TOPLOC)) { INFMESSAGE(handle Zone above Thumb)
1282 	SCROLLMODE = PAGE_UP;
1283         CALLscrollProc(w,((int)-PAGE_SCROLL_AMOUNT));
1284         DYNAMIC = INTERVAL;
1285         SET_TIMER(w,DELAY);
1286     } else if ((position<beoar)&&(position > TOPLOC + SHOWNLENGTH)) { INFMESSAGE(handle Zone below Thumb)
1287 	SCROLLMODE = PAGE_DOWN;
1288         CALLscrollProc(w,((int)PAGE_SCROLL_AMOUNT));
1289         DYNAMIC = INTERVAL;
1290         SET_TIMER(w,DELAY);
1291     }
1292     ENDMESSAGE(NotifyScroll);
1293 }
1294 
1295 /*###############################################################################
1296     EndScroll
1297 ###############################################################################*/
1298 
1299 /* ARGSUSED */
EndScroll(Widget w,XEvent * event _GL_UNUSED,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1300 static void EndScroll(Widget w, XEvent *event _GL_UNUSED, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1301 {
1302     SCROLLBARWIDGET w;
1303 
1304     BEGINMESSAGE(EndScroll)
1305     if (SHOW_ARROWS) {
1306        if (SCROLLMODE==ARROW_UP)   PaintArrows(SBW,UPPER_ARROW,NORMAL_ARROW);
1307        if (SCROLLMODE==ARROW_DOWN) PaintArrows(SBW,LOWER_ARROW,NORMAL_ARROW);
1308     }
1309     SCROLLMODE=NOSCROLL;
1310     DESTROY_TIMER;
1311     ENDMESSAGE(EndScroll)
1312 }
1313 
1314 /*###############################################################################
1315     MoveThumb
1316 ###############################################################################*/
1317 
MoveThumb(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1318 static void MoveThumb(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1319 {
1320    SCROLLBARWIDGET w;
1321    Position position;
1322    static Position old_position;
1323    float losr         = (float)(_SCROLL_LENGTH_-MIN_THUMB);
1324    Position tosr = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW;
1325    Position bosr = (Position) LENGTH-1-tosr;
1326    BEGINMESSAGE(MoveThumb)
1327    if (LookAhead (w, event)) {
1328       INFMESSAGE(aborting due to LookAhead) ENDMESSAGE(MoveThumb)
1329       return;
1330    }
1331 
1332    if (!event->xmotion.same_screen) {
1333       INFMESSAGE(aborting due to wrong screen) ENDMESSAGE(MoveThumb)
1334       return;
1335    }
1336 
1337    ExtractPosition(event,&position,(IS_VERTICAL));
1338    position = PUT_IN_RANGE(tosr,position,bosr);
1339 
1340    if (SCROLLMODE != CONTINUOUS) {
1341        if ((position < TOPLOC) || (position >= TOPLOC + SHOWNLENGTH)) {
1342          TOP = PUT_IN_RANGE(0.0,((float)(position-tosr))/losr, 1.0-SHOWN);
1343         }
1344       SCROLLMODE=CONTINUOUS;
1345    } else {
1346       TOP = PUT_IN_RANGE(0.0,TOP+((float)(position-old_position))/losr, 1.0-SHOWN);
1347    }
1348    old_position = position;
1349    PaintThumb(SBW);
1350    XFlush(XtDisplay (w));
1351    ENDMESSAGE(MoveThumb)
1352 }
1353 
1354 /*###############################################################################
1355     NotifyThumb
1356 ###############################################################################*/
1357 
NotifyThumb(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1358 static void NotifyThumb(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1359 {
1360    register SCROLLBARWIDGET w;
1361 
1362    BEGINMESSAGE(NotifyThumb)
1363    if (LookAhead (w, event)) {
1364       INFMESSAGE(returning due to LookAhead) ENDMESSAGE(NotifyThumb)
1365       return;
1366    }
1367     /*
1368        thumbProc is not pretty, but is necessary for backwards
1369        compatibility on those architectures for which it work{s,ed};
1370        the intent is to pass a (truncated) float by value.
1371     */
1372    XtCallCallbacks (w, XtNthumbProc, *(XtPointer*)&TOP);
1373    XtCallCallbacks (w, XtNjumpProc, (XtPointer)&TOP);
1374    ENDMESSAGE(NotifyThumb)
1375 }
1376 
1377 /********************************************************************************
1378  *
1379  *  Public routines.
1380  *
1381  *******************************************************************************/
1382 
1383 /*###############################################################################
1384     XawScrollbarSetThumb
1385     Set the scroll bar to the given location.
1386 ###############################################################################*/
1387 
XawScrollbarSetThumb(Widget w,double top,double shown)1388 void XawScrollbarSetThumb (Widget w,
1389 #if NeedWidePrototypes
1390                                      double top, double shown
1391 #else
1392                                      float top, float shown
1393 #endif
1394                           )
1395 {
1396    SCROLLBARWIDGET w;
1397 
1398    BEGINMESSAGE(XawScrollbarSetThumb)
1399 
1400    if (SCROLLMODE == CONTINUOUS) {
1401       INFMESSAGE(aborting since CONTINUOUS scroll in progress) ENDMESSAGE(XawScrollbarSetThumb)
1402       return;
1403    }
1404 
1405    SHOWN       = PUT_IN_RANGE(0.0,shown,1.0);  FMESSAGE(SHOWN)
1406    TOP         = PUT_IN_RANGE(0.0,top,  1.0);  FMESSAGE(TOP)
1407    PaintThumb(SBW);
1408 
1409    ENDMESSAGE(XawScrollbarSetThumb)
1410 }
1411 
1412