Merge branch 'vim'
[vim_extended.git] / src / gui_at_sb.c
blob16d8d36fa4bffa32e0accfb765985ef7e7986b9a
1 /* vi:set ts=8 sts=4 sw=4: */
2 /*
3 * MODIFIED ATHENA SCROLLBAR (USING ARROWHEADS AT ENDS OF TRAVEL)
4 * Modifications Copyright 1992 by Mitch Trachtenberg
5 * Rights, permissions, and disclaimer of warranty are as in the DEC and MIT
6 * notice below.
7 * $XConsortium: Scrollbar.c,v 1.72 94/04/17 20:12:40 kaleb Exp $
8 */
11 * Modified for Vim by Bill Foster and Bram Moolenaar
16 Copyright (c) 1987, 1988, 1994 X Consortium
18 Permission is hereby granted, free of charge, to any person obtaining a copy
19 of this software and associated documentation files (the "Software"), to deal
20 in the Software without restriction, including without limitation the rights
21 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 copies of the Software, and to permit persons to whom the Software is
23 furnished to do so, subject to the following conditions:
25 The above copyright notice and this permission notice shall be included in all
26 copies or substantial portions of the Software.
28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
31 CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 Except as contained in this notice, the name of the X Consortium shall not be
36 used in advertising or otherwise to promote the sale, use or other dealings in
37 this Software without prior written authorization from the X Consortium.
39 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
41 All Rights Reserved
43 Permission to use, copy, modify, and distribute this software and its
44 documentation for any purpose and without fee is hereby granted, provided that
45 the above copyright notice appear in all copies and that both that copyright
46 notice and this permission notice appear in supporting documentation, and that
47 the name of Digital not be used in advertising or publicity pertaining to
48 distribution of the software without specific, written prior permission.
50 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL
52 BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54 OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
59 /* ScrollBar.c */
60 /* created by weissman, Mon Jul 7 13:20:03 1986 */
61 /* converted by swick, Thu Aug 27 1987 */
63 #include <X11/IntrinsicP.h>
64 #include <X11/StringDefs.h>
66 #include <X11/Xaw/XawInit.h>
67 #include "vim.h"
68 #include "gui_at_sb.h"
70 #include <X11/Xmu/Drawing.h>
72 /* Private definitions. */
74 static char defaultTranslations[] =
75 "<Btn1Down>: NotifyScroll()\n\
76 <Btn2Down>: MoveThumb() NotifyThumb()\n\
77 <Btn3Down>: NotifyScroll()\n\
78 <Btn4Down>: ScrollOneLineUp()\n\
79 Shift<Btn4Down>: ScrollPageUp()\n\
80 <Btn5Down>: ScrollOneLineDown()\n\
81 Shift<Btn5Down>: ScrollPageDown()\n\
82 <Btn1Motion>: HandleThumb()\n\
83 <Btn3Motion>: HandleThumb()\n\
84 <Btn2Motion>: MoveThumb() NotifyThumb()\n\
85 <BtnUp>: EndScroll()";
87 static float floatZero = 0.0;
89 #define Offset(field) XtOffsetOf(ScrollbarRec, field)
91 static XtResource resources[] =
93 {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
94 Offset(scrollbar.length), XtRImmediate, (XtPointer) 1},
95 {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
96 Offset(scrollbar.thickness), XtRImmediate, (XtPointer) 14},
97 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
98 Offset(scrollbar.orientation), XtRImmediate, (XtPointer) XtorientVertical},
99 {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
100 Offset(scrollbar.scrollProc), XtRCallback, NULL},
101 {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
102 Offset(scrollbar.thumbProc), XtRCallback, NULL},
103 {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
104 Offset(scrollbar.jumpProc), XtRCallback, NULL},
105 {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
106 Offset(scrollbar.thumb), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
107 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
108 Offset(scrollbar.foreground), XtRString, XtDefaultForeground},
109 {XtNshown, XtCShown, XtRFloat, sizeof(float),
110 Offset(scrollbar.shown), XtRFloat, (XtPointer)&floatZero},
111 {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
112 Offset(scrollbar.top), XtRFloat, (XtPointer)&floatZero},
113 {XtNmaxOfThumb, XtCMaxOfThumb, XtRFloat, sizeof(float),
114 Offset(scrollbar.max), XtRFloat, (XtPointer)&floatZero},
115 {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
116 Offset(scrollbar.min_thumb), XtRImmediate, (XtPointer) 7},
117 {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
118 Offset(scrollbar.shadow_width), XtRImmediate, (XtPointer) 1},
119 {XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
120 Offset(scrollbar.top_shadow_pixel), XtRString, XtDefaultBackground},
121 {XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
122 Offset(scrollbar.bot_shadow_pixel), XtRString, XtDefaultForeground},
123 {XtNlimitThumb, XtCLimitThumb, XtRBool, sizeof(Bool),
124 Offset(scrollbar.limit_thumb), XtRImmediate, (XtPointer)0}
126 #undef Offset
128 static void ClassInitialize __ARGS((void));
129 static void Initialize __ARGS((Widget, Widget, ArgList, Cardinal *));
130 static void Destroy __ARGS((Widget));
131 static void Realize __ARGS((Widget, Mask *, XSetWindowAttributes *));
132 static void Resize __ARGS((Widget));
133 static void Redisplay __ARGS((Widget, XEvent *, Region));
134 static Boolean SetValues __ARGS((Widget, Widget, Widget, ArgList, Cardinal *));
136 static void HandleThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
137 static void MoveThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
138 static void NotifyThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
139 static void NotifyScroll __ARGS((Widget, XEvent *, String *, Cardinal *));
140 static void EndScroll __ARGS((Widget, XEvent *, String *, Cardinal *));
141 static void ScrollOneLineUp __ARGS((Widget, XEvent *, String *, Cardinal *));
142 static void ScrollOneLineDown __ARGS((Widget, XEvent *, String *, Cardinal *));
143 static void ScrollPageUp __ARGS((Widget, XEvent *, String *, Cardinal *));
144 static void ScrollPageDown __ARGS((Widget, XEvent *, String *, Cardinal *));
145 static void ScrollSome __ARGS((Widget w, XEvent *event, int call_data));
146 static void _Xaw3dDrawShadows __ARGS((Widget, XEvent *, Region, int));
147 static void AllocTopShadowGC __ARGS((Widget));
148 static void AllocBotShadowGC __ARGS((Widget));
150 static XtActionsRec actions[] =
152 {"HandleThumb", HandleThumb},
153 {"MoveThumb", MoveThumb},
154 {"NotifyThumb", NotifyThumb},
155 {"NotifyScroll", NotifyScroll},
156 {"EndScroll", EndScroll},
157 {"ScrollOneLineUp", ScrollOneLineUp},
158 {"ScrollOneLineDown", ScrollOneLineDown},
159 {"ScrollPageUp", ScrollPageUp},
160 {"ScrollPageDown", ScrollPageDown}
164 ScrollbarClassRec vim_scrollbarClassRec =
166 { /* core fields */
167 /* superclass */ (WidgetClass) &simpleClassRec,
168 /* class_name */ "Scrollbar",
169 /* size */ sizeof(ScrollbarRec),
170 /* class_initialize */ ClassInitialize,
171 /* class_part_init */ NULL,
172 /* class_inited */ FALSE,
173 /* initialize */ Initialize,
174 /* initialize_hook */ NULL,
175 /* realize */ Realize,
176 /* actions */ actions,
177 /* num_actions */ XtNumber(actions),
178 /* resources */ resources,
179 /* num_resources */ XtNumber(resources),
180 /* xrm_class */ NULLQUARK,
181 /* compress_motion */ TRUE,
182 /* compress_exposure*/ TRUE,
183 /* compress_enterleave*/ TRUE,
184 /* visible_interest */ FALSE,
185 /* destroy */ Destroy,
186 /* resize */ Resize,
187 /* expose */ Redisplay,
188 /* set_values */ SetValues,
189 /* set_values_hook */ NULL,
190 /* set_values_almost */ XtInheritSetValuesAlmost,
191 /* get_values_hook */ NULL,
192 /* accept_focus */ NULL,
193 /* version */ XtVersion,
194 /* callback_private */ NULL,
195 /* tm_table */ defaultTranslations,
196 /* query_geometry */ XtInheritQueryGeometry,
197 /* display_accelerator*/ XtInheritDisplayAccelerator,
198 /* extension */ NULL
200 { /* simple fields */
201 /* change_sensitive */ XtInheritChangeSensitive,
202 #ifndef OLDXAW
203 /* extension */ NULL
204 #endif
206 { /* scrollbar fields */
207 /* empty */ 0
211 WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
213 #define NoButton -1
214 #define PICKLENGTH(widget, x, y) \
215 ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
216 #define AT_MIN(x,y) ((x) < (y) ? (x) : (y))
217 #define AT_MAX(x,y) ((x) > (y) ? (x) : (y))
219 #define LINE_DELAY 300
220 #define PAGE_DELAY 300
221 #define LINE_REPEAT 50
222 #define PAGE_REPEAT 250
224 static void
225 ClassInitialize()
227 XawInitializeWidgetSet();
228 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
229 (XtConvertArgList)NULL, (Cardinal)0 );
232 #define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
234 static void
235 FillArea(sbw, top, bottom, fill, draw_shadow)
236 ScrollbarWidget sbw;
237 Position top, bottom;
238 int fill;
239 int draw_shadow;
241 int tlen = bottom - top; /* length of thumb in pixels */
242 int sw, margin, floor;
243 int lx, ly, lw, lh;
245 if (bottom <= 0 || bottom <= top)
246 return;
247 sw = sbw->scrollbar.shadow_width;
248 if (sw < 0)
249 sw = 0;
250 margin = MARGIN (sbw);
251 floor = sbw->scrollbar.length - margin + 2;
253 if (sbw->scrollbar.orientation == XtorientHorizontal)
255 lx = ((top < margin) ? margin : top);
256 ly = sw;
257 lw = (((top + tlen) > floor) ? floor - top : tlen);
258 lh = sbw->core.height - 2 * sw;
260 else
262 lx = sw;
263 ly = ((top < margin) ? margin : top);
264 lw = sbw->core.width - 2 * sw;
265 lh = (((top + tlen) > floor) ? floor - top : tlen);
267 if (lh <= 0 || lw <= 0)
268 return;
270 if (draw_shadow)
272 if (!(sbw->scrollbar.orientation == XtorientHorizontal))
274 /* Top border */
275 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
276 sbw->scrollbar.top_shadow_GC,
277 lx, ly, lx + lw - 1, ly);
279 /* Bottom border */
280 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
281 sbw->scrollbar.bot_shadow_GC,
282 lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
284 else
286 /* Left border */
287 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
288 sbw->scrollbar.top_shadow_GC,
289 lx, ly, lx, ly + lh - 1);
291 /* Right border */
292 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
293 sbw->scrollbar.bot_shadow_GC,
294 lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
296 return;
299 if (fill)
301 XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
302 sbw->scrollbar.gc,
303 lx, ly, (unsigned int) lw, (unsigned int) lh);
305 if (!(sbw->scrollbar.orientation == XtorientHorizontal))
307 /* Left border */
308 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
309 sbw->scrollbar.top_shadow_GC,
310 lx, ly, lx, ly + lh - 1);
312 /* Right border */
313 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
314 sbw->scrollbar.bot_shadow_GC,
315 lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
317 else
319 /* Top border */
320 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
321 sbw->scrollbar.top_shadow_GC,
322 lx, ly, lx + lw - 1, ly);
324 /* Bottom border */
325 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
326 sbw->scrollbar.bot_shadow_GC,
327 lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
330 else
332 XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
333 lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE);
337 /* Paint the thumb in the area specified by sbw->top and
338 sbw->shown. The old area is erased. The painting and
339 erasing is done cleverly so that no flickering will occur.
342 static void
343 PaintThumb(sbw)
344 ScrollbarWidget sbw;
346 Position oldtop, oldbot, newtop, newbot;
347 Dimension margin, tzl;
349 margin = MARGIN (sbw);
350 tzl = sbw->scrollbar.length - 2 * margin;
351 newtop = margin + (int)(tzl * sbw->scrollbar.top);
352 newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
353 if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
354 newbot = newtop + sbw->scrollbar.min_thumb;
356 oldtop = sbw->scrollbar.topLoc;
357 oldbot = oldtop + sbw->scrollbar.shownLength;
358 sbw->scrollbar.topLoc = newtop;
359 sbw->scrollbar.shownLength = newbot - newtop;
360 if (XtIsRealized ((Widget) sbw))
362 if (newtop < oldtop)
363 FillArea(sbw, newtop, AT_MIN(newbot, oldtop+1),1,0);
364 if (newtop > oldtop)
365 FillArea(sbw, oldtop, AT_MIN(newtop, oldbot ),0,0);
366 if (newbot < oldbot)
367 FillArea(sbw, AT_MAX(newbot, oldtop), oldbot, 0,0);
368 if (newbot > oldbot)
369 FillArea(sbw, AT_MAX(newtop, oldbot-1), newbot, 1,0);
371 /* Only draw the missing shadows */
372 FillArea(sbw, newtop, newbot, 0, 1);
376 static void
377 PaintArrows(sbw)
378 ScrollbarWidget sbw;
380 XPoint point[6];
381 Dimension thickness = sbw->scrollbar.thickness - 1;
382 Dimension size;
383 Dimension off;
385 if (XtIsRealized((Widget) sbw))
387 if ((int)thickness * 2 > (int)sbw->scrollbar.length)
389 size = sbw->scrollbar.length / 2;
390 off = (int)(thickness - size) / 2;
392 else
394 size = thickness;
395 off = 0;
397 point[0].x = off + sbw->scrollbar.shadow_width;
398 point[0].y = size;
399 point[1].x = thickness - off - sbw->scrollbar.shadow_width;
400 point[1].y = size;
401 point[2].x = thickness / 2;
402 point[2].y = sbw->scrollbar.shadow_width;
404 point[3].x = off + sbw->scrollbar.shadow_width;
405 point[3].y = sbw->scrollbar.length - size;
406 point[4].x = thickness - off - sbw->scrollbar.shadow_width;
407 point[4].y = sbw->scrollbar.length - size;
408 point[5].x = thickness / 2;
409 point[5].y = sbw->scrollbar.length - sbw->scrollbar.shadow_width - 1;
411 /* horizontal arrows require that x and y coordinates be swapped */
412 if (sbw->scrollbar.orientation == XtorientHorizontal)
414 int n;
415 int swap;
416 for (n = 0; n < 6; n++)
418 swap = point[n].x;
419 point[n].x = point[n].y;
420 point[n].y = swap;
423 /* draw the up/left arrow */
424 XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
425 sbw->scrollbar.gc,
426 point, 3,
427 Convex, CoordModeOrigin);
428 XDrawLines (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
429 sbw->scrollbar.bot_shadow_GC,
430 point, 3,
431 CoordModeOrigin);
432 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
433 sbw->scrollbar.top_shadow_GC,
434 point[0].x, point[0].y,
435 point[2].x, point[2].y);
436 /* draw the down/right arrow */
437 XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
438 sbw->scrollbar.gc,
439 point+3, 3,
440 Convex, CoordModeOrigin);
441 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
442 sbw->scrollbar.top_shadow_GC,
443 point[3].x, point[3].y,
444 point[4].x, point[4].y);
445 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
446 sbw->scrollbar.top_shadow_GC,
447 point[3].x, point[3].y,
448 point[5].x, point[5].y);
449 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
450 sbw->scrollbar.bot_shadow_GC,
451 point[4].x, point[4].y,
452 point[5].x, point[5].y);
456 static void
457 Destroy(w)
458 Widget w;
460 ScrollbarWidget sbw = (ScrollbarWidget) w;
461 if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
462 XtRemoveTimeOut (sbw->scrollbar.timer_id);
463 XtReleaseGC(w, sbw->scrollbar.gc);
464 XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
465 XtReleaseGC(w, sbw->scrollbar.bot_shadow_GC);
468 static void
469 CreateGC(w)
470 Widget w;
472 ScrollbarWidget sbw = (ScrollbarWidget) w;
473 XGCValues gcValues;
474 XtGCMask mask;
475 unsigned int depth = 1;
477 if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
479 sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w),
480 (Pixel) 1, (Pixel) 0, depth);
482 else if (sbw->scrollbar.thumb != None)
484 Window root;
485 int x, y;
486 unsigned int width, height, bw;
488 if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
489 &width, &height, &bw, &depth) == 0)
490 EMSG(_("Scrollbar Widget: Could not get geometry of thumb pixmap."));
493 gcValues.foreground = sbw->scrollbar.foreground;
494 gcValues.background = sbw->core.background_pixel;
495 mask = GCForeground | GCBackground;
497 if (sbw->scrollbar.thumb != None)
499 gcValues.fill_style = FillSolid;
500 mask |= GCFillStyle;
502 /* the creation should be non-caching, because */
503 /* we now set and clear clip masks on the gc returned */
504 sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
507 static void
508 SetDimensions(sbw)
509 ScrollbarWidget sbw;
511 if (sbw->scrollbar.orientation == XtorientVertical)
513 sbw->scrollbar.length = sbw->core.height;
514 sbw->scrollbar.thickness = sbw->core.width;
516 else
518 sbw->scrollbar.length = sbw->core.width;
519 sbw->scrollbar.thickness = sbw->core.height;
523 static void
524 Initialize(request, new, args, num_args)
525 Widget request UNUSED; /* what the client asked for */
526 Widget new; /* what we're going to give him */
527 ArgList args UNUSED;
528 Cardinal *num_args UNUSED;
530 ScrollbarWidget sbw = (ScrollbarWidget) new;
532 CreateGC(new);
533 AllocTopShadowGC(new);
534 AllocBotShadowGC(new);
536 if (sbw->core.width == 0)
537 sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
538 ? sbw->scrollbar.thickness : sbw->scrollbar.length;
540 if (sbw->core.height == 0)
541 sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
542 ? sbw->scrollbar.thickness : sbw->scrollbar.length;
544 SetDimensions(sbw);
545 sbw->scrollbar.scroll_mode = SMODE_NONE;
546 sbw->scrollbar.timer_id = (XtIntervalId)0;
547 sbw->scrollbar.topLoc = 0;
548 sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
551 static void
552 Realize(w, valueMask, attributes)
553 Widget w;
554 Mask *valueMask;
555 XSetWindowAttributes *attributes;
557 /* The Simple widget actually stuffs the value in the valuemask. */
558 (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
559 (w, valueMask, attributes);
562 static Boolean
563 SetValues(current, request, desired, args, num_args)
564 Widget current; /* what I am */
565 Widget request UNUSED; /* what he wants me to be */
566 Widget desired; /* what I will become */
567 ArgList args UNUSED;
568 Cardinal *num_args UNUSED;
570 ScrollbarWidget sbw = (ScrollbarWidget) current;
571 ScrollbarWidget dsbw = (ScrollbarWidget) desired;
572 Boolean redraw = FALSE;
575 * If these values are outside the acceptable range ignore them...
577 if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
578 dsbw->scrollbar.top = sbw->scrollbar.top;
580 if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
581 dsbw->scrollbar.shown = sbw->scrollbar.shown;
584 * Change colors and stuff...
586 if (XtIsRealized(desired))
588 if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
589 sbw->core.background_pixel != dsbw->core.background_pixel ||
590 sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
592 XtReleaseGC(desired, sbw->scrollbar.gc);
593 CreateGC (desired);
594 redraw = TRUE;
596 if (sbw->scrollbar.top != dsbw->scrollbar.top ||
597 sbw->scrollbar.shown != dsbw->scrollbar.shown)
598 redraw = TRUE;
600 return redraw;
603 static void
604 Resize(w)
605 Widget w;
607 /* ForgetGravity has taken care of background, but thumb may
608 * have to move as a result of the new size. */
609 SetDimensions ((ScrollbarWidget) w);
610 Redisplay(w, (XEvent*) NULL, (Region)NULL);
614 static void
615 Redisplay(w, event, region)
616 Widget w;
617 XEvent *event;
618 Region region;
620 ScrollbarWidget sbw = (ScrollbarWidget) w;
621 int x, y;
622 unsigned int width, height;
624 _Xaw3dDrawShadows(w, event, region, FALSE);
626 if (sbw->scrollbar.orientation == XtorientHorizontal)
628 x = sbw->scrollbar.topLoc;
629 y = 1;
630 width = sbw->scrollbar.shownLength;
631 height = sbw->core.height - 2;
633 else
635 x = 1;
636 y = sbw->scrollbar.topLoc;
637 width = sbw->core.width - 2;
638 height = sbw->scrollbar.shownLength;
640 if (region == NULL ||
641 XRectInRegion (region, x, y, width, height) != RectangleOut)
643 /* Forces entire thumb to be painted. */
644 sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
645 PaintThumb (sbw);
647 /* we'd like to be region aware here!!!! */
648 PaintArrows(sbw);
652 static Boolean
653 CompareEvents(oldEvent, newEvent)
654 XEvent *oldEvent, *newEvent;
656 #define Check(field) if (newEvent->field != oldEvent->field) return False;
658 Check(xany.display);
659 Check(xany.type);
660 Check(xany.window);
662 switch (newEvent->type)
664 case MotionNotify:
665 Check(xmotion.state);
666 break;
667 case ButtonPress:
668 case ButtonRelease:
669 Check(xbutton.state);
670 Check(xbutton.button);
671 break;
672 case KeyPress:
673 case KeyRelease:
674 Check(xkey.state);
675 Check(xkey.keycode);
676 break;
677 case EnterNotify:
678 case LeaveNotify:
679 Check(xcrossing.mode);
680 Check(xcrossing.detail);
681 Check(xcrossing.state);
682 break;
684 #undef Check
686 return True;
689 struct EventData
691 XEvent *oldEvent;
692 int count;
695 static Bool
696 PeekNotifyEvent(dpy, event, args)
697 Display *dpy;
698 XEvent *event;
699 char *args;
701 struct EventData *eventData = (struct EventData*)args;
703 return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */
704 || CompareEvents(event, eventData->oldEvent));
708 static Boolean
709 LookAhead(w, event)
710 Widget w;
711 XEvent *event;
713 XEvent newEvent;
714 struct EventData eventData;
716 if (QLength (XtDisplay (w)) == 0)
717 return False;
719 eventData.count = 0;
720 eventData.oldEvent = event;
722 XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
724 return CompareEvents (event, &newEvent);
728 static void
729 ExtractPosition(event, x, y, state)
730 XEvent *event;
731 Position *x, *y; /* RETURN */
732 unsigned int *state; /* RETURN */
734 switch (event->type)
736 case MotionNotify:
737 *x = event->xmotion.x;
738 *y = event->xmotion.y;
739 if (state != NULL)
740 *state = event->xmotion.state;
741 break;
742 case ButtonPress:
743 case ButtonRelease:
744 *x = event->xbutton.x;
745 *y = event->xbutton.y;
746 if (state != NULL)
747 *state = event->xbutton.state;
748 break;
749 case KeyPress:
750 case KeyRelease:
751 *x = event->xkey.x;
752 *y = event->xkey.y;
753 if (state != NULL)
754 *state = event->xkey.state;
755 break;
756 case EnterNotify:
757 case LeaveNotify:
758 *x = event->xcrossing.x;
759 *y = event->xcrossing.y;
760 if (state != NULL)
761 *state = event->xcrossing.state;
762 break;
763 default:
764 *x = 0; *y = 0;
765 if (state != NULL)
766 *state = 0;
770 static void
771 HandleThumb(w, event, params, num_params)
772 Widget w;
773 XEvent *event;
774 String *params;
775 Cardinal *num_params;
777 Position x, y, loc;
778 ScrollbarWidget sbw = (ScrollbarWidget) w;
780 ExtractPosition(event, &x, &y, (unsigned int *)NULL);
781 loc = PICKLENGTH(sbw, x, y);
782 /* if the motion event puts the pointer in thumb, call Move and Notify */
783 /* also call Move and Notify if we're already in continuous scroll mode */
784 if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
785 (loc >= sbw->scrollbar.topLoc &&
786 loc <= sbw->scrollbar.topLoc + (int)sbw->scrollbar.shownLength))
788 XtCallActionProc(w, "MoveThumb", event, params, *num_params);
789 XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
793 static void
794 RepeatNotify(client_data, idp)
795 XtPointer client_data;
796 XtIntervalId *idp UNUSED;
798 ScrollbarWidget sbw = (ScrollbarWidget) client_data;
799 int call_data;
800 char mode = sbw->scrollbar.scroll_mode;
801 unsigned long rep;
803 if (mode == SMODE_NONE || mode == SMODE_CONT)
805 sbw->scrollbar.timer_id = (XtIntervalId)0;
806 return;
809 if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
811 call_data = ONE_LINE_DATA;
812 rep = LINE_REPEAT;
814 else
816 call_data = ONE_PAGE_DATA;
817 rep = PAGE_REPEAT;
820 if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
821 call_data = -call_data;
823 XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)call_data);
825 sbw->scrollbar.timer_id =
826 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
827 rep,
828 RepeatNotify,
829 client_data);
833 * Same as above, but for floating numbers.
835 static float
836 FloatInRange(num, small, big)
837 float num, small, big;
839 return (num < small) ? small : ((num > big) ? big : num);
842 static void
843 ScrollOneLineUp(w, event, params, num_params)
844 Widget w;
845 XEvent *event;
846 String *params UNUSED;
847 Cardinal *num_params UNUSED;
849 ScrollSome(w, event, -ONE_LINE_DATA);
852 static void
853 ScrollOneLineDown(w, event, params, num_params)
854 Widget w;
855 XEvent *event;
856 String *params UNUSED;
857 Cardinal *num_params UNUSED;
859 ScrollSome(w, event, ONE_LINE_DATA);
862 static void
863 ScrollPageDown(w, event, params, num_params)
864 Widget w;
865 XEvent *event;
866 String *params UNUSED;
867 Cardinal *num_params UNUSED;
869 ScrollSome(w, event, ONE_PAGE_DATA);
872 static void
873 ScrollPageUp(w, event, params, num_params)
874 Widget w;
875 XEvent *event;
876 String *params UNUSED;
877 Cardinal *num_params UNUSED;
879 ScrollSome(w, event, -ONE_PAGE_DATA);
882 static void
883 ScrollSome(w, event, call_data)
884 Widget w;
885 XEvent *event;
886 int call_data;
888 ScrollbarWidget sbw = (ScrollbarWidget) w;
890 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
891 return;
893 if (LookAhead(w, event))
894 return;
896 sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
897 XtCallCallbacks(w, XtNscrollProc, (XtPointer)call_data);
900 static void
901 NotifyScroll(w, event, params, num_params)
902 Widget w;
903 XEvent *event;
904 String *params UNUSED;
905 Cardinal *num_params UNUSED;
907 ScrollbarWidget sbw = (ScrollbarWidget) w;
908 Position x, y, loc;
909 Dimension arrow_size;
910 unsigned long delay = 0;
911 int call_data = 0;
912 unsigned int state;
914 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
915 return;
917 if (LookAhead (w, event))
918 return;
920 ExtractPosition(event, &x, &y, &state);
921 loc = PICKLENGTH(sbw, x, y);
923 if ((int)sbw->scrollbar.thickness * 2 > (int)sbw->scrollbar.length)
924 arrow_size = sbw->scrollbar.length / 2;
925 else
926 arrow_size = sbw->scrollbar.thickness;
929 * handle CTRL modifier
931 if (state & ControlMask)
933 if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
934 call_data = END_PAGE_DATA;
935 else
936 call_data = -END_PAGE_DATA;
937 sbw->scrollbar.scroll_mode = SMODE_NONE;
940 * handle first arrow zone
942 else if (loc < (Position)arrow_size)
944 call_data = -ONE_LINE_DATA;
945 sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
946 delay = LINE_DELAY;
950 * handle last arrow zone
952 else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
954 call_data = ONE_LINE_DATA;
955 sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
956 delay = LINE_DELAY;
960 * handle zone "above" the thumb
962 else if (loc < sbw->scrollbar.topLoc)
964 call_data = -ONE_PAGE_DATA;
965 sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
966 delay = PAGE_DELAY;
970 * handle zone "below" the thumb
972 else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
974 call_data = ONE_PAGE_DATA;
975 sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
976 delay = PAGE_DELAY;
979 if (call_data)
980 XtCallCallbacks(w, XtNscrollProc, (XtPointer)call_data);
982 /* establish autoscroll */
983 if (delay)
984 sbw->scrollbar.timer_id =
985 XtAppAddTimeOut(XtWidgetToApplicationContext(w),
986 delay, RepeatNotify, (XtPointer)w);
989 static void
990 EndScroll(w, event, params, num_params)
991 Widget w;
992 XEvent *event UNUSED;
993 String *params UNUSED;
994 Cardinal *num_params UNUSED;
996 ScrollbarWidget sbw = (ScrollbarWidget) w;
998 sbw->scrollbar.scroll_mode = SMODE_NONE;
999 /* no need to remove any autoscroll timeout; it will no-op */
1000 /* because the scroll_mode is SMODE_NONE */
1001 /* but be sure to remove timeout in destroy proc */
1004 static float
1005 FractionLoc(sbw, x, y)
1006 ScrollbarWidget sbw;
1007 int x, y;
1009 int margin;
1010 float height, width;
1012 margin = MARGIN(sbw);
1013 x -= margin;
1014 y -= margin;
1015 height = (float)sbw->core.height - 2 * margin;
1016 width = (float)sbw->core.width - 2 * margin;
1017 return PICKLENGTH(sbw, x / width, y / height);
1020 static void
1021 MoveThumb(w, event, params, num_params)
1022 Widget w;
1023 XEvent *event;
1024 String *params UNUSED;
1025 Cardinal *num_params UNUSED;
1027 ScrollbarWidget sbw = (ScrollbarWidget)w;
1028 Position x, y;
1029 float top;
1030 char old_mode = sbw->scrollbar.scroll_mode;
1032 sbw->scrollbar.scroll_mode = SMODE_CONT; /* indicate continuous scroll */
1034 if (LookAhead(w, event))
1035 return;
1037 if (!event->xmotion.same_screen)
1038 return;
1040 ExtractPosition(event, &x, &y, (unsigned int *)NULL);
1042 top = FractionLoc(sbw, x, y);
1044 if (old_mode != SMODE_CONT) /* start dragging: set offset */
1046 if (event->xbutton.button == Button2)
1047 sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
1048 else
1049 sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
1052 top -= sbw->scrollbar.scroll_off;
1053 if (sbw->scrollbar.limit_thumb)
1054 top = FloatInRange(top, 0.0,
1055 sbw->scrollbar.max - sbw->scrollbar.shown + 0.000001);
1056 else
1057 top = FloatInRange(top, 0.0, sbw->scrollbar.max);
1059 sbw->scrollbar.top = top;
1060 PaintThumb(sbw);
1061 XFlush(XtDisplay(w)); /* re-draw it before Notifying */
1065 static void
1066 NotifyThumb(w, event, params, num_params)
1067 Widget w;
1068 XEvent *event;
1069 String *params UNUSED;
1070 Cardinal *num_params UNUSED;
1072 ScrollbarWidget sbw = (ScrollbarWidget)w;
1073 /* Use a union to avoid a warning for the weird conversion from float to
1074 * XtPointer. Comes from Xaw/Scrollbar.c. */
1075 union {
1076 XtPointer xtp;
1077 float xtf;
1078 } xtpf;
1080 if (LookAhead(w, event))
1081 return;
1083 /* thumbProc is not pretty, but is necessary for backwards
1084 compatibility on those architectures for which it work{s,ed};
1085 the intent is to pass a (truncated) float by value. */
1086 xtpf.xtf = sbw->scrollbar.top;
1087 XtCallCallbacks(w, XtNthumbProc, xtpf.xtp);
1088 XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
1091 static void
1092 AllocTopShadowGC(w)
1093 Widget w;
1095 ScrollbarWidget sbw = (ScrollbarWidget) w;
1096 XtGCMask valuemask;
1097 XGCValues myXGCV;
1099 valuemask = GCForeground;
1100 myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
1101 sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1104 static void
1105 AllocBotShadowGC(w)
1106 Widget w;
1108 ScrollbarWidget sbw = (ScrollbarWidget) w;
1109 XtGCMask valuemask;
1110 XGCValues myXGCV;
1112 valuemask = GCForeground;
1113 myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
1114 sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1117 static void
1118 _Xaw3dDrawShadows(gw, event, region, out)
1119 Widget gw;
1120 XEvent *event UNUSED;
1121 Region region;
1122 int out;
1124 XPoint pt[6];
1125 ScrollbarWidget sbw = (ScrollbarWidget) gw;
1126 Dimension s = sbw->scrollbar.shadow_width;
1128 * draw the shadows using the core part width and height,
1129 * and the scrollbar part shadow_width.
1131 * no point to do anything if the shadow_width is 0 or the
1132 * widget has not been realized.
1134 if (s > 0 && XtIsRealized(gw))
1136 Dimension h = sbw->core.height;
1137 Dimension w = sbw->core.width;
1138 Dimension wms = w - s;
1139 Dimension hms = h - s;
1140 Display *dpy = XtDisplay (gw);
1141 Window win = XtWindow (gw);
1142 GC top, bot;
1144 if (out)
1146 top = sbw->scrollbar.top_shadow_GC;
1147 bot = sbw->scrollbar.bot_shadow_GC;
1149 else
1151 top = sbw->scrollbar.bot_shadow_GC;
1152 bot = sbw->scrollbar.top_shadow_GC;
1155 /* top-left shadow */
1156 if ((region == NULL) ||
1157 (XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
1158 (XRectInRegion (region, 0, 0, s, h) != RectangleOut))
1160 pt[0].x = 0; pt[0].y = h;
1161 pt[1].x = pt[1].y = 0;
1162 pt[2].x = w; pt[2].y = 0;
1163 pt[3].x = wms; pt[3].y = s;
1164 pt[4].x = pt[4].y = s;
1165 pt[5].x = s; pt[5].y = hms;
1166 XFillPolygon (dpy, win, top, pt, 6, Complex, CoordModeOrigin);
1169 /* bottom-right shadow */
1170 if ((region == NULL) ||
1171 (XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
1172 (XRectInRegion (region, wms, 0, s, h) != RectangleOut))
1174 pt[0].x = 0; pt[0].y = h;
1175 pt[1].x = w; pt[1].y = h;
1176 pt[2].x = w; pt[2].y = 0;
1177 pt[3].x = wms; pt[3].y = s;
1178 pt[4].x = wms; pt[4].y = hms;
1179 pt[5].x = s; pt[5].y = hms;
1180 XFillPolygon (dpy, win, bot, pt, 6, Complex, CoordModeOrigin);
1187 * Set the scroll bar to the given location.
1189 void
1190 vim_XawScrollbarSetThumb(w, top, shown, max)
1191 Widget w;
1192 double top, shown, max;
1194 ScrollbarWidget sbw = (ScrollbarWidget) w;
1196 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if still thumbing */
1197 return;
1199 sbw->scrollbar.max = (max > 1.0) ? 1.0 :
1200 (max >= 0.0) ? max : sbw->scrollbar.max;
1202 sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
1203 (top >= 0.0) ? top : sbw->scrollbar.top;
1205 sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
1206 (shown >= 0.0) ? shown : sbw->scrollbar.shown;
1208 PaintThumb(sbw);