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 */ 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 59/* ScrollBar.c */ 60/* created by weissman, Mon Jul 7 13:20:03 1986 */ 61/* converted by swick, Thu Aug 27 1987 */ 62 63#include <X11/IntrinsicP.h> 64#include <X11/StringDefs.h> 65 66#include <X11/Xaw/XawInit.h> 67#include "vim.h" 68#include "gui_at_sb.h" 69 70#include <X11/Xmu/Drawing.h> 71 72/* Private definitions. */ 73 74static 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()"; 86 87static float floatZero = 0.0; 88 89#define Offset(field) XtOffsetOf(ScrollbarRec, field) 90 91static XtResource resources[] = 92{ 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} 125}; 126#undef Offset 127 128static void ClassInitialize __ARGS((void)); 129static void Initialize __ARGS((Widget, Widget, ArgList, Cardinal *)); 130static void Destroy __ARGS((Widget)); 131static void Realize __ARGS((Widget, Mask *, XSetWindowAttributes *)); 132static void Resize __ARGS((Widget)); 133static void Redisplay __ARGS((Widget, XEvent *, Region)); 134static Boolean SetValues __ARGS((Widget, Widget, Widget, ArgList, Cardinal *)); 135 136static void HandleThumb __ARGS((Widget, XEvent *, String *, Cardinal *)); 137static void MoveThumb __ARGS((Widget, XEvent *, String *, Cardinal *)); 138static void NotifyThumb __ARGS((Widget, XEvent *, String *, Cardinal *)); 139static void NotifyScroll __ARGS((Widget, XEvent *, String *, Cardinal *)); 140static void EndScroll __ARGS((Widget, XEvent *, String *, Cardinal *)); 141static void ScrollOneLineUp __ARGS((Widget, XEvent *, String *, Cardinal *)); 142static void ScrollOneLineDown __ARGS((Widget, XEvent *, String *, Cardinal *)); 143static void ScrollPageUp __ARGS((Widget, XEvent *, String *, Cardinal *)); 144static void ScrollPageDown __ARGS((Widget, XEvent *, String *, Cardinal *)); 145static void ScrollSome __ARGS((Widget w, XEvent *event, int call_data)); 146static void _Xaw3dDrawShadows __ARGS((Widget, XEvent *, Region, int)); 147static void AllocTopShadowGC __ARGS((Widget)); 148static void AllocBotShadowGC __ARGS((Widget)); 149 150static XtActionsRec actions[] = 151{ 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} 161}; 162 163 164ScrollbarClassRec vim_scrollbarClassRec = 165{ 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 199 }, 200 { /* simple fields */ 201 /* change_sensitive */ XtInheritChangeSensitive, 202#ifndef OLDXAW 203 /* extension */ NULL 204#endif 205 }, 206 { /* scrollbar fields */ 207 /* empty */ 0 208 } 209}; 210 211WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec; 212 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)) 218 219#define LINE_DELAY 300 220#define PAGE_DELAY 300 221#define LINE_REPEAT 50 222#define PAGE_REPEAT 250 223 224 static void 225ClassInitialize() 226{ 227 XawInitializeWidgetSet(); 228 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation, 229 (XtConvertArgList)NULL, (Cardinal)0 ); 230} 231 232#define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width 233 234 static void 235FillArea(sbw, top, bottom, fill, draw_shadow) 236 ScrollbarWidget sbw; 237 Position top, bottom; 238 int fill; 239 int draw_shadow; 240{ 241 int tlen = bottom - top; /* length of thumb in pixels */ 242 int sw, margin, floor; 243 int lx, ly, lw, lh; 244 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; 252 253 if (sbw->scrollbar.orientation == XtorientHorizontal) 254 { 255 lx = ((top < margin) ? margin : top); 256 ly = sw; 257 lw = (((top + tlen) > floor) ? floor - top : tlen); 258 lh = sbw->core.height - 2 * sw; 259 } 260 else 261 { 262 lx = sw; 263 ly = ((top < margin) ? margin : top); 264 lw = sbw->core.width - 2 * sw; 265 lh = (((top + tlen) > floor) ? floor - top : tlen); 266 } 267 if (lh <= 0 || lw <= 0) 268 return; 269 270 if (draw_shadow) 271 { 272 if (!(sbw->scrollbar.orientation == XtorientHorizontal)) 273 { 274 /* Top border */ 275 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw), 276 sbw->scrollbar.top_shadow_GC, 277 lx, ly, lx + lw - 1, ly); 278 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); 283 } 284 else 285 { 286 /* Left border */ 287 XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw), 288 sbw->scrollbar.top_shadow_GC, 289 lx, ly, lx, ly + lh - 1); 290 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); 295 } 296 return; 297 } 298 299 if (fill) 300 { 301 XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw), 302 sbw->scrollbar.gc, 303 lx, ly, (unsigned int) lw, (unsigned int) lh); 304 305 if (!(sbw->scrollbar.orientation == XtorientHorizontal)) 306 { 307 /* Left border */ 308 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw), 309 sbw->scrollbar.top_shadow_GC, 310 lx, ly, lx, ly + lh - 1); 311 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); 316 } 317 else 318 { 319 /* Top border */ 320 XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw), 321 sbw->scrollbar.top_shadow_GC, 322 lx, ly, lx + lw - 1, ly); 323 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); 328 } 329 } 330 else 331 { 332 XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw), 333 lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE); 334 } 335} 336 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. 340 */ 341 342 static void 343PaintThumb(sbw) 344 ScrollbarWidget sbw; 345{ 346 Position oldtop, oldbot, newtop, newbot; 347 Dimension margin, tzl; 348 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; 355 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)) 361 { 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); 370 371 /* Only draw the missing shadows */ 372 FillArea(sbw, newtop, newbot, 0, 1); 373 } 374} 375 376 static void 377PaintArrows(sbw) 378 ScrollbarWidget sbw; 379{ 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 411 /* horizontal arrows require that x and y coordinates be swapped */ 412 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 } 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); 453 } 454} 455 456 static void 457Destroy(w) 458 Widget w; 459{ 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); 466} 467 468 static void 469CreateGC(w) 470 Widget w; 471{ 472 ScrollbarWidget sbw = (ScrollbarWidget) w; 473 XGCValues gcValues; 474 XtGCMask mask; 475 unsigned int depth = 1; 476 477 if (sbw->scrollbar.thumb == XtUnspecifiedPixmap) 478 { 479 sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w), 480 (Pixel) 1, (Pixel) 0, depth); 481 } 482 else if (sbw->scrollbar.thumb != None) 483 { 484 Window root; 485 int x, y; 486 unsigned int width, height, bw; 487 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.")); 491 } 492 493 gcValues.foreground = sbw->scrollbar.foreground; 494 gcValues.background = sbw->core.background_pixel; 495 mask = GCForeground | GCBackground; 496 497 if (sbw->scrollbar.thumb != None) 498 { 499 gcValues.fill_style = FillSolid; 500 mask |= GCFillStyle; 501 } 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); 505} 506 507 static void 508SetDimensions(sbw) 509 ScrollbarWidget sbw; 510{ 511 if (sbw->scrollbar.orientation == XtorientVertical) 512 { 513 sbw->scrollbar.length = sbw->core.height; 514 sbw->scrollbar.thickness = sbw->core.width; 515 } 516 else 517 { 518 sbw->scrollbar.length = sbw->core.width; 519 sbw->scrollbar.thickness = sbw->core.height; 520 } 521} 522 523 static void 524Initialize(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; 529{ 530 ScrollbarWidget sbw = (ScrollbarWidget) new; 531 532 CreateGC(new); 533 AllocTopShadowGC(new); 534 AllocBotShadowGC(new); 535 536 if (sbw->core.width == 0) 537 sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical) 538 ? sbw->scrollbar.thickness : sbw->scrollbar.length; 539 540 if (sbw->core.height == 0) 541 sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal) 542 ? sbw->scrollbar.thickness : sbw->scrollbar.length; 543 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; 549} 550 551 static void 552Realize(w, valueMask, attributes) 553 Widget w; 554 Mask *valueMask; 555 XSetWindowAttributes *attributes; 556{ 557 /* The Simple widget actually stuffs the value in the valuemask. */ 558 (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize) 559 (w, valueMask, attributes); 560} 561 562 static Boolean 563SetValues(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; 569{ 570 ScrollbarWidget sbw = (ScrollbarWidget) current; 571 ScrollbarWidget dsbw = (ScrollbarWidget) desired; 572 Boolean redraw = FALSE; 573 574/* 575 * If these values are outside the acceptable range ignore them... 576 */ 577 if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0) 578 dsbw->scrollbar.top = sbw->scrollbar.top; 579 580 if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0) 581 dsbw->scrollbar.shown = sbw->scrollbar.shown; 582 583/* 584 * Change colors and stuff... 585 */ 586 if (XtIsRealized(desired)) 587 { 588 if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground || 589 sbw->core.background_pixel != dsbw->core.background_pixel || 590 sbw->scrollbar.thumb != dsbw->scrollbar.thumb) 591 { 592 XtReleaseGC(desired, sbw->scrollbar.gc); 593 CreateGC (desired); 594 redraw = TRUE; 595 } 596 if (sbw->scrollbar.top != dsbw->scrollbar.top || 597 sbw->scrollbar.shown != dsbw->scrollbar.shown) 598 redraw = TRUE; 599 } 600 return redraw; 601} 602 603 static void 604Resize(w) 605 Widget w; 606{ 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); 611} 612 613 614 static void 615Redisplay(w, event, region) 616 Widget w; 617 XEvent *event; 618 Region region; 619{ 620 ScrollbarWidget sbw = (ScrollbarWidget) w; 621 int x, y; 622 unsigned int width, height; 623 624 _Xaw3dDrawShadows(w, event, region, FALSE); 625 626 if (sbw->scrollbar.orientation == XtorientHorizontal) 627 { 628 x = sbw->scrollbar.topLoc; 629 y = 1; 630 width = sbw->scrollbar.shownLength; 631 height = sbw->core.height - 2; 632 } 633 else 634 { 635 x = 1; 636 y = sbw->scrollbar.topLoc; 637 width = sbw->core.width - 2; 638 height = sbw->scrollbar.shownLength; 639 } 640 if (region == NULL || 641 XRectInRegion (region, x, y, width, height) != RectangleOut) 642 { 643 /* Forces entire thumb to be painted. */ 644 sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1); 645 PaintThumb (sbw); 646 } 647 /* we'd like to be region aware here!!!! */ 648 PaintArrows(sbw); 649} 650 651 652 static Boolean 653CompareEvents(oldEvent, newEvent) 654 XEvent *oldEvent, *newEvent; 655{ 656#define Check(field) if (newEvent->field != oldEvent->field) return False; 657 658 Check(xany.display); 659 Check(xany.type); 660 Check(xany.window); 661 662 switch (newEvent->type) 663 { 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; 683 } 684#undef Check 685 686 return True; 687} 688 689struct EventData 690{ 691 XEvent *oldEvent; 692 int count; 693}; 694 695 static Bool 696PeekNotifyEvent(dpy, event, args) 697 Display *dpy; 698 XEvent *event; 699 char *args; 700{ 701 struct EventData *eventData = (struct EventData*)args; 702 703 return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */ 704 || CompareEvents(event, eventData->oldEvent)); 705} 706 707 708 static Boolean 709LookAhead(w, event) 710 Widget w; 711 XEvent *event; 712{ 713 XEvent newEvent; 714 struct EventData eventData; 715 716 if (QLength (XtDisplay (w)) == 0) 717 return False; 718 719 eventData.count = 0; 720 eventData.oldEvent = event; 721 722 XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData); 723 724 return CompareEvents (event, &newEvent); 725} 726 727 728 static void 729ExtractPosition(event, x, y, state) 730 XEvent *event; 731 Position *x, *y; /* RETURN */ 732 unsigned int *state; /* RETURN */ 733{ 734 switch (event->type) 735 { 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; 767 } 768} 769 770 static void 771HandleThumb(w, event, params, num_params) 772 Widget w; 773 XEvent *event; 774 String *params; 775 Cardinal *num_params; 776{ 777 Position x, y, loc; 778 ScrollbarWidget sbw = (ScrollbarWidget) w; 779 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)) 787 { 788 XtCallActionProc(w, "MoveThumb", event, params, *num_params); 789 XtCallActionProc(w, "NotifyThumb", event, params, *num_params); 790 } 791} 792 793 static void 794RepeatNotify(client_data, idp) 795 XtPointer client_data; 796 XtIntervalId *idp UNUSED; 797{ 798 ScrollbarWidget sbw = (ScrollbarWidget) client_data; 799 int call_data; 800 char mode = sbw->scrollbar.scroll_mode; 801 unsigned long rep; 802 803 if (mode == SMODE_NONE || mode == SMODE_CONT) 804 { 805 sbw->scrollbar.timer_id = (XtIntervalId)0; 806 return; 807 } 808 809 if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP) 810 { 811 call_data = ONE_LINE_DATA; 812 rep = LINE_REPEAT; 813 } 814 else 815 { 816 call_data = ONE_PAGE_DATA; 817 rep = PAGE_REPEAT; 818 } 819 820 if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP) 821 call_data = -call_data; 822 823 XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)(long_u)call_data); 824 825 sbw->scrollbar.timer_id = 826 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw), 827 rep, 828 RepeatNotify, 829 client_data); 830} 831 832/* 833 * Same as above, but for floating numbers. 834 */ 835 static float 836FloatInRange(num, small, big) 837 float num, small, big; 838{ 839 return (num < small) ? small : ((num > big) ? big : num); 840} 841 842 static void 843ScrollOneLineUp(w, event, params, num_params) 844 Widget w; 845 XEvent *event; 846 String *params UNUSED; 847 Cardinal *num_params UNUSED; 848{ 849 ScrollSome(w, event, -ONE_LINE_DATA); 850} 851 852 static void 853ScrollOneLineDown(w, event, params, num_params) 854 Widget w; 855 XEvent *event; 856 String *params UNUSED; 857 Cardinal *num_params UNUSED; 858{ 859 ScrollSome(w, event, ONE_LINE_DATA); 860} 861 862 static void 863ScrollPageDown(w, event, params, num_params) 864 Widget w; 865 XEvent *event; 866 String *params UNUSED; 867 Cardinal *num_params UNUSED; 868{ 869 ScrollSome(w, event, ONE_PAGE_DATA); 870} 871 872 static void 873ScrollPageUp(w, event, params, num_params) 874 Widget w; 875 XEvent *event; 876 String *params UNUSED; 877 Cardinal *num_params UNUSED; 878{ 879 ScrollSome(w, event, -ONE_PAGE_DATA); 880} 881 882 static void 883ScrollSome(w, event, call_data) 884 Widget w; 885 XEvent *event; 886 int call_data; 887{ 888 ScrollbarWidget sbw = (ScrollbarWidget) w; 889 890 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */ 891 return; 892 893 if (LookAhead(w, event)) 894 return; 895 896 sbw->scrollbar.scroll_mode = SMODE_LINE_UP; 897 XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data); 898} 899 900 static void 901NotifyScroll(w, event, params, num_params) 902 Widget w; 903 XEvent *event; 904 String *params UNUSED; 905 Cardinal *num_params UNUSED; 906{ 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; 913 914 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */ 915 return; 916 917 if (LookAhead (w, event)) 918 return; 919 920 ExtractPosition(event, &x, &y, &state); 921 loc = PICKLENGTH(sbw, x, y); 922 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; 927 928 /* 929 * handle CTRL modifier 930 */ 931 if (state & ControlMask) 932 { 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; 938 } 939 /* 940 * handle first arrow zone 941 */ 942 else if (loc < (Position)arrow_size) 943 { 944 call_data = -ONE_LINE_DATA; 945 sbw->scrollbar.scroll_mode = SMODE_LINE_UP; 946 delay = LINE_DELAY; 947 } 948 949 /* 950 * handle last arrow zone 951 */ 952 else if (loc > (Position)(sbw->scrollbar.length - arrow_size)) 953 { 954 call_data = ONE_LINE_DATA; 955 sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN; 956 delay = LINE_DELAY; 957 } 958 959 /* 960 * handle zone "above" the thumb 961 */ 962 else if (loc < sbw->scrollbar.topLoc) 963 { 964 call_data = -ONE_PAGE_DATA; 965 sbw->scrollbar.scroll_mode = SMODE_PAGE_UP; 966 delay = PAGE_DELAY; 967 } 968 969 /* 970 * handle zone "below" the thumb 971 */ 972 else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength) 973 { 974 call_data = ONE_PAGE_DATA; 975 sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN; 976 delay = PAGE_DELAY; 977 } 978 979 if (call_data) 980 XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data); 981 982 /* establish autoscroll */ 983 if (delay) 984 sbw->scrollbar.timer_id = 985 XtAppAddTimeOut(XtWidgetToApplicationContext(w), 986 delay, RepeatNotify, (XtPointer)w); 987} 988 989 static void 990EndScroll(w, event, params, num_params) 991 Widget w; 992 XEvent *event UNUSED; 993 String *params UNUSED; 994 Cardinal *num_params UNUSED; 995{ 996 ScrollbarWidget sbw = (ScrollbarWidget) w; 997 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 */ 1002} 1003 1004 static float 1005FractionLoc(sbw, x, y) 1006 ScrollbarWidget sbw; 1007 int x, y; 1008{ 1009 int margin; 1010 float height, width; 1011 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); 1018} 1019 1020 static void 1021MoveThumb(w, event, params, num_params) 1022 Widget w; 1023 XEvent *event; 1024 String *params UNUSED; 1025 Cardinal *num_params UNUSED; 1026{ 1027 ScrollbarWidget sbw = (ScrollbarWidget)w; 1028 Position x, y; 1029 float top; 1030 char old_mode = sbw->scrollbar.scroll_mode; 1031 1032 sbw->scrollbar.scroll_mode = SMODE_CONT; /* indicate continuous scroll */ 1033 1034 if (LookAhead(w, event)) 1035 return; 1036 1037 if (!event->xmotion.same_screen) 1038 return; 1039 1040 ExtractPosition(event, &x, &y, (unsigned int *)NULL); 1041 1042 top = FractionLoc(sbw, x, y); 1043 1044 if (old_mode != SMODE_CONT) /* start dragging: set offset */ 1045 { 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; 1050 } 1051 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); 1058 1059 sbw->scrollbar.top = top; 1060 PaintThumb(sbw); 1061 XFlush(XtDisplay(w)); /* re-draw it before Notifying */ 1062} 1063 1064 1065 static void 1066NotifyThumb(w, event, params, num_params) 1067 Widget w; 1068 XEvent *event; 1069 String *params UNUSED; 1070 Cardinal *num_params UNUSED; 1071{ 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; 1079 1080 if (LookAhead(w, event)) 1081 return; 1082 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); 1089} 1090 1091 static void 1092AllocTopShadowGC(w) 1093 Widget w; 1094{ 1095 ScrollbarWidget sbw = (ScrollbarWidget) w; 1096 XtGCMask valuemask; 1097 XGCValues myXGCV; 1098 1099 valuemask = GCForeground; 1100 myXGCV.foreground = sbw->scrollbar.top_shadow_pixel; 1101 sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV); 1102} 1103 1104 static void 1105AllocBotShadowGC(w) 1106 Widget w; 1107{ 1108 ScrollbarWidget sbw = (ScrollbarWidget) w; 1109 XtGCMask valuemask; 1110 XGCValues myXGCV; 1111 1112 valuemask = GCForeground; 1113 myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel; 1114 sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV); 1115} 1116 1117 static void 1118_Xaw3dDrawShadows(gw, event, region, out) 1119 Widget gw; 1120 XEvent *event UNUSED; 1121 Region region; 1122 int out; 1123{ 1124 XPoint pt[6]; 1125 ScrollbarWidget sbw = (ScrollbarWidget) gw; 1126 Dimension s = sbw->scrollbar.shadow_width; 1127 /* 1128 * draw the shadows using the core part width and height, 1129 * and the scrollbar part shadow_width. 1130 * 1131 * no point to do anything if the shadow_width is 0 or the 1132 * widget has not been realized. 1133 */ 1134 if (s > 0 && XtIsRealized(gw)) 1135 { 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; 1143 1144 if (out) 1145 { 1146 top = sbw->scrollbar.top_shadow_GC; 1147 bot = sbw->scrollbar.bot_shadow_GC; 1148 } 1149 else 1150 { 1151 top = sbw->scrollbar.bot_shadow_GC; 1152 bot = sbw->scrollbar.top_shadow_GC; 1153 } 1154 1155 /* top-left shadow */ 1156 if ((region == NULL) || 1157 (XRectInRegion (region, 0, 0, w, s) != RectangleOut) || 1158 (XRectInRegion (region, 0, 0, s, h) != RectangleOut)) 1159 { 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); 1167 } 1168 1169 /* bottom-right shadow */ 1170 if ((region == NULL) || 1171 (XRectInRegion (region, 0, hms, w, s) != RectangleOut) || 1172 (XRectInRegion (region, wms, 0, s, h) != RectangleOut)) 1173 { 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); 1181 } 1182 } 1183} 1184 1185 1186/* 1187 * Set the scroll bar to the given location. 1188 */ 1189 void 1190vim_XawScrollbarSetThumb(w, top, shown, max) 1191 Widget w; 1192 double top, shown, max; 1193{ 1194 ScrollbarWidget sbw = (ScrollbarWidget) w; 1195 1196 if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if still thumbing */ 1197 return; 1198 1199 sbw->scrollbar.max = (max > 1.0) ? 1.0 : 1200 (max >= 0.0) ? max : sbw->scrollbar.max; 1201 1202 sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max : 1203 (top >= 0.0) ? top : sbw->scrollbar.top; 1204 1205 sbw->scrollbar.shown = (shown > 1.0) ? 1.0 : 1206 (shown >= 0.0) ? shown : sbw->scrollbar.shown; 1207 1208 PaintThumb(sbw); 1209} 1210