|
|
1.1 ! root 1: /* ! 2: * tkScrollbar.c -- ! 3: * ! 4: * This module implements a scrollbar widgets for the Tk ! 5: * toolkit. A scrollbar displays a slider and two arrows; ! 6: * mouse clicks on features within the scrollbar cause ! 7: * scrolling commands to be invoked. ! 8: * ! 9: * Copyright 1990-1992 Regents of the University of California. ! 10: * Permission to use, copy, modify, and distribute this ! 11: * software and its documentation for any purpose and without ! 12: * fee is hereby granted, provided that the above copyright ! 13: * notice appear in all copies. The University of California ! 14: * makes no representations about the suitability of this ! 15: * software for any purpose. It is provided "as is" without ! 16: * express or implied warranty. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkScrollbar.c,v 1.35 92/05/22 16:57:27 ouster Exp $ SPRITE (Berkeley)"; ! 21: #endif ! 22: ! 23: #include "tkconfig.h" ! 24: #include "default.h" ! 25: #include "tkint.h" ! 26: ! 27: /* ! 28: * A data structure of the following type is kept for each scrollbar ! 29: * widget managed by this file: ! 30: */ ! 31: ! 32: typedef struct { ! 33: Tk_Window tkwin; /* Window that embodies the scrollbar. NULL ! 34: * means that the window has been destroyed ! 35: * but the data structures haven't yet been ! 36: * cleaned up.*/ ! 37: Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ ! 38: Tk_Uid orientUid; /* Orientation for window ("vertical" or ! 39: * "horizontal"). */ ! 40: int vertical; /* Non-zero means vertical orientation ! 41: * requested, zero means horizontal. */ ! 42: int width; /* Desired narrow dimension of scrollbar, ! 43: * in pixels. */ ! 44: char *command; /* Command prefix to use when invoking ! 45: * scrolling commands. NULL means don't ! 46: * invoke commands. Malloc'ed. */ ! 47: int commandSize; /* Number of non-NULL bytes in command. */ ! 48: int repeatDelay; /* How long to wait before auto-repeating ! 49: * on scrolling actions (in ms). */ ! 50: int repeatInterval; /* Interval between autorepeats (in ms). */ ! 51: ! 52: /* ! 53: * Information used when displaying widget: ! 54: */ ! 55: ! 56: int borderWidth; /* Width of 3-D borders. */ ! 57: Tk_3DBorder bgBorder; /* Used for drawing background. */ ! 58: Tk_3DBorder fgBorder; /* For drawing foreground shapes. */ ! 59: Tk_3DBorder activeBorder; /* For drawing foreground shapes when ! 60: * active (i.e. when mouse is positioned ! 61: * over element). NULL means use fgBorder. */ ! 62: GC copyGC; /* Used for copying from pixmap onto screen. */ ! 63: int relief; /* Indicates whether window as a whole is ! 64: * raised, sunken, or flat. */ ! 65: int offset; /* Zero if relief is TK_RELIEF_FLAT, ! 66: * borderWidth otherwise. Indicates how ! 67: * much interior stuff must be offset from ! 68: * outside edges to leave room for border. */ ! 69: int arrowLength; /* Length of arrows along long dimension of ! 70: * scrollbar. Recomputed on window size ! 71: * changes. */ ! 72: int sliderFirst; /* Pixel coordinate of top or left edge ! 73: * of slider area, including border. */ ! 74: int sliderLast; /* Coordinate of pixel just after bottom ! 75: * or right edge of slider area, including ! 76: * border. */ ! 77: int mouseField; /* Indicates which scrollbar element is ! 78: * under mouse (e.g. TOP_ARROW; see below ! 79: * for possible values). */ ! 80: int pressField; /* Field in which button was pressed, or -1 ! 81: * if no button is down. */ ! 82: int pressPos; /* Position of mouse when button was ! 83: * pressed (y for vertical scrollbar, x ! 84: * for horizontal). */ ! 85: int pressFirstUnit; /* Value of "firstUnit" when mouse button ! 86: * was pressed. */ ! 87: ! 88: /* ! 89: * Information describing the application related to the scrollbar. ! 90: * This information is provided by the application by invoking the ! 91: * "set" widget command. ! 92: */ ! 93: ! 94: int totalUnits; /* Total dimension of application, in ! 95: * units. */ ! 96: int windowUnits; /* Maximum number of units that can ! 97: * be displayed in the window at ! 98: * once. */ ! 99: int firstUnit; /* Number of last unit visible in ! 100: * application's window. */ ! 101: int lastUnit; /* Index of last unit visible in window. */ ! 102: ! 103: /* ! 104: * Miscellaneous information: ! 105: */ ! 106: ! 107: Cursor cursor; /* Current cursor for window, or None. */ ! 108: Tk_TimerToken autoRepeat; /* Token for auto-repeat that's ! 109: * currently in progress. NULL means no ! 110: * auto-repeat in progress. */ ! 111: int flags; /* Various flags; see below for ! 112: * definitions. */ ! 113: } Scrollbar; ! 114: ! 115: /* ! 116: * Legal values for "mouseField" field of Scrollbar structures. These ! 117: * are also the return values from the ScrollbarPosition procedure. ! 118: */ ! 119: ! 120: #define TOP_ARROW 1 ! 121: #define TOP_GAP 2 ! 122: #define SLIDER 3 ! 123: #define BOTTOM_GAP 4 ! 124: #define BOTTOM_ARROW 5 ! 125: #define OUTSIDE 6 ! 126: ! 127: /* ! 128: * Flag bits for scrollbars: ! 129: * ! 130: * REDRAW_PENDING: Non-zero means a DoWhenIdle handler ! 131: * has already been queued to redraw ! 132: * this window. ! 133: */ ! 134: ! 135: #define REDRAW_PENDING 1 ! 136: ! 137: /* ! 138: * Information used for argv parsing. ! 139: */ ! 140: ! 141: ! 142: static Tk_ConfigSpec configSpecs[] = { ! 143: {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background", ! 144: DEF_SCROLLBAR_ACTIVE_FG_COLOR, Tk_Offset(Scrollbar, activeBorder), ! 145: TK_CONFIG_COLOR_ONLY}, ! 146: {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background", ! 147: DEF_SCROLLBAR_ACTIVE_FG_MONO, Tk_Offset(Scrollbar, activeBorder), ! 148: TK_CONFIG_MONO_ONLY}, ! 149: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 150: DEF_SCROLLBAR_BG_COLOR, Tk_Offset(Scrollbar, bgBorder), ! 151: TK_CONFIG_COLOR_ONLY}, ! 152: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 153: DEF_SCROLLBAR_BG_MONO, Tk_Offset(Scrollbar, bgBorder), ! 154: TK_CONFIG_MONO_ONLY}, ! 155: {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, ! 156: (char *) NULL, 0, 0}, ! 157: {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, ! 158: (char *) NULL, 0, 0}, ! 159: {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", ! 160: DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(Scrollbar, borderWidth), 0}, ! 161: {TK_CONFIG_STRING, "-command", "command", "Command", ! 162: DEF_SCROLLBAR_COMMAND, Tk_Offset(Scrollbar, command), 0}, ! 163: {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", ! 164: DEF_SCROLLBAR_CURSOR, Tk_Offset(Scrollbar, cursor), TK_CONFIG_NULL_OK}, ! 165: {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, ! 166: (char *) NULL, 0, 0}, ! 167: {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", ! 168: DEF_SCROLLBAR_FG_COLOR, Tk_Offset(Scrollbar, fgBorder), ! 169: TK_CONFIG_COLOR_ONLY}, ! 170: {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", ! 171: DEF_SCROLLBAR_FG_MONO, Tk_Offset(Scrollbar, fgBorder), ! 172: TK_CONFIG_MONO_ONLY}, ! 173: {TK_CONFIG_UID, "-orient", "orient", "Orient", ! 174: DEF_SCROLLBAR_ORIENT, Tk_Offset(Scrollbar, orientUid), 0}, ! 175: {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", ! 176: DEF_SCROLLBAR_RELIEF, Tk_Offset(Scrollbar, relief), 0}, ! 177: {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", ! 178: DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(Scrollbar, repeatDelay), 0}, ! 179: {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", ! 180: DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(Scrollbar, repeatInterval), 0}, ! 181: {TK_CONFIG_PIXELS, "-width", "width", "Width", ! 182: DEF_SCROLLBAR_WIDTH, Tk_Offset(Scrollbar, width), 0}, ! 183: {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, ! 184: (char *) NULL, 0, 0} ! 185: }; ! 186: ! 187: /* ! 188: * Forward declarations for procedures defined later in this file: ! 189: */ ! 190: ! 191: static void ComputeScrollbarGeometry _ANSI_ARGS_(( ! 192: Scrollbar *scrollPtr)); ! 193: static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp, ! 194: Scrollbar *scrollPtr, int argc, char **argv, ! 195: int flags)); ! 196: static void DestroyScrollbar _ANSI_ARGS_((ClientData clientData)); ! 197: static void DisplayScrollbar _ANSI_ARGS_((ClientData clientData)); ! 198: static void EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr)); ! 199: static void ScrollbarEventProc _ANSI_ARGS_((ClientData clientData, ! 200: XEvent *eventPtr)); ! 201: static void ScrollbarMouseProc _ANSI_ARGS_((ClientData clientData, ! 202: XEvent *eventPtr)); ! 203: static void ScrollbarNewField _ANSI_ARGS_((Scrollbar *scrollPtr, ! 204: int field)); ! 205: static int ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr, ! 206: int x, int y)); ! 207: static void ScrollbarTimerProc _ANSI_ARGS_(( ! 208: ClientData clientData)); ! 209: static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData, ! 210: Tcl_Interp *, int argc, char **argv)); ! 211: static void ScrollCmd _ANSI_ARGS_((Scrollbar *scrollPtr, ! 212: int unit)); ! 213: ! 214: /* ! 215: *-------------------------------------------------------------- ! 216: * ! 217: * Tk_ScrollbarCmd -- ! 218: * ! 219: * This procedure is invoked to process the "scrollbar" Tcl ! 220: * command. See the user documentation for details on what ! 221: * it does. ! 222: * ! 223: * Results: ! 224: * A standard Tcl result. ! 225: * ! 226: * Side effects: ! 227: * See the user documentation. ! 228: * ! 229: *-------------------------------------------------------------- ! 230: */ ! 231: ! 232: int ! 233: Tk_ScrollbarCmd(clientData, interp, argc, argv) ! 234: ClientData clientData; /* Main window associated with ! 235: * interpreter. */ ! 236: Tcl_Interp *interp; /* Current interpreter. */ ! 237: int argc; /* Number of arguments. */ ! 238: char **argv; /* Argument strings. */ ! 239: { ! 240: Tk_Window tkwin = (Tk_Window) clientData; ! 241: register Scrollbar *scrollPtr; ! 242: Tk_Window new; ! 243: ! 244: if (argc < 2) { ! 245: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 246: argv[0], " pathName ?options?\"", (char *) NULL); ! 247: return TCL_ERROR; ! 248: } ! 249: ! 250: new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); ! 251: if (new == NULL) { ! 252: return TCL_ERROR; ! 253: } ! 254: ! 255: /* ! 256: * Initialize fields that won't be initialized by ConfigureScrollbar, ! 257: * or which ConfigureScrollbar expects to have reasonable values ! 258: * (e.g. resource pointers). ! 259: */ ! 260: ! 261: scrollPtr = (Scrollbar *) ckalloc(sizeof(Scrollbar)); ! 262: scrollPtr->tkwin = new; ! 263: scrollPtr->interp = interp; ! 264: scrollPtr->command = NULL; ! 265: scrollPtr->bgBorder = NULL; ! 266: scrollPtr->fgBorder = NULL; ! 267: scrollPtr->activeBorder = NULL; ! 268: scrollPtr->copyGC = None; ! 269: scrollPtr->mouseField = OUTSIDE; ! 270: scrollPtr->pressField = -1; ! 271: scrollPtr->totalUnits = 0; ! 272: scrollPtr->windowUnits = 0; ! 273: scrollPtr->firstUnit = 0; ! 274: scrollPtr->lastUnit = 0; ! 275: scrollPtr->cursor = None; ! 276: scrollPtr->autoRepeat = NULL; ! 277: scrollPtr->flags = 0; ! 278: ! 279: Tk_SetClass(scrollPtr->tkwin, "Scrollbar"); ! 280: Tk_CreateEventHandler(scrollPtr->tkwin, ExposureMask|StructureNotifyMask, ! 281: ScrollbarEventProc, (ClientData) scrollPtr); ! 282: Tk_CreateEventHandler(scrollPtr->tkwin, EnterWindowMask|LeaveWindowMask ! 283: |PointerMotionMask|ButtonPressMask|ButtonReleaseMask, ! 284: ScrollbarMouseProc, (ClientData) scrollPtr); ! 285: Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, ! 286: (ClientData) scrollPtr, (void (*)()) NULL); ! 287: if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) { ! 288: goto error; ! 289: } ! 290: ! 291: interp->result = Tk_PathName(scrollPtr->tkwin); ! 292: return TCL_OK; ! 293: ! 294: error: ! 295: Tk_DestroyWindow(scrollPtr->tkwin); ! 296: return TCL_ERROR; ! 297: } ! 298: ! 299: /* ! 300: *-------------------------------------------------------------- ! 301: * ! 302: * ScrollbarWidgetCmd -- ! 303: * ! 304: * This procedure is invoked to process the Tcl command ! 305: * that corresponds to a widget managed by this module. ! 306: * See the user documentation for details on what it does. ! 307: * ! 308: * Results: ! 309: * A standard Tcl result. ! 310: * ! 311: * Side effects: ! 312: * See the user documentation. ! 313: * ! 314: *-------------------------------------------------------------- ! 315: */ ! 316: ! 317: static int ! 318: ScrollbarWidgetCmd(clientData, interp, argc, argv) ! 319: ClientData clientData; /* Information about scrollbar ! 320: * widget. */ ! 321: Tcl_Interp *interp; /* Current interpreter. */ ! 322: int argc; /* Number of arguments. */ ! 323: char **argv; /* Argument strings. */ ! 324: { ! 325: register Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 326: int result = TCL_OK; ! 327: int length; ! 328: char c; ! 329: ! 330: if (argc < 2) { ! 331: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 332: argv[0], " option ?arg arg ...?\"", (char *) NULL); ! 333: return TCL_ERROR; ! 334: } ! 335: Tk_Preserve((ClientData) scrollPtr); ! 336: c = argv[1][0]; ! 337: length = strlen(argv[1]); ! 338: if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { ! 339: if (argc == 2) { ! 340: result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, ! 341: (char *) scrollPtr, (char *) NULL, 0); ! 342: } else if (argc == 3) { ! 343: result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, ! 344: (char *) scrollPtr, argv[2], 0); ! 345: } else { ! 346: result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, ! 347: TK_CONFIG_ARGV_ONLY); ! 348: } ! 349: } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { ! 350: if (argc != 2) { ! 351: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 352: argv[0], " get\"", (char *) NULL); ! 353: goto error; ! 354: } ! 355: sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits, ! 356: scrollPtr->windowUnits, scrollPtr->firstUnit, ! 357: scrollPtr->lastUnit); ! 358: } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { ! 359: int totalUnits, windowUnits, firstUnit, lastUnit; ! 360: ! 361: if (argc != 6) { ! 362: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 363: argv[0], ! 364: " set totalUnits windowUnits firstUnit lastUnit\"", ! 365: (char *) NULL); ! 366: goto error; ! 367: } ! 368: if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) { ! 369: goto error; ! 370: } ! 371: if (totalUnits < 0) { ! 372: sprintf(interp->result, "illegal totalUnits %d", totalUnits); ! 373: goto error; ! 374: } ! 375: if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) { ! 376: goto error; ! 377: } ! 378: if (windowUnits < 0) { ! 379: sprintf(interp->result, "illegal windowUnits %d", windowUnits); ! 380: goto error; ! 381: } ! 382: if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) { ! 383: goto error; ! 384: } ! 385: if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) { ! 386: goto error; ! 387: } ! 388: if (totalUnits > 0) { ! 389: if (lastUnit < firstUnit) { ! 390: sprintf(interp->result, "illegal lastUnit %d", lastUnit); ! 391: goto error; ! 392: } ! 393: } else { ! 394: firstUnit = lastUnit = 0; ! 395: } ! 396: scrollPtr->totalUnits = totalUnits; ! 397: scrollPtr->windowUnits = windowUnits; ! 398: scrollPtr->firstUnit = firstUnit; ! 399: scrollPtr->lastUnit = lastUnit; ! 400: ComputeScrollbarGeometry(scrollPtr); ! 401: EventuallyRedraw(scrollPtr); ! 402: } else { ! 403: Tcl_AppendResult(interp, "bad option \"", argv[1], ! 404: "\": must be configure, get, or set", (char *) NULL); ! 405: goto error; ! 406: } ! 407: Tk_Release((ClientData) scrollPtr); ! 408: return result; ! 409: ! 410: error: ! 411: Tk_Release((ClientData) scrollPtr); ! 412: return TCL_ERROR; ! 413: } ! 414: ! 415: /* ! 416: *---------------------------------------------------------------------- ! 417: * ! 418: * DestroyScrollbar -- ! 419: * ! 420: * This procedure is invoked by Tk_EventuallyFree or Tk_Release ! 421: * to clean up the internal structure of a scrollbar at a safe time ! 422: * (when no-one is using it anymore). ! 423: * ! 424: * Results: ! 425: * None. ! 426: * ! 427: * Side effects: ! 428: * Everything associated with the scrollbar is freed up. ! 429: * ! 430: *---------------------------------------------------------------------- ! 431: */ ! 432: ! 433: static void ! 434: DestroyScrollbar(clientData) ! 435: ClientData clientData; /* Info about scrollbar widget. */ ! 436: { ! 437: register Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 438: ! 439: if (scrollPtr->command != NULL) { ! 440: ckfree(scrollPtr->command); ! 441: } ! 442: if (scrollPtr->bgBorder != NULL) { ! 443: Tk_Free3DBorder(scrollPtr->bgBorder); ! 444: } ! 445: if (scrollPtr->fgBorder != NULL) { ! 446: Tk_Free3DBorder(scrollPtr->fgBorder); ! 447: } ! 448: if (scrollPtr->activeBorder != NULL) { ! 449: Tk_Free3DBorder(scrollPtr->activeBorder); ! 450: } ! 451: if (scrollPtr->copyGC != None) { ! 452: Tk_FreeGC(scrollPtr->copyGC); ! 453: } ! 454: if (scrollPtr->cursor != None) { ! 455: Tk_FreeCursor(scrollPtr->cursor); ! 456: } ! 457: ckfree((char *) scrollPtr); ! 458: } ! 459: ! 460: /* ! 461: *---------------------------------------------------------------------- ! 462: * ! 463: * ConfigureScrollbar -- ! 464: * ! 465: * This procedure is called to process an argv/argc list, plus ! 466: * the Tk option database, in order to configure (or ! 467: * reconfigure) a scrollbar widget. ! 468: * ! 469: * Results: ! 470: * The return value is a standard Tcl result. If TCL_ERROR is ! 471: * returned, then interp->result contains an error message. ! 472: * ! 473: * Side effects: ! 474: * Configuration information, such as colors, border width, ! 475: * etc. get set for scrollPtr; old resources get freed, ! 476: * if there were any. ! 477: * ! 478: *---------------------------------------------------------------------- ! 479: */ ! 480: ! 481: static int ! 482: ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) ! 483: Tcl_Interp *interp; /* Used for error reporting. */ ! 484: register Scrollbar *scrollPtr; /* Information about widget; may or ! 485: * may not already have values for ! 486: * some fields. */ ! 487: int argc; /* Number of valid entries in argv. */ ! 488: char **argv; /* Arguments. */ ! 489: int flags; /* Flags to pass to ! 490: * Tk_ConfigureWidget. */ ! 491: { ! 492: int length; ! 493: XGCValues gcValues; ! 494: ! 495: if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, configSpecs, ! 496: argc, argv, (char *) scrollPtr, flags) != TCL_OK) { ! 497: return TCL_ERROR; ! 498: } ! 499: ! 500: /* ! 501: * A few options need special processing, such as parsing the ! 502: * orientation or setting the background from a 3-D border. ! 503: */ ! 504: ! 505: length = strlen(scrollPtr->orientUid); ! 506: if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { ! 507: scrollPtr->vertical = 1; ! 508: } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { ! 509: scrollPtr->vertical = 0; ! 510: } else { ! 511: Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, ! 512: "\": must be vertical or horizontal", (char *) NULL); ! 513: return TCL_ERROR; ! 514: } ! 515: ! 516: if (scrollPtr->command != NULL) { ! 517: scrollPtr->commandSize = strlen(scrollPtr->command); ! 518: } else { ! 519: scrollPtr->commandSize = 0; ! 520: } ! 521: ! 522: Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder); ! 523: ! 524: if (scrollPtr->copyGC == None) { ! 525: gcValues.graphics_exposures = False; ! 526: scrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures, ! 527: &gcValues); ! 528: } ! 529: ! 530: /* ! 531: * Register the desired geometry for the window (leave enough space ! 532: * for the two arrows plus a minimum-size slider, plus border around ! 533: * the whole window, if any). Then arrange for the window to be ! 534: * redisplayed. ! 535: */ ! 536: ! 537: ComputeScrollbarGeometry(scrollPtr); ! 538: EventuallyRedraw(scrollPtr); ! 539: return TCL_OK; ! 540: } ! 541: ! 542: /* ! 543: *-------------------------------------------------------------- ! 544: * ! 545: * DisplayScrollbar -- ! 546: * ! 547: * This procedure redraws the contents of a scrollbar window. ! 548: * It is invoked as a do-when-idle handler, so it only runs ! 549: * when there's nothing else for the application to do. ! 550: * ! 551: * Results: ! 552: * None. ! 553: * ! 554: * Side effects: ! 555: * Information appears on the screen. ! 556: * ! 557: *-------------------------------------------------------------- ! 558: */ ! 559: ! 560: static void ! 561: DisplayScrollbar(clientData) ! 562: ClientData clientData; /* Information about window. */ ! 563: { ! 564: register Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 565: register Tk_Window tkwin = scrollPtr->tkwin; ! 566: XPoint points[7]; ! 567: Tk_3DBorder border; ! 568: int relief, width, fieldLength; ! 569: Pixmap pixmap; ! 570: ! 571: if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { ! 572: goto done; ! 573: } ! 574: ! 575: if (scrollPtr->vertical) { ! 576: width = Tk_Width(tkwin) - 2*scrollPtr->offset; ! 577: } else { ! 578: width = Tk_Height(tkwin) - 2*scrollPtr->offset; ! 579: } ! 580: ! 581: /* ! 582: * In order to avoid screen flashes, this procedure redraws ! 583: * the scrollbar in a pixmap, then copies the pixmap to the ! 584: * screen in a single operation. This means that there's no ! 585: * point in time where the on-sreen image has been cleared. ! 586: */ ! 587: ! 588: pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 589: Tk_Width(tkwin), Tk_Height(tkwin), ! 590: Tk_DefaultDepth(Tk_Screen(tkwin))); ! 591: Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, scrollPtr->bgBorder, ! 592: 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), ! 593: scrollPtr->borderWidth, scrollPtr->relief); ! 594: ! 595: /* ! 596: * Draw the top or left arrow. The coordinates of the polygon ! 597: * points probably seem odd, but they were carefully chosen with ! 598: * respect to X's rules for filling polygons. These point choices ! 599: * cause the arrows to just fill the narrow dimension of the ! 600: * scrollbar and be properly centered. ! 601: */ ! 602: ! 603: if (scrollPtr->mouseField == TOP_ARROW) { ! 604: border = scrollPtr->activeBorder; ! 605: relief = scrollPtr->pressField == TOP_ARROW ? TK_RELIEF_SUNKEN ! 606: : TK_RELIEF_RAISED; ! 607: } else { ! 608: border = scrollPtr->fgBorder; ! 609: relief = TK_RELIEF_RAISED; ! 610: } ! 611: if (scrollPtr->vertical) { ! 612: points[0].x = scrollPtr->offset - 1; ! 613: points[0].y = scrollPtr->arrowLength + scrollPtr->offset; ! 614: points[1].x = width + scrollPtr->offset; ! 615: points[1].y = points[0].y; ! 616: points[2].x = width/2 + scrollPtr->offset; ! 617: points[2].y = scrollPtr->offset - 1; ! 618: Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border, ! 619: points, 3, scrollPtr->borderWidth, relief); ! 620: } else { ! 621: points[0].x = scrollPtr->arrowLength + scrollPtr->offset; ! 622: points[0].y = scrollPtr->offset - 1; ! 623: points[1].x = scrollPtr->offset; ! 624: points[1].y = width/2 + scrollPtr->offset; ! 625: points[2].x = points[0].x; ! 626: points[2].y = width + scrollPtr->offset; ! 627: Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border, ! 628: points, 3, scrollPtr->borderWidth, relief); ! 629: } ! 630: ! 631: /* ! 632: * Display the bottom or right arrow. ! 633: */ ! 634: ! 635: if (scrollPtr->mouseField == BOTTOM_ARROW) { ! 636: border = scrollPtr->activeBorder; ! 637: relief = scrollPtr->pressField == BOTTOM_ARROW ? TK_RELIEF_SUNKEN ! 638: : TK_RELIEF_RAISED; ! 639: } else { ! 640: border = scrollPtr->fgBorder; ! 641: relief = TK_RELIEF_RAISED; ! 642: } ! 643: if (scrollPtr->vertical) { ! 644: points[0].x = scrollPtr->offset; ! 645: points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength ! 646: - scrollPtr->offset; ! 647: points[1].x = width/2 + scrollPtr->offset; ! 648: points[1].y = Tk_Height(tkwin) - scrollPtr->offset; ! 649: points[2].x = width + scrollPtr->offset; ! 650: points[2].y = points[0].y; ! 651: Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border, ! 652: points, 3, scrollPtr->borderWidth, relief); ! 653: } else { ! 654: points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength ! 655: - scrollPtr->offset; ! 656: points[0].y = scrollPtr->offset - 1; ! 657: points[1].x = points[0].x; ! 658: points[1].y = width + scrollPtr->offset; ! 659: points[2].x = Tk_Width(tkwin) - scrollPtr->offset; ! 660: points[2].y = width/2 + scrollPtr->offset; ! 661: Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border, ! 662: points, 3, scrollPtr->borderWidth, relief); ! 663: } ! 664: ! 665: /* ! 666: * Display the slider. ! 667: */ ! 668: ! 669: if (scrollPtr->mouseField == SLIDER) { ! 670: border = scrollPtr->activeBorder; ! 671: relief = scrollPtr->pressField == SLIDER ? TK_RELIEF_SUNKEN ! 672: : TK_RELIEF_RAISED; ! 673: } else { ! 674: border = scrollPtr->fgBorder; ! 675: relief = TK_RELIEF_RAISED; ! 676: } ! 677: fieldLength = (scrollPtr->vertical ? Tk_Height(tkwin) : Tk_Width(tkwin)) ! 678: - 2*(scrollPtr->arrowLength + scrollPtr->offset); ! 679: if (fieldLength < 0) { ! 680: fieldLength = 0; ! 681: } ! 682: if (scrollPtr->vertical) { ! 683: Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, border, ! 684: 1 + scrollPtr->offset, scrollPtr->sliderFirst, ! 685: width-2, scrollPtr->sliderLast - scrollPtr->sliderFirst, ! 686: scrollPtr->borderWidth, relief); ! 687: } else { ! 688: Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, border, ! 689: scrollPtr->sliderFirst, 1 + scrollPtr->offset, ! 690: scrollPtr->sliderLast - scrollPtr->sliderFirst, width-2, ! 691: scrollPtr->borderWidth, relief); ! 692: } ! 693: ! 694: /* ! 695: * Copy the information from the off-screen pixmap onto the screen, ! 696: * then delete the pixmap. ! 697: */ ! 698: ! 699: XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), ! 700: scrollPtr->copyGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0); ! 701: XFreePixmap(Tk_Display(tkwin), pixmap); ! 702: ! 703: done: ! 704: scrollPtr->flags &= ~REDRAW_PENDING; ! 705: } ! 706: ! 707: /* ! 708: *-------------------------------------------------------------- ! 709: * ! 710: * ScrollbarEventProc -- ! 711: * ! 712: * This procedure is invoked by the Tk dispatcher for various ! 713: * events on scrollbars. ! 714: * ! 715: * Results: ! 716: * None. ! 717: * ! 718: * Side effects: ! 719: * When the window gets deleted, internal structures get ! 720: * cleaned up. When it gets exposed, it is redisplayed. ! 721: * ! 722: *-------------------------------------------------------------- ! 723: */ ! 724: ! 725: static void ! 726: ScrollbarEventProc(clientData, eventPtr) ! 727: ClientData clientData; /* Information about window. */ ! 728: XEvent *eventPtr; /* Information about event. */ ! 729: { ! 730: Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 731: ! 732: if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { ! 733: EventuallyRedraw(scrollPtr); ! 734: } else if (eventPtr->type == DestroyNotify) { ! 735: Tcl_DeleteCommand(scrollPtr->interp, Tk_PathName(scrollPtr->tkwin)); ! 736: scrollPtr->tkwin = NULL; ! 737: if (scrollPtr->flags & REDRAW_PENDING) { ! 738: Tk_CancelIdleCall(DisplayScrollbar, (ClientData) scrollPtr); ! 739: } ! 740: Tk_EventuallyFree((ClientData) scrollPtr, DestroyScrollbar); ! 741: } else if (eventPtr->type == ConfigureNotify) { ! 742: ComputeScrollbarGeometry(scrollPtr); ! 743: } ! 744: } ! 745: ! 746: /* ! 747: *---------------------------------------------------------------------- ! 748: * ! 749: * ComputeScrollbarGeometry -- ! 750: * ! 751: * After changes in a scrollbar's size or configuration, this ! 752: * procedure recomputes various geometry information used in ! 753: * displaying the scrollbar. ! 754: * ! 755: * Results: ! 756: * None. ! 757: * ! 758: * Side effects: ! 759: * The scrollbar will be displayed differently. ! 760: * ! 761: *---------------------------------------------------------------------- ! 762: */ ! 763: ! 764: static void ! 765: ComputeScrollbarGeometry(scrollPtr) ! 766: register Scrollbar *scrollPtr; /* Scrollbar whose geometry may ! 767: * have changed. */ ! 768: { ! 769: int width, fieldLength; ! 770: ! 771: if (scrollPtr->relief == TK_RELIEF_FLAT) { ! 772: scrollPtr->offset = 0; ! 773: } else { ! 774: scrollPtr->offset = scrollPtr->borderWidth; ! 775: } ! 776: width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin) ! 777: : Tk_Height(scrollPtr->tkwin); ! 778: scrollPtr->arrowLength = ! 779: (((width - 2*scrollPtr->offset)*173) + 100) / 200; ! 780: fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) ! 781: : Tk_Width(scrollPtr->tkwin)) ! 782: - 2*(scrollPtr->arrowLength + scrollPtr->offset); ! 783: if (fieldLength < 0) { ! 784: fieldLength = 0; ! 785: } ! 786: if (scrollPtr->totalUnits <= 0) { ! 787: scrollPtr->sliderFirst = 0; ! 788: scrollPtr->sliderLast = fieldLength; ! 789: } else { ! 790: scrollPtr->sliderFirst = (fieldLength*scrollPtr->firstUnit ! 791: + scrollPtr->totalUnits/2)/scrollPtr->totalUnits; ! 792: scrollPtr->sliderLast = (fieldLength*(scrollPtr->lastUnit+1) ! 793: + scrollPtr->totalUnits/2)/scrollPtr->totalUnits; ! 794: ! 795: /* ! 796: * Adjust the slider so that some piece of it is always ! 797: * displayed in the scrollbar and so that it has at least ! 798: * a minimal width (so it can be grabbed with the mouse). ! 799: */ ! 800: ! 801: if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) { ! 802: scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth; ! 803: } ! 804: if (scrollPtr->sliderFirst < 0) { ! 805: scrollPtr->sliderFirst = 0; ! 806: } ! 807: if (scrollPtr->sliderLast < (scrollPtr->sliderFirst ! 808: + 2*scrollPtr->borderWidth)) { ! 809: scrollPtr->sliderLast = scrollPtr->sliderFirst ! 810: + 2*scrollPtr->borderWidth; ! 811: } ! 812: if (scrollPtr->sliderLast > fieldLength) { ! 813: scrollPtr->sliderLast = fieldLength; ! 814: } ! 815: } ! 816: scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->offset; ! 817: scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->offset; ! 818: ! 819: /* ! 820: * Register the desired geometry for the window (leave enough space ! 821: * for the two arrows plus a minimum-size slider, plus border around ! 822: * the whole window, if any). Then arrange for the window to be ! 823: * redisplayed. ! 824: */ ! 825: ! 826: if (scrollPtr->vertical) { ! 827: Tk_GeometryRequest(scrollPtr->tkwin, ! 828: scrollPtr->width + 2*scrollPtr->offset, ! 829: 2*(scrollPtr->arrowLength + scrollPtr->borderWidth ! 830: + scrollPtr->offset)); ! 831: } else { ! 832: Tk_GeometryRequest(scrollPtr->tkwin, ! 833: 2*(scrollPtr->arrowLength + scrollPtr->borderWidth ! 834: + scrollPtr->offset), scrollPtr->width + 2*scrollPtr->offset); ! 835: } ! 836: Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->borderWidth); ! 837: ! 838: } ! 839: ! 840: /* ! 841: *-------------------------------------------------------------- ! 842: * ! 843: * ScrollbarPosition -- ! 844: * ! 845: * Determine the scrollbar element corresponding to a ! 846: * given position. ! 847: * ! 848: * Results: ! 849: * One of TOP_ARROW, TOP_GAP, etc., indicating which element ! 850: * of the scrollbar covers the position given by (x, y). If ! 851: * (x,y) is outside the scrollbar entirely, then OUTSIDE is ! 852: * returned. ! 853: * ! 854: * Side effects: ! 855: * None. ! 856: * ! 857: *-------------------------------------------------------------- ! 858: */ ! 859: ! 860: static int ! 861: ScrollbarPosition(scrollPtr, x, y) ! 862: register Scrollbar *scrollPtr; /* Scrollbar widget record. */ ! 863: int x, y; /* Coordinates within scrollPtr's ! 864: * window. */ ! 865: { ! 866: int length, width, tmp; ! 867: ! 868: if (scrollPtr->vertical) { ! 869: length = Tk_Height(scrollPtr->tkwin); ! 870: width = Tk_Width(scrollPtr->tkwin); ! 871: } else { ! 872: tmp = x; ! 873: x = y; ! 874: y = tmp; ! 875: length = Tk_Width(scrollPtr->tkwin); ! 876: width = Tk_Height(scrollPtr->tkwin); ! 877: } ! 878: ! 879: if ((x < 0) || (x > width) || (y < 0)) { ! 880: return OUTSIDE; ! 881: } ! 882: ! 883: /* ! 884: * All of the calculations in this procedure mirror those in ! 885: * DisplayScrollbar. Be sure to keep the two consistent. ! 886: */ ! 887: ! 888: if (y < (scrollPtr->offset + scrollPtr->arrowLength)) { ! 889: return TOP_ARROW; ! 890: } ! 891: if (y < scrollPtr->sliderFirst) { ! 892: return TOP_GAP; ! 893: } ! 894: if (y < scrollPtr->sliderLast) { ! 895: return SLIDER; ! 896: } ! 897: if (y >= (length - (scrollPtr->arrowLength + scrollPtr->offset))) { ! 898: return BOTTOM_ARROW; ! 899: } ! 900: return BOTTOM_GAP; ! 901: } ! 902: ! 903: /* ! 904: *-------------------------------------------------------------- ! 905: * ! 906: * ScrollbarMouseProc -- ! 907: * ! 908: * This procedure is called back by Tk in response to ! 909: * mouse events such as window entry, window exit, mouse ! 910: * motion, and button presses. ! 911: * ! 912: * Results: ! 913: * None. ! 914: * ! 915: * Side effects: ! 916: * This procedure implements the "feel" of the scrollbar ! 917: * by issuing scrolling commands in response to button presses ! 918: * and mouse motion. ! 919: * ! 920: *-------------------------------------------------------------- ! 921: */ ! 922: ! 923: static void ! 924: ScrollbarMouseProc(clientData, eventPtr) ! 925: ClientData clientData; /* Information about window. */ ! 926: register XEvent *eventPtr; /* Information about event. */ ! 927: { ! 928: register Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 929: ! 930: Tk_Preserve((ClientData) scrollPtr); ! 931: if (eventPtr->type == EnterNotify) { ! 932: if (scrollPtr->pressField == -1) { ! 933: ScrollbarNewField(scrollPtr, ! 934: ScrollbarPosition(scrollPtr, eventPtr->xcrossing.x, ! 935: eventPtr->xcrossing.y)); ! 936: } ! 937: } else if (eventPtr->type == LeaveNotify) { ! 938: if (scrollPtr->pressField == -1) { ! 939: ScrollbarNewField(scrollPtr, OUTSIDE); ! 940: } ! 941: } else if (eventPtr->type == MotionNotify) { ! 942: if (scrollPtr->pressField == SLIDER) { ! 943: int delta, length, newFirst; ! 944: ! 945: if (scrollPtr->vertical) { ! 946: delta = eventPtr->xmotion.y - scrollPtr->pressPos; ! 947: length = Tk_Height(scrollPtr->tkwin) ! 948: - 2*(scrollPtr->arrowLength + scrollPtr->offset); ! 949: } else { ! 950: delta = eventPtr->xmotion.x - scrollPtr->pressPos; ! 951: length = Tk_Width(scrollPtr->tkwin) ! 952: - 2*(scrollPtr->arrowLength + scrollPtr->offset); ! 953: } ! 954: ! 955: /* ! 956: * Do the division with positive numbers to avoid ! 957: * differences in negative-number truncation on different ! 958: * machines. ! 959: */ ! 960: ! 961: if (delta >= 0) { ! 962: newFirst = scrollPtr->pressFirstUnit ! 963: + ((delta * scrollPtr->totalUnits) + (length/2)) ! 964: / length; ! 965: } else { ! 966: newFirst = scrollPtr->pressFirstUnit ! 967: - (((-delta) * scrollPtr->totalUnits) + (length/2)) ! 968: / length; ! 969: } ! 970: ScrollCmd(scrollPtr, newFirst); ! 971: } else if (scrollPtr->pressField == -1) { ! 972: ScrollbarNewField(scrollPtr, ! 973: ScrollbarPosition(scrollPtr, eventPtr->xmotion.x, ! 974: eventPtr->xmotion.y)); ! 975: } ! 976: } else if ((eventPtr->type == ButtonPress) ! 977: && (eventPtr->xbutton.state == 0)) { ! 978: scrollPtr->pressField = scrollPtr->mouseField; ! 979: if (scrollPtr->pressField != SLIDER) { ! 980: scrollPtr->autoRepeat = Tk_CreateTimerHandler( ! 981: scrollPtr->repeatDelay, ! 982: ScrollbarTimerProc, (ClientData) scrollPtr); ! 983: } ! 984: if (scrollPtr->vertical) { ! 985: scrollPtr->pressPos = eventPtr->xbutton.y; ! 986: } else { ! 987: scrollPtr->pressPos = eventPtr->xbutton.x; ! 988: } ! 989: scrollPtr->pressFirstUnit = scrollPtr->firstUnit; ! 990: if (scrollPtr->pressFirstUnit <= -scrollPtr->windowUnits) { ! 991: scrollPtr->pressFirstUnit = 1-scrollPtr->windowUnits; ! 992: } ! 993: if (scrollPtr->pressFirstUnit >= scrollPtr->totalUnits) { ! 994: scrollPtr->pressFirstUnit = scrollPtr->totalUnits-1; ! 995: } ! 996: EventuallyRedraw(scrollPtr); ! 997: } else if (eventPtr->type == ButtonRelease) { ! 998: if (scrollPtr->pressField == scrollPtr->mouseField) { ! 999: switch (scrollPtr->pressField) { ! 1000: case TOP_ARROW: ! 1001: ScrollCmd(scrollPtr, scrollPtr->firstUnit-1); ! 1002: break; ! 1003: case TOP_GAP: ! 1004: if (scrollPtr->windowUnits <= 1) { ! 1005: ScrollCmd(scrollPtr, scrollPtr->firstUnit - 1); ! 1006: } else { ! 1007: ScrollCmd(scrollPtr, scrollPtr->firstUnit ! 1008: - (scrollPtr->windowUnits-1)); ! 1009: } ! 1010: break; ! 1011: case BOTTOM_GAP: { ! 1012: if (scrollPtr->windowUnits <= 1) { ! 1013: ScrollCmd(scrollPtr, scrollPtr->firstUnit + 1); ! 1014: } else { ! 1015: ScrollCmd(scrollPtr, scrollPtr->firstUnit ! 1016: + (scrollPtr->windowUnits-1)); ! 1017: } ! 1018: break; ! 1019: } ! 1020: case BOTTOM_ARROW: ! 1021: ScrollCmd(scrollPtr, scrollPtr->firstUnit+1); ! 1022: break; ! 1023: } ! 1024: } ! 1025: if (scrollPtr->autoRepeat != NULL) { ! 1026: Tk_DeleteTimerHandler(scrollPtr->autoRepeat); ! 1027: scrollPtr->autoRepeat = NULL; ! 1028: } ! 1029: EventuallyRedraw(scrollPtr); ! 1030: scrollPtr->pressField = -1; ! 1031: ScrollbarNewField(scrollPtr, ! 1032: ScrollbarPosition(scrollPtr, eventPtr->xbutton.x, ! 1033: eventPtr->xbutton.y)); ! 1034: } ! 1035: Tk_Release((ClientData) scrollPtr); ! 1036: } ! 1037: ! 1038: /* ! 1039: *-------------------------------------------------------------- ! 1040: * ! 1041: * ScrollCmd -- ! 1042: * ! 1043: * This procedure takes care of invoking a scrolling Tcl ! 1044: * command and reporting any error that occurs in it. ! 1045: * ! 1046: * Results: ! 1047: * None. ! 1048: * ! 1049: * Side effects: ! 1050: * A Tcl command is invoked, and an additional error-processing ! 1051: * command may also be invoked. ! 1052: * ! 1053: *-------------------------------------------------------------- ! 1054: */ ! 1055: ! 1056: static void ! 1057: ScrollCmd(scrollPtr, unit) ! 1058: register Scrollbar *scrollPtr; /* Scrollbar from which to issue ! 1059: * command. */ ! 1060: int unit; /* Unit position within thing being ! 1061: * being displayed that should appear ! 1062: * at top or right of screen. */ ! 1063: { ! 1064: char string[20]; ! 1065: int result; ! 1066: ! 1067: if ((unit == scrollPtr->firstUnit) || (scrollPtr->command == NULL)) { ! 1068: return; ! 1069: } ! 1070: sprintf(string, " %d", unit); ! 1071: result = Tcl_VarEval(scrollPtr->interp, scrollPtr->command, string, ! 1072: (char *) NULL); ! 1073: if (result != TCL_OK) { ! 1074: TkBindError(scrollPtr->interp); ! 1075: } ! 1076: } ! 1077: ! 1078: /* ! 1079: *-------------------------------------------------------------- ! 1080: * ! 1081: * EventuallyRedraw -- ! 1082: * ! 1083: * Arrange for one or more of the fields of a scrollbar ! 1084: * to be redrawn. ! 1085: * ! 1086: * Results: ! 1087: * None. ! 1088: * ! 1089: * Side effects: ! 1090: * None. ! 1091: * ! 1092: *-------------------------------------------------------------- ! 1093: */ ! 1094: ! 1095: static void ! 1096: EventuallyRedraw(scrollPtr) ! 1097: register Scrollbar *scrollPtr; /* Information about widget. */ ! 1098: { ! 1099: if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) { ! 1100: return; ! 1101: } ! 1102: if ((scrollPtr->flags & REDRAW_PENDING) == 0) { ! 1103: Tk_DoWhenIdle(DisplayScrollbar, (ClientData) scrollPtr); ! 1104: scrollPtr->flags |= REDRAW_PENDING; ! 1105: } ! 1106: } ! 1107: ! 1108: /* ! 1109: *-------------------------------------------------------------- ! 1110: * ! 1111: * ScrollbarNewField -- ! 1112: * ! 1113: * This procedure is called to declare that the mouse is in ! 1114: * a particular field of the scrollbar (e.g. top arrow), so ! 1115: * that the field can be highlighed and the previous field ! 1116: * can be returned to normal display. ! 1117: * ! 1118: * Results: ! 1119: * None. ! 1120: * ! 1121: * Side effects: ! 1122: * Fields may be redisplayed. ! 1123: * ! 1124: *-------------------------------------------------------------- ! 1125: */ ! 1126: ! 1127: static void ! 1128: ScrollbarNewField(scrollPtr, field) ! 1129: register Scrollbar *scrollPtr; /* Information about widget. */ ! 1130: int field; /* Identifies field under mouse, ! 1131: * e.g. TOP_ARROW. */ ! 1132: { ! 1133: if (field == scrollPtr->mouseField) { ! 1134: return; ! 1135: } ! 1136: EventuallyRedraw(scrollPtr); ! 1137: scrollPtr->mouseField = field; ! 1138: } ! 1139: ! 1140: /* ! 1141: *-------------------------------------------------------------- ! 1142: * ! 1143: * ScrollbarTimerProc -- ! 1144: * ! 1145: * This procedure is invoked as a Tk timer handler for actions ! 1146: * that auto-repeat (mouse presses in an arrow or gap). It ! 1147: * performs the auto-repeat action. ! 1148: * ! 1149: * Results: ! 1150: * None. ! 1151: * ! 1152: * Side effects: ! 1153: * Whatever action corresponds to the current mouse button ! 1154: * is repeated, and this procedure is rescheduled to execute ! 1155: * again later. ! 1156: * ! 1157: *-------------------------------------------------------------- ! 1158: */ ! 1159: ! 1160: static void ! 1161: ScrollbarTimerProc(clientData) ! 1162: ClientData clientData; /* Information about widget. */ ! 1163: { ! 1164: register Scrollbar *scrollPtr = (Scrollbar *) clientData; ! 1165: ! 1166: Tk_Preserve((ClientData) scrollPtr); ! 1167: switch(scrollPtr->pressField) { ! 1168: case TOP_ARROW: ! 1169: ScrollCmd(scrollPtr, scrollPtr->firstUnit-1); ! 1170: break; ! 1171: case TOP_GAP: ! 1172: ScrollCmd(scrollPtr, scrollPtr->firstUnit ! 1173: - (scrollPtr->windowUnits-1)); ! 1174: break; ! 1175: case BOTTOM_GAP: { ! 1176: ScrollCmd(scrollPtr, scrollPtr->firstUnit ! 1177: + (scrollPtr->windowUnits-1)); ! 1178: break; ! 1179: } ! 1180: case BOTTOM_ARROW: ! 1181: ScrollCmd(scrollPtr, scrollPtr->firstUnit+1); ! 1182: break; ! 1183: } ! 1184: if (scrollPtr->tkwin != NULL) { ! 1185: scrollPtr->autoRepeat = Tk_CreateTimerHandler( ! 1186: scrollPtr->repeatInterval, ScrollbarTimerProc, ! 1187: (ClientData) scrollPtr); ! 1188: } ! 1189: Tk_Release((ClientData) scrollPtr); ! 1190: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.