Annotation of src/usr.bin/vim/gui_at_sb.c, Revision 1.1.1.1
1.1 downsj 1: /* $OpenBSD$ */
2: /* vi:set ts=4 sw=4: */
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 */
6: /* DEC and MIT notice below. */
7: /* $XConsortium: Scrollbar.c,v 1.72 94/04/17 20:12:40 kaleb Exp $ */
8:
9: /*
10: * Modified for Vim by Bill Foster and Bram Moolenaar
11: */
12:
13: /***********************************************************
14:
15: Copyright (c) 1987, 1988, 1994 X Consortium
16:
17: Permission is hereby granted, free of charge, to any person obtaining a copy
18: of this software and associated documentation files (the "Software"), to deal
19: in the Software without restriction, including without limitation the rights
20: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21: copies of the Software, and to permit persons to whom the Software is
22: furnished to do so, subject to the following conditions:
23:
24: The above copyright notice and this permission notice shall be included in
25: all copies or substantial portions of the Software.
26:
27: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30: X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
31: AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33:
34: Except as contained in this notice, the name of the X Consortium shall not be
35: used in advertising or otherwise to promote the sale, use or other dealings
36: in this Software without prior written authorization from the X Consortium.
37:
38:
39: Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
40:
41: All Rights Reserved
42:
43: Permission to use, copy, modify, and distribute this software and its
44: documentation for any purpose and without fee is hereby granted,
45: provided that the above copyright notice appear in all copies and that
46: both that copyright notice and this permission notice appear in
47: supporting documentation, and that the name of Digital not be
48: used in advertising or publicity pertaining to distribution of the
49: software without specific, written prior permission.
50:
51: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
52: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
53: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
54: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
55: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
56: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
57: SOFTWARE.
58:
59: ******************************************************************/
60:
61: /* ScrollBar.c */
62: /* created by weissman, Mon Jul 7 13:20:03 1986 */
63: /* converted by swick, Thu Aug 27 1987 */
64:
65: #include <X11/IntrinsicP.h>
66: #include <X11/StringDefs.h>
67:
68: #include <X11/Xaw/XawInit.h>
69: #include "vim.h"
70: #include "gui_at_sb.h"
71:
72: #include <X11/Xmu/Drawing.h>
73:
74: /* Private definitions. */
75:
76: static char defaultTranslations[] =
77: "<Btn1Down>: NotifyScroll()\n\
78: <Btn2Down>: MoveThumb() NotifyThumb() \n\
79: <Btn3Down>: NotifyScroll()\n\
80: <Btn1Motion>: HandleThumb() \n\
81: <Btn3Motion>: HandleThumb() \n\
82: <Btn2Motion>: MoveThumb() NotifyThumb() \n\
83: <BtnUp>: EndScroll()";
84:
85: static float floatZero = 0.0;
86:
87: #define Offset(field) XtOffsetOf(ScrollbarRec, field)
88:
89: static XtResource resources[] =
90: {
91: /* {XtNscrollCursor, XtCCursor, XtRCursor, sizeof(Cursor),
92: Offset(scrollbar.cursor), XtRString, "crosshair"},*/
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: };
124: #undef Offset
125:
126: static void ClassInitialize __ARGS((void));
127: static void Initialize __ARGS((Widget, Widget, ArgList, Cardinal *));
128: static void Destroy __ARGS((Widget));
129: static void Realize __ARGS((Widget, Mask *, XSetWindowAttributes *));
130: static void Resize __ARGS((Widget));
131: static void Redisplay __ARGS((Widget, XEvent *, Region));
132: static Boolean SetValues __ARGS((Widget, Widget, Widget, ArgList, Cardinal *));
133:
134: static void HandleThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
135: static void MoveThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
136: static void NotifyThumb __ARGS((Widget, XEvent *, String *, Cardinal *));
137: static void NotifyScroll __ARGS((Widget, XEvent *, String *, Cardinal *));
138: static void EndScroll __ARGS((Widget, XEvent *, String *, Cardinal *));
139: static void _Xaw3dDrawShadows __ARGS((Widget, XEvent *, Region, Boolean));
140: static void AllocTopShadowGC __ARGS((Widget));
141: static void AllocBotShadowGC __ARGS((Widget));
142:
143: static XtActionsRec actions[] =
144: {
145: {"HandleThumb", HandleThumb},
146: {"MoveThumb", MoveThumb},
147: {"NotifyThumb", NotifyThumb},
148: {"NotifyScroll", NotifyScroll},
149: {"EndScroll", EndScroll}
150: };
151:
152:
153: ScrollbarClassRec vim_scrollbarClassRec =
154: {
155: { /* core fields */
156: /* superclass */ (WidgetClass) &simpleClassRec,
157: /* class_name */ "Scrollbar",
158: /* size */ sizeof(ScrollbarRec),
159: /* class_initialize */ ClassInitialize,
160: /* class_part_init */ NULL,
161: /* class_inited */ FALSE,
162: /* initialize */ Initialize,
163: /* initialize_hook */ NULL,
164: /* realize */ Realize,
165: /* actions */ actions,
166: /* num_actions */ XtNumber(actions),
167: /* resources */ resources,
168: /* num_resources */ XtNumber(resources),
169: /* xrm_class */ NULLQUARK,
170: /* compress_motion */ TRUE,
171: /* compress_exposure*/ TRUE,
172: /* compress_enterleave*/ TRUE,
173: /* visible_interest */ FALSE,
174: /* destroy */ Destroy,
175: /* resize */ Resize,
176: /* expose */ Redisplay,
177: /* set_values */ SetValues,
178: /* set_values_hook */ NULL,
179: /* set_values_almost */ XtInheritSetValuesAlmost,
180: /* get_values_hook */ NULL,
181: /* accept_focus */ NULL,
182: /* version */ XtVersion,
183: /* callback_private */ NULL,
184: /* tm_table */ defaultTranslations,
185: /* query_geometry */ XtInheritQueryGeometry,
186: /* display_accelerator*/ XtInheritDisplayAccelerator,
187: /* extension */ NULL
188: },
189: { /* simple fields */
190: /* change_sensitive */ XtInheritChangeSensitive
191: },
192: { /* scrollbar fields */
193: /* ignore */ 0
194: }
195:
196: };
197:
198: WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
199:
200: #define NoButton -1
201: #define PICKLENGTH(widget, x, y) \
202: ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
203: #define MIN(x,y) ((x) < (y) ? (x) : (y))
204: #define MAX(x,y) ((x) > (y) ? (x) : (y))
205:
206: #define LINE_DELAY 300
207: #define PAGE_DELAY 300
208: #define LINE_REPEAT 50
209: #define PAGE_REPEAT 250
210:
211: static void ClassInitialize()
212: {
213: XawInitializeWidgetSet();
214: XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
215: (XtConvertArgList)NULL, (Cardinal)0 );
216: }
217:
218: #define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
219:
220: static void FillArea(sbw, top, bottom, fill, draw_shadow)
221: ScrollbarWidget sbw;
222: Position top, bottom;
223: int fill;
224: int draw_shadow;
225: {
226: int tlen = bottom - top; /* length of thumb in pixels */
227: int sw, margin, floor;
228: int lx, ly, lw, lh;
229:
230: if (bottom <= 0 || bottom <= top)
231: return;
232: if ((sw = sbw->scrollbar.shadow_width) < 0)
233: sw = 0;
234: margin = MARGIN (sbw);
235: floor = sbw->scrollbar.length - margin + 2;
236:
237: if (sbw->scrollbar.orientation == XtorientHorizontal)
238: {
239: lx = ((top < margin) ? margin : top);
240: ly = sw;
241: lw = (((top + tlen) > floor) ? floor - top : tlen);
242: lh = sbw->core.height - 2 * sw;
243: }
244: else
245: {
246: lx = sw;
247: ly = ((top < margin) ? margin : top);
248: lw = sbw->core.width - 2 * sw;
249: lh = (((top + tlen) > floor) ? floor - top : tlen);
250: }
251: if (lh <= 0 || lw <= 0)
252: return;
253:
254: if (draw_shadow)
255: {
256: if (!sbw->scrollbar.orientation == XtorientHorizontal)
257: {
258: /* Top border */
259: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
260: sbw->scrollbar.top_shadow_GC,
261: lx, ly, lx + lw - 1, ly);
262:
263: /* Bottom border */
264: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
265: sbw->scrollbar.bot_shadow_GC,
266: lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
267: }
268: else
269: {
270: /* Left border */
271: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
272: sbw->scrollbar.top_shadow_GC,
273: lx, ly, lx, ly + lh - 1);
274:
275: /* Right border */
276: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
277: sbw->scrollbar.bot_shadow_GC,
278: lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
279: }
280: return;
281: }
282:
283: if (fill)
284: {
285: XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
286: sbw->scrollbar.gc,
287: lx, ly, (unsigned int) lw, (unsigned int) lh);
288:
289: if (!sbw->scrollbar.orientation == XtorientHorizontal)
290: {
291: /* Left border */
292: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
293: sbw->scrollbar.top_shadow_GC,
294: lx, ly, lx, ly + lh - 1);
295:
296: /* Right border */
297: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
298: sbw->scrollbar.bot_shadow_GC,
299: lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
300: }
301: else
302: {
303: /* Top border */
304: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
305: sbw->scrollbar.top_shadow_GC,
306: lx, ly, lx + lw - 1, ly);
307:
308: /* Bottom border */
309: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
310: sbw->scrollbar.bot_shadow_GC,
311: lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
312: }
313: }
314: else
315: {
316: XClearArea (XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
317: lx, ly, (unsigned int) lw, (unsigned int) lh,
318: FALSE);
319: }
320: }
321:
322: /* Paint the thumb in the area specified by sbw->top and
323: sbw->shown. The old area is erased. The painting and
324: erasing is done cleverly so that no flickering will occur.
325: */
326:
327: static void PaintThumb(sbw)
328: ScrollbarWidget sbw;
329: {
330: Position oldtop, oldbot, newtop, newbot;
331: Dimension margin, tzl;
332:
333: margin = MARGIN (sbw);
334: tzl = sbw->scrollbar.length - 2 * margin;
335: newtop = margin + (int)(tzl * sbw->scrollbar.top);
336: newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
337: if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
338: newbot = newtop + sbw->scrollbar.min_thumb;
339:
340: oldtop = sbw->scrollbar.topLoc;
341: oldbot = oldtop + sbw->scrollbar.shownLength;
342: sbw->scrollbar.topLoc = newtop;
343: sbw->scrollbar.shownLength = newbot - newtop;
344: if (XtIsRealized ((Widget) sbw))
345: {
346: if (newtop < oldtop)
347: FillArea(sbw, newtop, MIN(newbot, oldtop+1),1,0);
348: if (newtop > oldtop)
349: FillArea(sbw, oldtop, MIN(newtop, oldbot ),0,0);
350: if (newbot < oldbot)
351: FillArea(sbw, MAX(newbot, oldtop), oldbot, 0,0);
352: if (newbot > oldbot)
353: FillArea(sbw, MAX(newtop, oldbot-1), newbot, 1,0);
354:
355: /* Only draw the missing shadows */
356: FillArea(sbw, newtop, newbot, 0, 1);
357: }
358: }
359:
360: static void PaintArrows(sbw)
361: ScrollbarWidget sbw;
362: {
363: XPoint point[6];
364: Dimension thickness = sbw->scrollbar.thickness - 1;
365: Dimension size;
366: Dimension off;
367:
368: if (XtIsRealized((Widget) sbw))
369: {
370: if (thickness * 2 > sbw->scrollbar.length)
371: {
372: size = sbw->scrollbar.length / 2;
373: off = (thickness - size) / 2;
374: }
375: else
376: {
377: size = thickness;
378: off = 0;
379: }
380: point[0].x = off + sbw->scrollbar.shadow_width;
381: point[0].y = size;
382: point[1].x = thickness - off - sbw->scrollbar.shadow_width;
383: point[1].y = size;
384: point[2].x = thickness / 2;
385: point[2].y = sbw->scrollbar.shadow_width;
386:
387: point[3].x = off + sbw->scrollbar.shadow_width;
388: point[3].y = sbw->scrollbar.length - size;
389: point[4].x = thickness - off - sbw->scrollbar.shadow_width;
390: point[4].y = sbw->scrollbar.length - size;
391: point[5].x = thickness / 2;
392: point[5].y = sbw->scrollbar.length - sbw->scrollbar.shadow_width - 1;
393:
394: /* horizontal arrows require that x and y coordinates be swapped */
395: if (sbw->scrollbar.orientation == XtorientHorizontal)
396: {
397: int n;
398: int swap;
399: for (n = 0; n < 6; n++)
400: {
401: swap = point[n].x;
402: point[n].x = point[n].y;
403: point[n].y = swap;
404: }
405: }
406: /* draw the up/left arrow */
407: XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
408: sbw->scrollbar.gc,
409: point, 3,
410: Convex, CoordModeOrigin);
411: XDrawLines (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
412: sbw->scrollbar.bot_shadow_GC,
413: point, 3,
414: CoordModeOrigin);
415: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
416: sbw->scrollbar.top_shadow_GC,
417: point[0].x, point[0].y,
418: point[2].x, point[2].y);
419: /* draw the down/right arrow */
420: XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
421: sbw->scrollbar.gc,
422: point+3, 3,
423: Convex, CoordModeOrigin);
424: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
425: sbw->scrollbar.top_shadow_GC,
426: point[3].x, point[3].y,
427: point[4].x, point[4].y);
428: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
429: sbw->scrollbar.top_shadow_GC,
430: point[3].x, point[3].y,
431: point[5].x, point[5].y);
432: XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
433: sbw->scrollbar.bot_shadow_GC,
434: point[4].x, point[4].y,
435: point[5].x, point[5].y);
436: }
437: }
438:
439: /* Function Name: Destroy
440: * Description: Called as the scrollbar is going away...
441: * Arguments: w - the scrollbar.
442: * Returns: nonw
443: */
444: static void Destroy(w)
445: Widget w;
446: {
447: ScrollbarWidget sbw = (ScrollbarWidget) w;
448: if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
449: XtRemoveTimeOut (sbw->scrollbar.timer_id);
450: XtReleaseGC(w, sbw->scrollbar.gc);
451: XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
452: XtReleaseGC(w, sbw->scrollbar.bot_shadow_GC);
453: }
454:
455: /* Function Name: CreateGC
456: * Description: Creates the GC.
457: * Arguments: w - the scrollbar widget.
458: * Returns: none.
459: */
460:
461: static void CreateGC (w)
462: Widget w;
463: {
464: ScrollbarWidget sbw = (ScrollbarWidget) w;
465: XGCValues gcValues;
466: XtGCMask mask;
467: unsigned int depth = 1;
468:
469: if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
470: {
471: sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w),
472: (Pixel) 1, (Pixel) 0, depth);
473: }
474: else if (sbw->scrollbar.thumb != None)
475: {
476: Window root;
477: int x, y;
478: unsigned int width, height, bw;
479:
480: if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
481: &width, &height, &bw, &depth) == 0)
482: {
483: XtAppError (XtWidgetToApplicationContext (w),
484: "Scrollbar Widget: Could not get geometry of thumb pixmap.");
485: }
486: }
487:
488: gcValues.foreground = sbw->scrollbar.foreground;
489: gcValues.background = sbw->core.background_pixel;
490: mask = GCForeground | GCBackground;
491:
492: if (sbw->scrollbar.thumb != None)
493: {
494: gcValues.fill_style = FillSolid;
495: mask |= GCFillStyle;
496: #if 0
497: if (depth == 1)
498: {
499: gcValues.fill_style = FillOpaqueStippled;
500: gcValues.stipple = sbw->scrollbar.thumb;
501: mask |= GCFillStyle | GCStipple;
502: }
503: else
504: {
505: gcValues.fill_style = FillTiled;
506: gcValues.tile = sbw->scrollbar.thumb;
507: mask |= GCFillStyle | GCTile;
508: }
509: #endif
510: }
511: /* the creation should be non-caching, because */
512: /* we now set and clear clip masks on the gc returned */
513: sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
514: }
515:
516: static void SetDimensions(sbw)
517: ScrollbarWidget sbw;
518: {
519: if (sbw->scrollbar.orientation == XtorientVertical)
520: {
521: sbw->scrollbar.length = sbw->core.height;
522: sbw->scrollbar.thickness = sbw->core.width;
523: }
524: else
525: {
526: sbw->scrollbar.length = sbw->core.width;
527: sbw->scrollbar.thickness = sbw->core.height;
528: }
529: }
530:
531: /* ARGSUSED */
532: static void Initialize(request, new, args, num_args)
533: Widget request; /* what the client asked for */
534: Widget new; /* what we're going to give him */
535: ArgList args;
536: Cardinal *num_args;
537: {
538: ScrollbarWidget sbw = (ScrollbarWidget) new;
539:
540: CreateGC(new);
541: AllocTopShadowGC(new);
542: AllocBotShadowGC(new);
543:
544: if (sbw->core.width == 0)
545: sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
546: ? sbw->scrollbar.thickness : sbw->scrollbar.length;
547:
548: if (sbw->core.height == 0)
549: sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
550: ? sbw->scrollbar.thickness : sbw->scrollbar.length;
551:
552: SetDimensions(sbw);
553: sbw->scrollbar.scroll_mode = SMODE_NONE;
554: sbw->scrollbar.timer_id = (XtIntervalId)0;
555: sbw->scrollbar.topLoc = 0;
556: sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
557: }
558:
559: static void Realize(w, valueMask, attributes)
560: Widget w;
561: Mask *valueMask;
562: XSetWindowAttributes *attributes;
563: {
564: #if 0
565: ScrollbarWidget sbw = (ScrollbarWidget) w;
566:
567: if (sbw->simple.cursor_name == NULL)
568: XtVaSetValues(w, XtNcursorName, "crosshair", NULL);
569:
570: /* dont set the cursor of the window to anything */
571: *valueMask &= ~CWCursor;
572: #endif
573:
574: /*
575: * The Simple widget actually stuffs the value in the valuemask.
576: */
577: (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
578: (w, valueMask, attributes);
579: }
580:
581: /* ARGSUSED */
582: static Boolean SetValues(current, request, desired, args, num_args)
583: Widget current, /* what I am */
584: request, /* what he wants me to be */
585: desired; /* what I will become */
586: ArgList args;
587: Cardinal *num_args;
588: {
589: ScrollbarWidget sbw = (ScrollbarWidget) current;
590: ScrollbarWidget dsbw = (ScrollbarWidget) desired;
591: Boolean redraw = FALSE;
592:
593: /*
594: * If these values are outside the acceptable range ignore them...
595: */
596:
597: if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
598: dsbw->scrollbar.top = sbw->scrollbar.top;
599:
600: if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
601: dsbw->scrollbar.shown = sbw->scrollbar.shown;
602:
603: /*
604: * Change colors and stuff...
605: */
606: if (XtIsRealized(desired))
607: {
608: if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
609: sbw->core.background_pixel != dsbw->core.background_pixel ||
610: sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
611: {
612: XtReleaseGC(desired, sbw->scrollbar.gc);
613: CreateGC (desired);
614: redraw = TRUE;
615: }
616: if (sbw->scrollbar.top != dsbw->scrollbar.top ||
617: sbw->scrollbar.shown != dsbw->scrollbar.shown)
618: redraw = TRUE;
619: }
620: return redraw;
621: }
622:
623: static void Resize (w)
624: Widget w;
625: {
626: /* ForgetGravity has taken care of background, but thumb may
627: * have to move as a result of the new size. */
628: SetDimensions ((ScrollbarWidget) w);
629: Redisplay (w, (XEvent*) NULL, (Region)NULL);
630: }
631:
632:
633: /* ARGSUSED */
634: static void Redisplay(w, event, region)
635: Widget w;
636: XEvent *event;
637: Region region;
638: {
639: ScrollbarWidget sbw = (ScrollbarWidget) w;
640: int x, y;
641: unsigned int width, height;
642:
643: _Xaw3dDrawShadows(w, event, region, FALSE);
644:
645: if (sbw->scrollbar.orientation == XtorientHorizontal)
646: {
647: x = sbw->scrollbar.topLoc;
648: y = 1;
649: width = sbw->scrollbar.shownLength;
650: height = sbw->core.height - 2;
651: }
652: else
653: {
654: x = 1;
655: y = sbw->scrollbar.topLoc;
656: width = sbw->core.width - 2;
657: height = sbw->scrollbar.shownLength;
658: }
659: if (region == NULL ||
660: XRectInRegion (region, x, y, width, height) != RectangleOut)
661: {
662: /* Forces entire thumb to be painted. */
663: sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
664: PaintThumb (sbw);
665: }
666: /* we'd like to be region aware here!!!! */
667: PaintArrows(sbw);
668: }
669:
670:
671: static Boolean CompareEvents (oldEvent, newEvent)
672: XEvent *oldEvent, *newEvent;
673: {
674: #define Check(field) if (newEvent->field != oldEvent->field) return False;
675:
676: Check(xany.display);
677: Check(xany.type);
678: Check(xany.window);
679:
680: switch (newEvent->type)
681: {
682: case MotionNotify:
683: Check(xmotion.state);
684: break;
685: case ButtonPress:
686: case ButtonRelease:
687: Check(xbutton.state);
688: Check(xbutton.button);
689: break;
690: case KeyPress:
691: case KeyRelease:
692: Check(xkey.state);
693: Check(xkey.keycode);
694: break;
695: case EnterNotify:
696: case LeaveNotify:
697: Check(xcrossing.mode);
698: Check(xcrossing.detail);
699: Check(xcrossing.state);
700: break;
701: }
702: #undef Check
703:
704: return True;
705: }
706:
707: struct EventData
708: {
709: XEvent *oldEvent;
710: int count;
711: };
712:
713: static Bool PeekNotifyEvent (dpy, event, args)
714: Display *dpy;
715: XEvent *event;
716: char *args;
717: {
718: struct EventData *eventData = (struct EventData*)args;
719:
720: return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */
721: || CompareEvents(event, eventData->oldEvent));
722: }
723:
724:
725: static Boolean LookAhead (w, event)
726: Widget w;
727: XEvent *event;
728: {
729: XEvent newEvent;
730: struct EventData eventData;
731:
732: if (QLength (XtDisplay (w)) == 0)
733: return False;
734:
735: eventData.count = 0;
736: eventData.oldEvent = event;
737:
738: XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
739:
740: return CompareEvents (event, &newEvent);
741: }
742:
743:
744: static void ExtractPosition(event, x, y, state)
745: XEvent *event;
746: Position *x, *y; /* RETURN */
747: unsigned int *state; /* RETURN */
748: {
749: switch( event->type )
750: {
751: case MotionNotify:
752: *x = event->xmotion.x;
753: *y = event->xmotion.y;
754: if (state != NULL)
755: *state = event->xmotion.state;
756: break;
757: case ButtonPress:
758: case ButtonRelease:
759: *x = event->xbutton.x;
760: *y = event->xbutton.y;
761: if (state != NULL)
762: *state = event->xbutton.state;
763: break;
764: case KeyPress:
765: case KeyRelease:
766: *x = event->xkey.x;
767: *y = event->xkey.y;
768: if (state != NULL)
769: *state = event->xkey.state;
770: break;
771: case EnterNotify:
772: case LeaveNotify:
773: *x = event->xcrossing.x;
774: *y = event->xcrossing.y;
775: if (state != NULL)
776: *state = event->xcrossing.state;
777: break;
778: default:
779: *x = 0; *y = 0;
780: if (state != NULL)
781: *state = 0;
782: }
783: }
784:
785: /* ARGSUSED */
786: static void HandleThumb(w, event, params, num_params)
787: Widget w;
788: XEvent *event;
789: String *params; /* unused */
790: Cardinal *num_params; /* unused */
791: {
792: Position x, y, loc;
793: ScrollbarWidget sbw = (ScrollbarWidget) w;
794:
795: ExtractPosition(event, &x, &y, NULL);
796: loc = PICKLENGTH(sbw, x, y);
797: /* if the motion event puts the pointer in thumb, call Move and Notify */
798: /* also call Move and Notify if we're already in continuous scroll mode */
799: if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
800: (loc >= sbw->scrollbar.topLoc &&
801: loc <= sbw->scrollbar.topLoc + sbw->scrollbar.shownLength))
802: {
803: XtCallActionProc(w, "MoveThumb", event, params, *num_params);
804: XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
805: }
806: }
807:
808: static void RepeatNotify(client_data, idp)
809: XtPointer client_data;
810: XtIntervalId *idp;
811: {
812: ScrollbarWidget sbw = (ScrollbarWidget) client_data;
813: int call_data;
814: char mode = sbw->scrollbar.scroll_mode;
815: unsigned long rep;
816:
817: if (mode == SMODE_NONE || mode == SMODE_CONT)
818: {
819: sbw->scrollbar.timer_id = (XtIntervalId)0;
820: return;
821: }
822:
823: if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
824: {
825: call_data = ONE_LINE_DATA;
826: rep = LINE_REPEAT;
827: }
828: else
829: {
830: call_data = ONE_PAGE_DATA;
831: rep = PAGE_REPEAT;
832: }
833:
834: if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
835: call_data = -call_data;
836:
837: XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)call_data);
838:
839: sbw->scrollbar.timer_id =
840: XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
841: rep,
842: RepeatNotify,
843: client_data);
844: }
845:
846: /*
847: * Same as above, but for floating numbers.
848: */
849: static float FloatInRange(num, small, big)
850: float num, small, big;
851: {
852: return (num < small) ? small : ((num > big) ? big : num);
853: }
854:
855: /* ARGSUSED */
856: static void NotifyScroll(w, event, params, num_params)
857: Widget w;
858: XEvent *event;
859: String *params;
860: Cardinal *num_params;
861: {
862: ScrollbarWidget sbw = (ScrollbarWidget) w;
863: Position x, y, loc;
864: Dimension arrow_size;
865: unsigned long delay = 0;
866: int call_data = 0;
867: unsigned int state;
868:
869: if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
870: return;
871:
872: if (LookAhead (w, event))
873: return;
874:
875: ExtractPosition(event, &x, &y, &state);
876: loc = PICKLENGTH(sbw, x, y);
877:
878: if (sbw->scrollbar.thickness * 2 > sbw->scrollbar.length)
879: arrow_size = sbw->scrollbar.length / 2;
880: else
881: arrow_size = sbw->scrollbar.thickness;
882:
883: /*
884: * handle CTRL modifier
885: */
886: if (state & ControlMask)
887: {
888: if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
889: call_data = END_PAGE_DATA;
890: else
891: call_data = -END_PAGE_DATA;
892: sbw->scrollbar.scroll_mode = SMODE_NONE;
893: }
894: /*
895: * handle first arrow zone
896: */
897: else if (loc < (Position)arrow_size)
898: {
899: call_data = -ONE_LINE_DATA;
900: sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
901: delay = LINE_DELAY;
902: }
903:
904: /*
905: * handle last arrow zone
906: */
907: else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
908: {
909: call_data = ONE_LINE_DATA;
910: sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
911: delay = LINE_DELAY;
912: }
913:
914: /*
915: * handle zone "above" the thumb
916: */
917: else if (loc < sbw->scrollbar.topLoc)
918: {
919: call_data = -ONE_PAGE_DATA;
920: sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
921: delay = PAGE_DELAY;
922: }
923:
924: /*
925: * handle zone "below" the thumb
926: */
927: else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
928: {
929: call_data = ONE_PAGE_DATA;
930: sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
931: delay = PAGE_DELAY;
932: }
933:
934: if (call_data)
935: XtCallCallbacks(w, XtNscrollProc, (XtPointer)call_data);
936:
937: /* establish autoscroll */
938: if (delay)
939: sbw->scrollbar.timer_id =
940: XtAppAddTimeOut(XtWidgetToApplicationContext(w),
941: delay, RepeatNotify, (XtPointer)w);
942: }
943:
944: /* ARGSUSED */
945: static void EndScroll(w, event, params, num_params)
946: Widget w;
947: XEvent *event; /* unused */
948: String *params; /* unused */
949: Cardinal *num_params; /* unused */
950: {
951: ScrollbarWidget sbw = (ScrollbarWidget) w;
952:
953: sbw->scrollbar.scroll_mode = SMODE_NONE;
954: /* no need to remove any autoscroll timeout; it will no-op */
955: /* because the scroll_mode is SMODE_NONE */
956: /* but be sure to remove timeout in destroy proc */
957: }
958:
959: static float FractionLoc(sbw, x, y)
960: ScrollbarWidget sbw;
961: int x, y;
962: {
963: int margin;
964: float height, width;
965:
966: margin = MARGIN(sbw);
967: x -= margin;
968: y -= margin;
969: height = sbw->core.height - 2 * margin;
970: width = sbw->core.width - 2 * margin;
971: return PICKLENGTH(sbw, x / width, y / height);
972: }
973:
974:
975: static void MoveThumb(w, event, params, num_params)
976: Widget w;
977: XEvent *event;
978: String *params; /* unused */
979: Cardinal *num_params; /* unused */
980: {
981: ScrollbarWidget sbw = (ScrollbarWidget)w;
982: Position x, y;
983: float top;
984: char old_mode = sbw->scrollbar.scroll_mode;
985:
986: sbw->scrollbar.scroll_mode = SMODE_CONT; /* indicate continuous scroll */
987:
988: if (LookAhead(w, event))
989: return;
990:
991: if (!event->xmotion.same_screen)
992: return;
993:
994: ExtractPosition(event, &x, &y, NULL);
995:
996: top = FractionLoc(sbw, x, y);
997:
998: if (old_mode != SMODE_CONT) /* start dragging: set offset */
999: if (event->xbutton.button == Button2)
1000: sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
1001: else
1002: sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
1003:
1004: top -= sbw->scrollbar.scroll_off;
1005: top = FloatInRange(top, 0.0, sbw->scrollbar.max);
1006:
1007: sbw->scrollbar.top = top;
1008: PaintThumb(sbw);
1009: XFlush(XtDisplay(w)); /* re-draw it before Notifying */
1010: }
1011:
1012:
1013: /* ARGSUSED */
1014: static void NotifyThumb(w, event, params, num_params)
1015: Widget w;
1016: XEvent *event;
1017: String *params; /* unused */
1018: Cardinal *num_params; /* unused */
1019: {
1020: ScrollbarWidget sbw = (ScrollbarWidget)w;
1021:
1022: if (LookAhead(w, event))
1023: return;
1024:
1025: /* thumbProc is not pretty, but is necessary for backwards
1026: compatibility on those architectures for which it work{s,ed};
1027: the intent is to pass a (truncated) float by value. */
1028: XtCallCallbacks(w, XtNthumbProc, *(XtPointer*)&sbw->scrollbar.top);
1029: XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
1030: }
1031:
1032: /* ARGSUSED */
1033: static void
1034: AllocTopShadowGC (w)
1035: Widget w;
1036: {
1037: ScrollbarWidget sbw = (ScrollbarWidget) w;
1038: XtGCMask valuemask;
1039: XGCValues myXGCV;
1040:
1041: valuemask = GCForeground;
1042: myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
1043: sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1044: }
1045:
1046: /* ARGSUSED */
1047: static void
1048: AllocBotShadowGC (w)
1049: Widget w;
1050: {
1051: ScrollbarWidget sbw = (ScrollbarWidget) w;
1052: XtGCMask valuemask;
1053: XGCValues myXGCV;
1054:
1055: valuemask = GCForeground;
1056: myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
1057: sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1058: }
1059:
1060: /* ARGSUSED */
1061: static void
1062: _Xaw3dDrawShadows(gw, event, region, out)
1063: Widget gw;
1064: XEvent *event;
1065: Region region;
1066: Boolean out;
1067: {
1068: XPoint pt[6];
1069: ScrollbarWidget sbw = (ScrollbarWidget) gw;
1070: Dimension s = sbw->scrollbar.shadow_width;
1071: /*
1072: * draw the shadows using the core part width and height,
1073: * and the scrollbar part shadow_width.
1074: *
1075: * no point to do anything if the shadow_width is 0 or the
1076: * widget has not been realized.
1077: */
1078: if ((s > 0) && XtIsRealized (gw))
1079: {
1080: Dimension h = sbw->core.height;
1081: Dimension w = sbw->core.width;
1082: Dimension wms = w - s;
1083: Dimension hms = h - s;
1084: Display *dpy = XtDisplay (gw);
1085: Window win = XtWindow (gw);
1086: GC top, bot;
1087:
1088: if (out)
1089: {
1090: top = sbw->scrollbar.top_shadow_GC;
1091: bot = sbw->scrollbar.bot_shadow_GC;
1092: }
1093: else
1094: {
1095: top = sbw->scrollbar.bot_shadow_GC;
1096: bot = sbw->scrollbar.top_shadow_GC;
1097: }
1098:
1099: /* top-left shadow */
1100: if ((region == NULL) ||
1101: (XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
1102: (XRectInRegion (region, 0, 0, s, h) != RectangleOut))
1103: {
1104: pt[0].x = 0; pt[0].y = h;
1105: pt[1].x = pt[1].y = 0;
1106: pt[2].x = w; pt[2].y = 0;
1107: pt[3].x = wms; pt[3].y = s;
1108: pt[4].x = pt[4].y = s;
1109: pt[5].x = s; pt[5].y = hms;
1110: XFillPolygon (dpy, win, top, pt, 6,Complex,CoordModeOrigin);
1111: }
1112:
1113: /* bottom-right shadow */
1114: if ((region == NULL) ||
1115: (XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
1116: (XRectInRegion (region, wms, 0, s, h) != RectangleOut))
1117: {
1118: pt[0].x = 0; pt[0].y = h;
1119: pt[1].x = w; pt[1].y = h;
1120: pt[2].x = w; pt[2].y = 0;
1121: pt[3].x = wms; pt[3].y = s;
1122: pt[4].x = wms; pt[4].y = hms;
1123: pt[5].x = s; pt[5].y = hms;
1124: XFillPolygon (dpy, win, bot, pt,6, Complex,CoordModeOrigin);
1125: }
1126: }
1127: }
1128:
1129: /************************************************************
1130: *
1131: * Public routines.
1132: *
1133: ************************************************************/
1134:
1135: /* Set the scroll bar to the given location. */
1136:
1137: void vim_XawScrollbarSetThumb (w, top, shown, max)
1138: Widget w;
1139: #if NeedWidePrototypes
1140: double top, shown, max;
1141: #else
1142: float top, shown, max;
1143: #endif
1144: {
1145: ScrollbarWidget sbw = (ScrollbarWidget) w;
1146:
1147: if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if still thumbing */
1148: return;
1149:
1150: sbw->scrollbar.max = (max > 1.0) ? 1.0 :
1151: (max >= 0.0) ? max : sbw->scrollbar.max;
1152:
1153: sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
1154: (top >= 0.0) ? top : sbw->scrollbar.top;
1155:
1156: sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
1157: (shown >= 0.0) ? shown : sbw->scrollbar.shown;
1158:
1159: PaintThumb (sbw);
1160: }