blob: 0a68210f26789ae9b5d6a549855fbfba3e2ff705 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet: */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002/*
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 */
9
10/*
11 * Modified for Vim by Bill Foster and Bram Moolenaar
12 */
13
14/*
15
16Copyright (c) 1987, 1988, 1994 X Consortium
17
18Permission is hereby granted, free of charge, to any person obtaining a copy
19of this software and associated documentation files (the "Software"), to deal
20in the Software without restriction, including without limitation the rights
21to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22copies of the Software, and to permit persons to whom the Software is
23furnished to do so, subject to the following conditions:
24
25The above copyright notice and this permission notice shall be included in all
26copies or substantial portions of the Software.
27
28THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
31CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34
35Except as contained in this notice, the name of the X Consortium shall not be
36used in advertising or otherwise to promote the sale, use or other dealings in
37this Software without prior written authorization from the X Consortium.
38
39Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
40
41 All Rights Reserved
42
43Permission to use, copy, modify, and distribute this software and its
44documentation for any purpose and without fee is hereby granted, provided that
45the above copyright notice appear in all copies and that both that copyright
46notice and this permission notice appear in supporting documentation, and that
47the name of Digital not be used in advertising or publicity pertaining to
48distribution of the software without specific, written prior permission.
49
50DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL
52BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56
57*/
58
Bram Moolenaar30613902019-12-01 22:11:18 +010059// ScrollBar.c
60// created by weissman, Mon Jul 7 13:20:03 1986
61// converted by swick, Thu Aug 27 1987
Bram Moolenaar071d4272004-06-13 20:20:40 +000062
Bram Moolenaarf7506ca2017-02-25 16:01:49 +010063#include "vim.h"
64
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#include <X11/IntrinsicP.h>
66#include <X11/StringDefs.h>
67
68#include <X11/Xaw/XawInit.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000069#include "gui_at_sb.h"
70
71#include <X11/Xmu/Drawing.h>
72
Bram Moolenaar30613902019-12-01 22:11:18 +010073// Private definitions.
Bram Moolenaar071d4272004-06-13 20:20:40 +000074
75static char defaultTranslations[] =
76 "<Btn1Down>: NotifyScroll()\n\
77 <Btn2Down>: MoveThumb() NotifyThumb()\n\
78 <Btn3Down>: NotifyScroll()\n\
79 <Btn4Down>: ScrollOneLineUp()\n\
80 Shift<Btn4Down>: ScrollPageUp()\n\
81 <Btn5Down>: ScrollOneLineDown()\n\
82 Shift<Btn5Down>: ScrollPageDown()\n\
83 <Btn1Motion>: HandleThumb()\n\
84 <Btn3Motion>: HandleThumb()\n\
85 <Btn2Motion>: MoveThumb() NotifyThumb()\n\
86 <BtnUp>: EndScroll()";
87
88static float floatZero = 0.0;
89
90#define Offset(field) XtOffsetOf(ScrollbarRec, field)
91
92static XtResource resources[] =
93{
94 {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
95 Offset(scrollbar.length), XtRImmediate, (XtPointer) 1},
96 {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
97 Offset(scrollbar.thickness), XtRImmediate, (XtPointer) 14},
98 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
99 Offset(scrollbar.orientation), XtRImmediate, (XtPointer) XtorientVertical},
100 {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
101 Offset(scrollbar.scrollProc), XtRCallback, NULL},
102 {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
103 Offset(scrollbar.thumbProc), XtRCallback, NULL},
104 {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
105 Offset(scrollbar.jumpProc), XtRCallback, NULL},
106 {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
107 Offset(scrollbar.thumb), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
108 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
109 Offset(scrollbar.foreground), XtRString, XtDefaultForeground},
110 {XtNshown, XtCShown, XtRFloat, sizeof(float),
111 Offset(scrollbar.shown), XtRFloat, (XtPointer)&floatZero},
112 {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
113 Offset(scrollbar.top), XtRFloat, (XtPointer)&floatZero},
114 {XtNmaxOfThumb, XtCMaxOfThumb, XtRFloat, sizeof(float),
115 Offset(scrollbar.max), XtRFloat, (XtPointer)&floatZero},
116 {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
117 Offset(scrollbar.min_thumb), XtRImmediate, (XtPointer) 7},
118 {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
119 Offset(scrollbar.shadow_width), XtRImmediate, (XtPointer) 1},
120 {XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
121 Offset(scrollbar.top_shadow_pixel), XtRString, XtDefaultBackground},
122 {XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
123 Offset(scrollbar.bot_shadow_pixel), XtRString, XtDefaultForeground},
124 {XtNlimitThumb, XtCLimitThumb, XtRBool, sizeof(Bool),
125 Offset(scrollbar.limit_thumb), XtRImmediate, (XtPointer)0}
126};
127#undef Offset
128
Bram Moolenaar56985072016-01-29 23:23:06 +0100129static void ClassInitialize(void);
130static void Initialize(Widget, Widget, ArgList, Cardinal *);
131static void Destroy(Widget);
132static void Realize(Widget, Mask *, XSetWindowAttributes *);
133static void Resize(Widget);
134static void Redisplay(Widget, XEvent *, Region);
135static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136
Bram Moolenaar56985072016-01-29 23:23:06 +0100137static void HandleThumb(Widget, XEvent *, String *, Cardinal *);
138static void MoveThumb(Widget, XEvent *, String *, Cardinal *);
139static void NotifyThumb(Widget, XEvent *, String *, Cardinal *);
140static void NotifyScroll(Widget, XEvent *, String *, Cardinal *);
141static void EndScroll(Widget, XEvent *, String *, Cardinal *);
142static void ScrollOneLineUp(Widget, XEvent *, String *, Cardinal *);
143static void ScrollOneLineDown(Widget, XEvent *, String *, Cardinal *);
144static void ScrollPageUp(Widget, XEvent *, String *, Cardinal *);
145static void ScrollPageDown(Widget, XEvent *, String *, Cardinal *);
146static void ScrollSome(Widget w, XEvent *event, int call_data);
147static void _Xaw3dDrawShadows(Widget, XEvent *, Region, int);
148static void AllocTopShadowGC(Widget);
149static void AllocBotShadowGC(Widget);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150
151static XtActionsRec actions[] =
152{
153 {"HandleThumb", HandleThumb},
154 {"MoveThumb", MoveThumb},
155 {"NotifyThumb", NotifyThumb},
156 {"NotifyScroll", NotifyScroll},
157 {"EndScroll", EndScroll},
158 {"ScrollOneLineUp", ScrollOneLineUp},
159 {"ScrollOneLineDown", ScrollOneLineDown},
160 {"ScrollPageUp", ScrollPageUp},
161 {"ScrollPageDown", ScrollPageDown}
162};
163
164
165ScrollbarClassRec vim_scrollbarClassRec =
166{
Bram Moolenaar30613902019-12-01 22:11:18 +0100167 { // core fields
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168 /* superclass */ (WidgetClass) &simpleClassRec,
169 /* class_name */ "Scrollbar",
170 /* size */ sizeof(ScrollbarRec),
171 /* class_initialize */ ClassInitialize,
172 /* class_part_init */ NULL,
173 /* class_inited */ FALSE,
174 /* initialize */ Initialize,
175 /* initialize_hook */ NULL,
176 /* realize */ Realize,
177 /* actions */ actions,
178 /* num_actions */ XtNumber(actions),
179 /* resources */ resources,
180 /* num_resources */ XtNumber(resources),
181 /* xrm_class */ NULLQUARK,
182 /* compress_motion */ TRUE,
183 /* compress_exposure*/ TRUE,
184 /* compress_enterleave*/ TRUE,
185 /* visible_interest */ FALSE,
186 /* destroy */ Destroy,
187 /* resize */ Resize,
188 /* expose */ Redisplay,
189 /* set_values */ SetValues,
190 /* set_values_hook */ NULL,
191 /* set_values_almost */ XtInheritSetValuesAlmost,
192 /* get_values_hook */ NULL,
193 /* accept_focus */ NULL,
194 /* version */ XtVersion,
195 /* callback_private */ NULL,
196 /* tm_table */ defaultTranslations,
197 /* query_geometry */ XtInheritQueryGeometry,
198 /* display_accelerator*/ XtInheritDisplayAccelerator,
199 /* extension */ NULL
200 },
Bram Moolenaar30613902019-12-01 22:11:18 +0100201 { // simple fields
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000202 /* change_sensitive */ XtInheritChangeSensitive,
203#ifndef OLDXAW
204 /* extension */ NULL
205#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206 },
Bram Moolenaar30613902019-12-01 22:11:18 +0100207 { // scrollbar fields
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000208 /* empty */ 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 }
210};
211
212WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
213
214#define NoButton -1
215#define PICKLENGTH(widget, x, y) \
216 ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
217#define AT_MIN(x,y) ((x) < (y) ? (x) : (y))
218#define AT_MAX(x,y) ((x) > (y) ? (x) : (y))
219
220#define LINE_DELAY 300
221#define PAGE_DELAY 300
222#define LINE_REPEAT 50
223#define PAGE_REPEAT 250
224
225 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100226ClassInitialize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227{
228 XawInitializeWidgetSet();
229 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
230 (XtConvertArgList)NULL, (Cardinal)0 );
231}
232
233#define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
234
235 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100236FillArea(
237 ScrollbarWidget sbw,
Bram Moolenaar02fdaea2016-01-30 18:13:55 +0100238 Position top,
239 Position bottom,
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100240 int fill,
241 int draw_shadow)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242{
Bram Moolenaar30613902019-12-01 22:11:18 +0100243 int tlen = bottom - top; // length of thumb in pixels
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 int sw, margin, floor;
245 int lx, ly, lw, lh;
246
247 if (bottom <= 0 || bottom <= top)
248 return;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000249 sw = sbw->scrollbar.shadow_width;
250 if (sw < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251 sw = 0;
252 margin = MARGIN (sbw);
253 floor = sbw->scrollbar.length - margin + 2;
254
255 if (sbw->scrollbar.orientation == XtorientHorizontal)
256 {
257 lx = ((top < margin) ? margin : top);
258 ly = sw;
259 lw = (((top + tlen) > floor) ? floor - top : tlen);
260 lh = sbw->core.height - 2 * sw;
261 }
262 else
263 {
264 lx = sw;
265 ly = ((top < margin) ? margin : top);
266 lw = sbw->core.width - 2 * sw;
267 lh = (((top + tlen) > floor) ? floor - top : tlen);
268 }
269 if (lh <= 0 || lw <= 0)
270 return;
271
272 if (draw_shadow)
273 {
274 if (!(sbw->scrollbar.orientation == XtorientHorizontal))
275 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100276 // Top border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
278 sbw->scrollbar.top_shadow_GC,
279 lx, ly, lx + lw - 1, ly);
280
Bram Moolenaar30613902019-12-01 22:11:18 +0100281 // Bottom border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
283 sbw->scrollbar.bot_shadow_GC,
284 lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
285 }
286 else
287 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100288 // Left border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
290 sbw->scrollbar.top_shadow_GC,
291 lx, ly, lx, ly + lh - 1);
292
Bram Moolenaar30613902019-12-01 22:11:18 +0100293 // Right border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
295 sbw->scrollbar.bot_shadow_GC,
296 lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
297 }
298 return;
299 }
300
301 if (fill)
302 {
303 XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
304 sbw->scrollbar.gc,
305 lx, ly, (unsigned int) lw, (unsigned int) lh);
306
307 if (!(sbw->scrollbar.orientation == XtorientHorizontal))
308 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100309 // Left border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
311 sbw->scrollbar.top_shadow_GC,
312 lx, ly, lx, ly + lh - 1);
313
Bram Moolenaar30613902019-12-01 22:11:18 +0100314 // Right border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000315 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
316 sbw->scrollbar.bot_shadow_GC,
317 lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
318 }
319 else
320 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100321 // Top border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
323 sbw->scrollbar.top_shadow_GC,
324 lx, ly, lx + lw - 1, ly);
325
Bram Moolenaar30613902019-12-01 22:11:18 +0100326 // Bottom border
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
328 sbw->scrollbar.bot_shadow_GC,
329 lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
330 }
331 }
332 else
333 {
334 XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
335 lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE);
336 }
337}
338
Bram Moolenaar30613902019-12-01 22:11:18 +0100339/*
340 * Paint the thumb in the area specified by sbw->top and
341 * sbw->shown. The old area is erased. The painting and
342 * erasing is done cleverly so that no flickering will occur.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100345PaintThumb(ScrollbarWidget sbw)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346{
347 Position oldtop, oldbot, newtop, newbot;
348 Dimension margin, tzl;
349
350 margin = MARGIN (sbw);
351 tzl = sbw->scrollbar.length - 2 * margin;
352 newtop = margin + (int)(tzl * sbw->scrollbar.top);
353 newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
354 if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
355 newbot = newtop + sbw->scrollbar.min_thumb;
356
357 oldtop = sbw->scrollbar.topLoc;
358 oldbot = oldtop + sbw->scrollbar.shownLength;
359 sbw->scrollbar.topLoc = newtop;
360 sbw->scrollbar.shownLength = newbot - newtop;
361 if (XtIsRealized ((Widget) sbw))
362 {
363 if (newtop < oldtop)
364 FillArea(sbw, newtop, AT_MIN(newbot, oldtop+1),1,0);
365 if (newtop > oldtop)
366 FillArea(sbw, oldtop, AT_MIN(newtop, oldbot ),0,0);
367 if (newbot < oldbot)
368 FillArea(sbw, AT_MAX(newbot, oldtop), oldbot, 0,0);
369 if (newbot > oldbot)
370 FillArea(sbw, AT_MAX(newtop, oldbot-1), newbot, 1,0);
371
Bram Moolenaar30613902019-12-01 22:11:18 +0100372 // Only draw the missing shadows
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 FillArea(sbw, newtop, newbot, 0, 1);
374 }
375}
376
377 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100378PaintArrows(ScrollbarWidget sbw)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379{
380 XPoint point[6];
381 Dimension thickness = sbw->scrollbar.thickness - 1;
382 Dimension size;
383 Dimension off;
384
385 if (XtIsRealized((Widget) sbw))
386 {
387 if ((int)thickness * 2 > (int)sbw->scrollbar.length)
388 {
389 size = sbw->scrollbar.length / 2;
390 off = (int)(thickness - size) / 2;
391 }
392 else
393 {
394 size = thickness;
395 off = 0;
396 }
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;
403
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;
410
Bram Moolenaar30613902019-12-01 22:11:18 +0100411 // horizontal arrows require that x and y coordinates be swapped
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 if (sbw->scrollbar.orientation == XtorientHorizontal)
413 {
414 int n;
415 int swap;
416 for (n = 0; n < 6; n++)
417 {
418 swap = point[n].x;
419 point[n].x = point[n].y;
420 point[n].y = swap;
421 }
422 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100423 // draw the up/left arrow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 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);
Bram Moolenaar30613902019-12-01 22:11:18 +0100436 // draw the down/right arrow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 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);
453 }
454}
455
456 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100457Destroy(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458{
459 ScrollbarWidget sbw = (ScrollbarWidget) w;
460 if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
461 XtRemoveTimeOut (sbw->scrollbar.timer_id);
462 XtReleaseGC(w, sbw->scrollbar.gc);
463 XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
464 XtReleaseGC(w, sbw->scrollbar.bot_shadow_GC);
465}
466
467 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100468CreateGC(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000469{
470 ScrollbarWidget sbw = (ScrollbarWidget) w;
471 XGCValues gcValues;
472 XtGCMask mask;
473 unsigned int depth = 1;
474
475 if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
476 {
477 sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w),
478 (Pixel) 1, (Pixel) 0, depth);
479 }
480 else if (sbw->scrollbar.thumb != None)
481 {
482 Window root;
483 int x, y;
484 unsigned int width, height, bw;
485
486 if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
487 &width, &height, &bw, &depth) == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100488 emsg(_("Scrollbar Widget: Could not get geometry of thumb pixmap."));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000489 }
490
491 gcValues.foreground = sbw->scrollbar.foreground;
492 gcValues.background = sbw->core.background_pixel;
493 mask = GCForeground | GCBackground;
494
495 if (sbw->scrollbar.thumb != None)
496 {
497 gcValues.fill_style = FillSolid;
498 mask |= GCFillStyle;
499 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100500 // the creation should be non-caching, because
501 // we now set and clear clip masks on the gc returned
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
503}
504
505 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100506SetDimensions(ScrollbarWidget sbw)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507{
508 if (sbw->scrollbar.orientation == XtorientVertical)
509 {
510 sbw->scrollbar.length = sbw->core.height;
511 sbw->scrollbar.thickness = sbw->core.width;
512 }
513 else
514 {
515 sbw->scrollbar.length = sbw->core.width;
516 sbw->scrollbar.thickness = sbw->core.height;
517 }
518}
519
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100521Initialize(
Bram Moolenaar30613902019-12-01 22:11:18 +0100522 Widget request UNUSED, // what the client asked for
523 Widget new, // what we're going to give him
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100524 ArgList args UNUSED,
525 Cardinal *num_args UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526{
527 ScrollbarWidget sbw = (ScrollbarWidget) new;
528
529 CreateGC(new);
530 AllocTopShadowGC(new);
531 AllocBotShadowGC(new);
532
533 if (sbw->core.width == 0)
534 sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
535 ? sbw->scrollbar.thickness : sbw->scrollbar.length;
536
537 if (sbw->core.height == 0)
538 sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
539 ? sbw->scrollbar.thickness : sbw->scrollbar.length;
540
541 SetDimensions(sbw);
542 sbw->scrollbar.scroll_mode = SMODE_NONE;
543 sbw->scrollbar.timer_id = (XtIntervalId)0;
544 sbw->scrollbar.topLoc = 0;
545 sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
546}
547
548 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100549Realize(
550 Widget w,
551 Mask *valueMask,
552 XSetWindowAttributes *attributes)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553{
Bram Moolenaar30613902019-12-01 22:11:18 +0100554 // The Simple widget actually stuffs the value in the valuemask.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
556 (w, valueMask, attributes);
557}
558
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100560SetValues(
Bram Moolenaar30613902019-12-01 22:11:18 +0100561 Widget current, // what I am
562 Widget request UNUSED, // what he wants me to be
563 Widget desired, // what I will become
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100564 ArgList args UNUSED,
565 Cardinal *num_args UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566{
567 ScrollbarWidget sbw = (ScrollbarWidget) current;
568 ScrollbarWidget dsbw = (ScrollbarWidget) desired;
569 Boolean redraw = FALSE;
570
571/*
572 * If these values are outside the acceptable range ignore them...
573 */
574 if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
575 dsbw->scrollbar.top = sbw->scrollbar.top;
576
577 if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
578 dsbw->scrollbar.shown = sbw->scrollbar.shown;
579
580/*
581 * Change colors and stuff...
582 */
583 if (XtIsRealized(desired))
584 {
585 if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
586 sbw->core.background_pixel != dsbw->core.background_pixel ||
587 sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
588 {
589 XtReleaseGC(desired, sbw->scrollbar.gc);
590 CreateGC (desired);
591 redraw = TRUE;
592 }
593 if (sbw->scrollbar.top != dsbw->scrollbar.top ||
594 sbw->scrollbar.shown != dsbw->scrollbar.shown)
595 redraw = TRUE;
596 }
597 return redraw;
598}
599
600 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100601Resize(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602{
Bram Moolenaar30613902019-12-01 22:11:18 +0100603 // ForgetGravity has taken care of background, but thumb may
604 // have to move as a result of the new size.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 SetDimensions ((ScrollbarWidget) w);
606 Redisplay(w, (XEvent*) NULL, (Region)NULL);
607}
608
609
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100611Redisplay(Widget w, XEvent *event, Region region)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612{
613 ScrollbarWidget sbw = (ScrollbarWidget) w;
614 int x, y;
615 unsigned int width, height;
616
617 _Xaw3dDrawShadows(w, event, region, FALSE);
618
619 if (sbw->scrollbar.orientation == XtorientHorizontal)
620 {
621 x = sbw->scrollbar.topLoc;
622 y = 1;
623 width = sbw->scrollbar.shownLength;
624 height = sbw->core.height - 2;
625 }
626 else
627 {
628 x = 1;
629 y = sbw->scrollbar.topLoc;
630 width = sbw->core.width - 2;
631 height = sbw->scrollbar.shownLength;
632 }
633 if (region == NULL ||
634 XRectInRegion (region, x, y, width, height) != RectangleOut)
635 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100636 // Forces entire thumb to be painted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
638 PaintThumb (sbw);
639 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100640 // we'd like to be region aware here!!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 PaintArrows(sbw);
642}
643
644
645 static Boolean
Bram Moolenaar02fdaea2016-01-30 18:13:55 +0100646CompareEvents(XEvent *oldEvent, XEvent *newEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647{
Bram Moolenaar6f470022018-04-10 18:47:20 +0200648#define Check(field) \
649 do { \
650 if (newEvent->field != oldEvent->field) \
651 return False; \
652 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653
654 Check(xany.display);
655 Check(xany.type);
656 Check(xany.window);
657
658 switch (newEvent->type)
659 {
660 case MotionNotify:
661 Check(xmotion.state);
662 break;
663 case ButtonPress:
664 case ButtonRelease:
665 Check(xbutton.state);
666 Check(xbutton.button);
667 break;
668 case KeyPress:
669 case KeyRelease:
670 Check(xkey.state);
671 Check(xkey.keycode);
672 break;
673 case EnterNotify:
674 case LeaveNotify:
675 Check(xcrossing.mode);
676 Check(xcrossing.detail);
677 Check(xcrossing.state);
678 break;
679 }
680#undef Check
681
682 return True;
683}
684
685struct EventData
686{
687 XEvent *oldEvent;
688 int count;
689};
690
691 static Bool
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100692PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693{
694 struct EventData *eventData = (struct EventData*)args;
695
Bram Moolenaar30613902019-12-01 22:11:18 +0100696 return ((++eventData->count == QLength(dpy)) // since PeekIf blocks
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697 || CompareEvents(event, eventData->oldEvent));
698}
699
700
701 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100702LookAhead(Widget w, XEvent *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703{
704 XEvent newEvent;
705 struct EventData eventData;
706
707 if (QLength (XtDisplay (w)) == 0)
708 return False;
709
710 eventData.count = 0;
711 eventData.oldEvent = event;
712
713 XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
714
715 return CompareEvents (event, &newEvent);
716}
717
718
719 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100720ExtractPosition(
721 XEvent *event,
Bram Moolenaar30613902019-12-01 22:11:18 +0100722 Position *x, // RETURN
723 Position *y, // RETURN
724 unsigned int *state) // RETURN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725{
726 switch (event->type)
727 {
728 case MotionNotify:
729 *x = event->xmotion.x;
730 *y = event->xmotion.y;
731 if (state != NULL)
732 *state = event->xmotion.state;
733 break;
734 case ButtonPress:
735 case ButtonRelease:
736 *x = event->xbutton.x;
737 *y = event->xbutton.y;
738 if (state != NULL)
739 *state = event->xbutton.state;
740 break;
741 case KeyPress:
742 case KeyRelease:
743 *x = event->xkey.x;
744 *y = event->xkey.y;
745 if (state != NULL)
746 *state = event->xkey.state;
747 break;
748 case EnterNotify:
749 case LeaveNotify:
750 *x = event->xcrossing.x;
751 *y = event->xcrossing.y;
752 if (state != NULL)
753 *state = event->xcrossing.state;
754 break;
755 default:
756 *x = 0; *y = 0;
757 if (state != NULL)
758 *state = 0;
759 }
760}
761
762 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100763HandleThumb(
764 Widget w,
765 XEvent *event,
766 String *params,
767 Cardinal *num_params)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768{
769 Position x, y, loc;
770 ScrollbarWidget sbw = (ScrollbarWidget) w;
771
772 ExtractPosition(event, &x, &y, (unsigned int *)NULL);
773 loc = PICKLENGTH(sbw, x, y);
Bram Moolenaar30613902019-12-01 22:11:18 +0100774 // if the motion event puts the pointer in thumb, call Move and Notify
775 // also call Move and Notify if we're already in continuous scroll mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
777 (loc >= sbw->scrollbar.topLoc &&
778 loc <= sbw->scrollbar.topLoc + (int)sbw->scrollbar.shownLength))
779 {
780 XtCallActionProc(w, "MoveThumb", event, params, *num_params);
781 XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
782 }
783}
784
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100786RepeatNotify(XtPointer client_data, XtIntervalId *idp UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787{
788 ScrollbarWidget sbw = (ScrollbarWidget) client_data;
789 int call_data;
790 char mode = sbw->scrollbar.scroll_mode;
791 unsigned long rep;
792
793 if (mode == SMODE_NONE || mode == SMODE_CONT)
794 {
795 sbw->scrollbar.timer_id = (XtIntervalId)0;
796 return;
797 }
798
799 if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
800 {
801 call_data = ONE_LINE_DATA;
802 rep = LINE_REPEAT;
803 }
804 else
805 {
806 call_data = ONE_PAGE_DATA;
807 rep = PAGE_REPEAT;
808 }
809
810 if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
811 call_data = -call_data;
812
Bram Moolenaar9d6650f2010-06-06 23:04:47 +0200813 XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)(long_u)call_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814
815 sbw->scrollbar.timer_id =
816 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
817 rep,
818 RepeatNotify,
819 client_data);
820}
821
822/*
823 * Same as above, but for floating numbers.
824 */
825 static float
Bram Moolenaar02fdaea2016-01-30 18:13:55 +0100826FloatInRange(float num, float small, float big)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827{
828 return (num < small) ? small : ((num > big) ? big : num);
829}
830
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100832ScrollOneLineUp(
833 Widget w,
834 XEvent *event,
835 String *params UNUSED,
836 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837{
838 ScrollSome(w, event, -ONE_LINE_DATA);
839}
840
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100842ScrollOneLineDown(
843 Widget w,
844 XEvent *event,
845 String *params UNUSED,
846 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847{
848 ScrollSome(w, event, ONE_LINE_DATA);
849}
850
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100852ScrollPageDown(
853 Widget w,
854 XEvent *event,
855 String *params UNUSED,
856 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857{
858 ScrollSome(w, event, ONE_PAGE_DATA);
859}
860
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100862ScrollPageUp(
863 Widget w,
864 XEvent *event,
865 String *params UNUSED,
866 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867{
868 ScrollSome(w, event, -ONE_PAGE_DATA);
869}
870
871 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100872ScrollSome(
873 Widget w,
874 XEvent *event,
875 int call_data)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876{
877 ScrollbarWidget sbw = (ScrollbarWidget) w;
878
Bram Moolenaar30613902019-12-01 22:11:18 +0100879 if (sbw->scrollbar.scroll_mode == SMODE_CONT) // if scroll continuous
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 return;
881
882 if (LookAhead(w, event))
883 return;
884
885 sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
Bram Moolenaar9d6650f2010-06-06 23:04:47 +0200886 XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887}
888
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100890NotifyScroll(
891 Widget w,
892 XEvent *event,
893 String *params UNUSED,
894 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895{
896 ScrollbarWidget sbw = (ScrollbarWidget) w;
897 Position x, y, loc;
898 Dimension arrow_size;
899 unsigned long delay = 0;
900 int call_data = 0;
901 unsigned int state;
902
Bram Moolenaar30613902019-12-01 22:11:18 +0100903 if (sbw->scrollbar.scroll_mode == SMODE_CONT) // if scroll continuous
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904 return;
905
906 if (LookAhead (w, event))
907 return;
908
909 ExtractPosition(event, &x, &y, &state);
910 loc = PICKLENGTH(sbw, x, y);
911
912 if ((int)sbw->scrollbar.thickness * 2 > (int)sbw->scrollbar.length)
913 arrow_size = sbw->scrollbar.length / 2;
914 else
915 arrow_size = sbw->scrollbar.thickness;
916
917 /*
918 * handle CTRL modifier
919 */
920 if (state & ControlMask)
921 {
922 if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
923 call_data = END_PAGE_DATA;
924 else
925 call_data = -END_PAGE_DATA;
926 sbw->scrollbar.scroll_mode = SMODE_NONE;
927 }
928 /*
929 * handle first arrow zone
930 */
931 else if (loc < (Position)arrow_size)
932 {
933 call_data = -ONE_LINE_DATA;
934 sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
935 delay = LINE_DELAY;
936 }
937
938 /*
939 * handle last arrow zone
940 */
941 else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
942 {
943 call_data = ONE_LINE_DATA;
944 sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
945 delay = LINE_DELAY;
946 }
947
948 /*
949 * handle zone "above" the thumb
950 */
951 else if (loc < sbw->scrollbar.topLoc)
952 {
953 call_data = -ONE_PAGE_DATA;
954 sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
955 delay = PAGE_DELAY;
956 }
957
958 /*
959 * handle zone "below" the thumb
960 */
961 else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
962 {
963 call_data = ONE_PAGE_DATA;
964 sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
965 delay = PAGE_DELAY;
966 }
967
968 if (call_data)
Bram Moolenaar9d6650f2010-06-06 23:04:47 +0200969 XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970
Bram Moolenaar30613902019-12-01 22:11:18 +0100971 // establish autoscroll
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 if (delay)
973 sbw->scrollbar.timer_id =
974 XtAppAddTimeOut(XtWidgetToApplicationContext(w),
975 delay, RepeatNotify, (XtPointer)w);
976}
977
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100979EndScroll(
980 Widget w,
981 XEvent *event UNUSED,
982 String *params UNUSED,
983 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984{
985 ScrollbarWidget sbw = (ScrollbarWidget) w;
986
987 sbw->scrollbar.scroll_mode = SMODE_NONE;
Bram Moolenaar30613902019-12-01 22:11:18 +0100988 // no need to remove any autoscroll timeout; it will no-op
989 // because the scroll_mode is SMODE_NONE
990 // but be sure to remove timeout in destroy proc
Bram Moolenaar071d4272004-06-13 20:20:40 +0000991}
992
993 static float
Bram Moolenaar02fdaea2016-01-30 18:13:55 +0100994FractionLoc(ScrollbarWidget sbw, int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995{
996 int margin;
997 float height, width;
998
999 margin = MARGIN(sbw);
1000 x -= margin;
1001 y -= margin;
1002 height = (float)sbw->core.height - 2 * margin;
1003 width = (float)sbw->core.width - 2 * margin;
1004 return PICKLENGTH(sbw, x / width, y / height);
1005}
1006
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001008MoveThumb(
1009 Widget w,
1010 XEvent *event,
1011 String *params UNUSED,
1012 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001013{
1014 ScrollbarWidget sbw = (ScrollbarWidget)w;
1015 Position x, y;
1016 float top;
1017 char old_mode = sbw->scrollbar.scroll_mode;
1018
Bram Moolenaar30613902019-12-01 22:11:18 +01001019 sbw->scrollbar.scroll_mode = SMODE_CONT; // indicate continuous scroll
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020
1021 if (LookAhead(w, event))
1022 return;
1023
1024 if (!event->xmotion.same_screen)
1025 return;
1026
1027 ExtractPosition(event, &x, &y, (unsigned int *)NULL);
1028
1029 top = FractionLoc(sbw, x, y);
1030
Bram Moolenaar30613902019-12-01 22:11:18 +01001031 if (old_mode != SMODE_CONT) // start dragging: set offset
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032 {
1033 if (event->xbutton.button == Button2)
1034 sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
1035 else
1036 sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
1037 }
1038
1039 top -= sbw->scrollbar.scroll_off;
1040 if (sbw->scrollbar.limit_thumb)
1041 top = FloatInRange(top, 0.0,
1042 sbw->scrollbar.max - sbw->scrollbar.shown + 0.000001);
1043 else
1044 top = FloatInRange(top, 0.0, sbw->scrollbar.max);
1045
1046 sbw->scrollbar.top = top;
1047 PaintThumb(sbw);
Bram Moolenaar30613902019-12-01 22:11:18 +01001048 XFlush(XtDisplay(w)); // re-draw it before Notifying
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049}
1050
1051
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001053NotifyThumb(
1054 Widget w,
1055 XEvent *event,
1056 String *params UNUSED,
1057 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058{
1059 ScrollbarWidget sbw = (ScrollbarWidget)w;
Bram Moolenaar30613902019-12-01 22:11:18 +01001060 // Use a union to avoid a warning for the weird conversion from float to
1061 // XtPointer. Comes from Xaw/Scrollbar.c.
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00001062 union {
1063 XtPointer xtp;
1064 float xtf;
1065 } xtpf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066
1067 if (LookAhead(w, event))
1068 return;
1069
Bram Moolenaar30613902019-12-01 22:11:18 +01001070 // thumbProc is not pretty, but is necessary for backwards
1071 // compatibility on those architectures for which it work{s,ed};
1072 // the intent is to pass a (truncated) float by value.
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00001073 xtpf.xtf = sbw->scrollbar.top;
1074 XtCallCallbacks(w, XtNthumbProc, xtpf.xtp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
1076}
1077
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001079AllocTopShadowGC(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080{
1081 ScrollbarWidget sbw = (ScrollbarWidget) w;
1082 XtGCMask valuemask;
1083 XGCValues myXGCV;
1084
1085 valuemask = GCForeground;
1086 myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
1087 sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1088}
1089
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001091AllocBotShadowGC(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092{
1093 ScrollbarWidget sbw = (ScrollbarWidget) w;
1094 XtGCMask valuemask;
1095 XGCValues myXGCV;
1096
1097 valuemask = GCForeground;
1098 myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
1099 sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1100}
1101
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001103_Xaw3dDrawShadows(
1104 Widget gw,
1105 XEvent *event UNUSED,
1106 Region region,
1107 int out)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001108{
1109 XPoint pt[6];
1110 ScrollbarWidget sbw = (ScrollbarWidget) gw;
1111 Dimension s = sbw->scrollbar.shadow_width;
1112 /*
1113 * draw the shadows using the core part width and height,
1114 * and the scrollbar part shadow_width.
1115 *
1116 * no point to do anything if the shadow_width is 0 or the
1117 * widget has not been realized.
1118 */
1119 if (s > 0 && XtIsRealized(gw))
1120 {
1121 Dimension h = sbw->core.height;
1122 Dimension w = sbw->core.width;
1123 Dimension wms = w - s;
1124 Dimension hms = h - s;
1125 Display *dpy = XtDisplay (gw);
1126 Window win = XtWindow (gw);
1127 GC top, bot;
1128
1129 if (out)
1130 {
1131 top = sbw->scrollbar.top_shadow_GC;
1132 bot = sbw->scrollbar.bot_shadow_GC;
1133 }
1134 else
1135 {
1136 top = sbw->scrollbar.bot_shadow_GC;
1137 bot = sbw->scrollbar.top_shadow_GC;
1138 }
1139
Bram Moolenaar30613902019-12-01 22:11:18 +01001140 // top-left shadow
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 if ((region == NULL) ||
1142 (XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
1143 (XRectInRegion (region, 0, 0, s, h) != RectangleOut))
1144 {
1145 pt[0].x = 0; pt[0].y = h;
1146 pt[1].x = pt[1].y = 0;
1147 pt[2].x = w; pt[2].y = 0;
1148 pt[3].x = wms; pt[3].y = s;
1149 pt[4].x = pt[4].y = s;
1150 pt[5].x = s; pt[5].y = hms;
1151 XFillPolygon (dpy, win, top, pt, 6, Complex, CoordModeOrigin);
1152 }
1153
Bram Moolenaar30613902019-12-01 22:11:18 +01001154 // bottom-right shadow
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 if ((region == NULL) ||
1156 (XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
1157 (XRectInRegion (region, wms, 0, s, h) != RectangleOut))
1158 {
1159 pt[0].x = 0; pt[0].y = h;
1160 pt[1].x = w; pt[1].y = h;
1161 pt[2].x = w; pt[2].y = 0;
1162 pt[3].x = wms; pt[3].y = s;
1163 pt[4].x = wms; pt[4].y = hms;
1164 pt[5].x = s; pt[5].y = hms;
1165 XFillPolygon (dpy, win, bot, pt, 6, Complex, CoordModeOrigin);
1166 }
1167 }
1168}
1169
1170
1171/*
1172 * Set the scroll bar to the given location.
1173 */
1174 void
Bram Moolenaar02fdaea2016-01-30 18:13:55 +01001175vim_XawScrollbarSetThumb(Widget w, double top, double shown, double max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176{
1177 ScrollbarWidget sbw = (ScrollbarWidget) w;
1178
Bram Moolenaar30613902019-12-01 22:11:18 +01001179 if (sbw->scrollbar.scroll_mode == SMODE_CONT) // if still thumbing
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180 return;
1181
1182 sbw->scrollbar.max = (max > 1.0) ? 1.0 :
1183 (max >= 0.0) ? max : sbw->scrollbar.max;
1184
1185 sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
1186 (top >= 0.0) ? top : sbw->scrollbar.top;
1187
1188 sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
1189 (shown >= 0.0) ? shown : sbw->scrollbar.shown;
1190
1191 PaintThumb(sbw);
1192}