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 (c) 1990-1994 The Regents of the University of California. 10 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 11 * 12 * See the file "license.terms" for information on usage and redistribution 13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 14 * 15 * RCS: @(#) $Id: tkScrollbar.c,v 1.6 2002/08/05 04:30:40 dgp Exp $ 16 */ 17 18#include "tkPort.h" 19#include "tkScrollbar.h" 20#include "default.h" 21 22/* 23 * Custom option for handling "-orient" 24 */ 25 26static Tk_CustomOption orientOption = { 27 (Tk_OptionParseProc *) TkOrientParseProc, 28 TkOrientPrintProc, 29 (ClientData) NULL 30}; 31 32/* 33 * Information used for argv parsing. 34 */ 35 36Tk_ConfigSpec tkpScrollbarConfigSpecs[] = { 37 {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", 38 DEF_SCROLLBAR_ACTIVE_BG_COLOR, Tk_Offset(TkScrollbar, activeBorder), 39 TK_CONFIG_COLOR_ONLY}, 40 {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", 41 DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(TkScrollbar, activeBorder), 42 TK_CONFIG_MONO_ONLY}, 43 {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", 44 DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(TkScrollbar, activeRelief), 0}, 45 {TK_CONFIG_BORDER, "-background", "background", "Background", 46 DEF_SCROLLBAR_BG_COLOR, Tk_Offset(TkScrollbar, bgBorder), 47 TK_CONFIG_COLOR_ONLY}, 48 {TK_CONFIG_BORDER, "-background", "background", "Background", 49 DEF_SCROLLBAR_BG_MONO, Tk_Offset(TkScrollbar, bgBorder), 50 TK_CONFIG_MONO_ONLY}, 51 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, 52 (char *) NULL, 0, 0}, 53 {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, 54 (char *) NULL, 0, 0}, 55 {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", 56 DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(TkScrollbar, borderWidth), 0}, 57 {TK_CONFIG_STRING, "-command", "command", "Command", 58 DEF_SCROLLBAR_COMMAND, Tk_Offset(TkScrollbar, command), 59 TK_CONFIG_NULL_OK}, 60 {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", 61 DEF_SCROLLBAR_CURSOR, Tk_Offset(TkScrollbar, cursor), TK_CONFIG_NULL_OK}, 62 {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth", 63 "BorderWidth", DEF_SCROLLBAR_EL_BORDER_WIDTH, 64 Tk_Offset(TkScrollbar, elementBorderWidth), 0}, 65 {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", 66 "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG, 67 Tk_Offset(TkScrollbar, highlightBgColorPtr), 0}, 68 {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", 69 DEF_SCROLLBAR_HIGHLIGHT, 70 Tk_Offset(TkScrollbar, highlightColorPtr), 0}, 71 {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", 72 "HighlightThickness", 73 DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(TkScrollbar, highlightWidth), 0}, 74 {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", 75 DEF_SCROLLBAR_JUMP, Tk_Offset(TkScrollbar, jump), 0}, 76 {TK_CONFIG_CUSTOM, "-orient", "orient", "Orient", 77 DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, vertical), 0, 78 &orientOption}, 79 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", 80 DEF_SCROLLBAR_RELIEF, Tk_Offset(TkScrollbar, relief), 0}, 81 {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", 82 DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(TkScrollbar, repeatDelay), 0}, 83 {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", 84 DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(TkScrollbar, repeatInterval), 0}, 85 {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", 86 DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(TkScrollbar, takeFocus), 87 TK_CONFIG_NULL_OK}, 88 {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", 89 DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(TkScrollbar, troughColorPtr), 90 TK_CONFIG_COLOR_ONLY}, 91 {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", 92 DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(TkScrollbar, troughColorPtr), 93 TK_CONFIG_MONO_ONLY}, 94 {TK_CONFIG_PIXELS, "-width", "width", "Width", 95 DEF_SCROLLBAR_WIDTH, Tk_Offset(TkScrollbar, width), 0}, 96 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, 97 (char *) NULL, 0, 0} 98}; 99 100/* 101 * Forward declarations for procedures defined later in this file: 102 */ 103 104static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp, 105 TkScrollbar *scrollPtr, int argc, CONST char **argv, 106 int flags)); 107static void ScrollbarCmdDeletedProc _ANSI_ARGS_(( 108 ClientData clientData)); 109static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData, 110 Tcl_Interp *, int argc, CONST char **argv)); 111 112/* 113 *-------------------------------------------------------------- 114 * 115 * Tk_ScrollbarCmd -- 116 * 117 * This procedure is invoked to process the "scrollbar" Tcl 118 * command. See the user documentation for details on what 119 * it does. 120 * 121 * Results: 122 * A standard Tcl result. 123 * 124 * Side effects: 125 * See the user documentation. 126 * 127 *-------------------------------------------------------------- 128 */ 129 130int 131Tk_ScrollbarCmd(clientData, interp, argc, argv) 132 ClientData clientData; /* Main window associated with 133 * interpreter. */ 134 Tcl_Interp *interp; /* Current interpreter. */ 135 int argc; /* Number of arguments. */ 136 CONST char **argv; /* Argument strings. */ 137{ 138 Tk_Window tkwin = (Tk_Window) clientData; 139 register TkScrollbar *scrollPtr; 140 Tk_Window new; 141 142 if (argc < 2) { 143 Tcl_AppendResult(interp, "wrong # args: should be \"", 144 argv[0], " pathName ?options?\"", (char *) NULL); 145 return TCL_ERROR; 146 } 147 148 new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); 149 if (new == NULL) { 150 return TCL_ERROR; 151 } 152 153 Tk_SetClass(new, "Scrollbar"); 154 scrollPtr = TkpCreateScrollbar(new); 155 156 Tk_SetClassProcs(new, &tkpScrollbarProcs, (ClientData) scrollPtr); 157 158 /* 159 * Initialize fields that won't be initialized by ConfigureScrollbar, 160 * or which ConfigureScrollbar expects to have reasonable values 161 * (e.g. resource pointers). 162 */ 163 164 scrollPtr->tkwin = new; 165 scrollPtr->display = Tk_Display(new); 166 scrollPtr->interp = interp; 167 scrollPtr->widgetCmd = Tcl_CreateCommand(interp, 168 Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, 169 (ClientData) scrollPtr, ScrollbarCmdDeletedProc); 170 scrollPtr->vertical = 0; 171 scrollPtr->width = 0; 172 scrollPtr->command = NULL; 173 scrollPtr->commandSize = 0; 174 scrollPtr->repeatDelay = 0; 175 scrollPtr->repeatInterval = 0; 176 scrollPtr->borderWidth = 0; 177 scrollPtr->bgBorder = NULL; 178 scrollPtr->activeBorder = NULL; 179 scrollPtr->troughColorPtr = NULL; 180 scrollPtr->relief = TK_RELIEF_FLAT; 181 scrollPtr->highlightWidth = 0; 182 scrollPtr->highlightBgColorPtr = NULL; 183 scrollPtr->highlightColorPtr = NULL; 184 scrollPtr->inset = 0; 185 scrollPtr->elementBorderWidth = -1; 186 scrollPtr->arrowLength = 0; 187 scrollPtr->sliderFirst = 0; 188 scrollPtr->sliderLast = 0; 189 scrollPtr->activeField = 0; 190 scrollPtr->activeRelief = TK_RELIEF_RAISED; 191 scrollPtr->totalUnits = 0; 192 scrollPtr->windowUnits = 0; 193 scrollPtr->firstUnit = 0; 194 scrollPtr->lastUnit = 0; 195 scrollPtr->firstFraction = 0.0; 196 scrollPtr->lastFraction = 0.0; 197 scrollPtr->cursor = None; 198 scrollPtr->takeFocus = NULL; 199 scrollPtr->flags = 0; 200 201 if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) { 202 Tk_DestroyWindow(scrollPtr->tkwin); 203 return TCL_ERROR; 204 } 205 206 Tcl_SetResult(interp, Tk_PathName(scrollPtr->tkwin), TCL_STATIC); 207 return TCL_OK; 208} 209 210/* 211 *-------------------------------------------------------------- 212 * 213 * ScrollbarWidgetCmd -- 214 * 215 * This procedure is invoked to process the Tcl command 216 * that corresponds to a widget managed by this module. 217 * See the user documentation for details on what it does. 218 * 219 * Results: 220 * A standard Tcl result. 221 * 222 * Side effects: 223 * See the user documentation. 224 * 225 *-------------------------------------------------------------- 226 */ 227 228static int 229ScrollbarWidgetCmd(clientData, interp, argc, argv) 230 ClientData clientData; /* Information about scrollbar 231 * widget. */ 232 Tcl_Interp *interp; /* Current interpreter. */ 233 int argc; /* Number of arguments. */ 234 CONST char **argv; /* Argument strings. */ 235{ 236 register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; 237 int result = TCL_OK; 238 size_t length; 239 int c; 240 241 if (argc < 2) { 242 Tcl_AppendResult(interp, "wrong # args: should be \"", 243 argv[0], " option ?arg arg ...?\"", (char *) NULL); 244 return TCL_ERROR; 245 } 246 Tcl_Preserve((ClientData) scrollPtr); 247 c = argv[1][0]; 248 length = strlen(argv[1]); 249 if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { 250 int oldActiveField; 251 if (argc == 2) { 252 switch (scrollPtr->activeField) { 253 case TOP_ARROW: 254 Tcl_SetResult(interp, "arrow1", TCL_STATIC); 255 break; 256 case SLIDER: 257 Tcl_SetResult(interp, "slider", TCL_STATIC); 258 break; 259 case BOTTOM_ARROW: 260 Tcl_SetResult(interp, "arrow2", TCL_STATIC); 261 break; 262 } 263 goto done; 264 } 265 if (argc != 3) { 266 Tcl_AppendResult(interp, "wrong # args: should be \"", 267 argv[0], " activate element\"", (char *) NULL); 268 goto error; 269 } 270 c = argv[2][0]; 271 length = strlen(argv[2]); 272 oldActiveField = scrollPtr->activeField; 273 if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) { 274 scrollPtr->activeField = TOP_ARROW; 275 } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) { 276 scrollPtr->activeField = BOTTOM_ARROW; 277 } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) { 278 scrollPtr->activeField = SLIDER; 279 } else { 280 scrollPtr->activeField = OUTSIDE; 281 } 282 if (oldActiveField != scrollPtr->activeField) { 283 TkScrollbarEventuallyRedraw(scrollPtr); 284 } 285 } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) 286 && (length >= 2)) { 287 if (argc != 3) { 288 Tcl_AppendResult(interp, "wrong # args: should be \"", 289 argv[0], " cget option\"", 290 (char *) NULL); 291 goto error; 292 } 293 result = Tk_ConfigureValue(interp, scrollPtr->tkwin, 294 tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0); 295 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) 296 && (length >= 2)) { 297 if (argc == 2) { 298 result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, 299 tkpScrollbarConfigSpecs, (char *) scrollPtr, 300 (char *) NULL, 0); 301 } else if (argc == 3) { 302 result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, 303 tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0); 304 } else { 305 result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 306 TK_CONFIG_ARGV_ONLY); 307 } 308 } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) { 309 int xDelta, yDelta, pixels, length; 310 double fraction; 311 char buf[TCL_DOUBLE_SPACE]; 312 313 if (argc != 4) { 314 Tcl_AppendResult(interp, "wrong # args: should be \"", 315 argv[0], " delta xDelta yDelta\"", (char *) NULL); 316 goto error; 317 } 318 if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK) 319 || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) { 320 goto error; 321 } 322 if (scrollPtr->vertical) { 323 pixels = yDelta; 324 length = Tk_Height(scrollPtr->tkwin) - 1 325 - 2*(scrollPtr->arrowLength + scrollPtr->inset); 326 } else { 327 pixels = xDelta; 328 length = Tk_Width(scrollPtr->tkwin) - 1 329 - 2*(scrollPtr->arrowLength + scrollPtr->inset); 330 } 331 if (length == 0) { 332 fraction = 0.0; 333 } else { 334 fraction = ((double) pixels / (double) length); 335 } 336 sprintf(buf, "%g", fraction); 337 Tcl_SetResult(interp, buf, TCL_VOLATILE); 338 } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) { 339 int x, y, pos, length; 340 double fraction; 341 char buf[TCL_DOUBLE_SPACE]; 342 343 if (argc != 4) { 344 Tcl_AppendResult(interp, "wrong # args: should be \"", 345 argv[0], " fraction x y\"", (char *) NULL); 346 goto error; 347 } 348 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) 349 || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { 350 goto error; 351 } 352 if (scrollPtr->vertical) { 353 pos = y - (scrollPtr->arrowLength + scrollPtr->inset); 354 length = Tk_Height(scrollPtr->tkwin) - 1 355 - 2*(scrollPtr->arrowLength + scrollPtr->inset); 356 } else { 357 pos = x - (scrollPtr->arrowLength + scrollPtr->inset); 358 length = Tk_Width(scrollPtr->tkwin) - 1 359 - 2*(scrollPtr->arrowLength + scrollPtr->inset); 360 } 361 if (length == 0) { 362 fraction = 0.0; 363 } else { 364 fraction = ((double) pos / (double) length); 365 } 366 if (fraction < 0) { 367 fraction = 0; 368 } else if (fraction > 1.0) { 369 fraction = 1.0; 370 } 371 sprintf(buf, "%g", fraction); 372 Tcl_SetResult(interp, buf, TCL_VOLATILE); 373 } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { 374 if (argc != 2) { 375 Tcl_AppendResult(interp, "wrong # args: should be \"", 376 argv[0], " get\"", (char *) NULL); 377 goto error; 378 } 379 if (scrollPtr->flags & NEW_STYLE_COMMANDS) { 380 char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE]; 381 382 Tcl_PrintDouble(interp, scrollPtr->firstFraction, first); 383 Tcl_PrintDouble(interp, scrollPtr->lastFraction, last); 384 Tcl_AppendResult(interp, first, " ", last, (char *) NULL); 385 } else { 386 char buf[TCL_INTEGER_SPACE * 4]; 387 388 sprintf(buf, "%d %d %d %d", scrollPtr->totalUnits, 389 scrollPtr->windowUnits, scrollPtr->firstUnit, 390 scrollPtr->lastUnit); 391 Tcl_SetResult(interp, buf, TCL_VOLATILE); 392 } 393 } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { 394 int x, y, thing; 395 396 if (argc != 4) { 397 Tcl_AppendResult(interp, "wrong # args: should be \"", 398 argv[0], " identify x y\"", (char *) NULL); 399 goto error; 400 } 401 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) 402 || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { 403 goto error; 404 } 405 thing = TkpScrollbarPosition(scrollPtr, x,y); 406 switch (thing) { 407 case TOP_ARROW: 408 Tcl_SetResult(interp, "arrow1", TCL_STATIC); 409 break; 410 case TOP_GAP: 411 Tcl_SetResult(interp, "trough1", TCL_STATIC); 412 break; 413 case SLIDER: 414 Tcl_SetResult(interp, "slider", TCL_STATIC); 415 break; 416 case BOTTOM_GAP: 417 Tcl_SetResult(interp, "trough2", TCL_STATIC); 418 break; 419 case BOTTOM_ARROW: 420 Tcl_SetResult(interp, "arrow2", TCL_STATIC); 421 break; 422 } 423 } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { 424 int totalUnits, windowUnits, firstUnit, lastUnit; 425 426 if (argc == 4) { 427 double first, last; 428 429 if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) { 430 goto error; 431 } 432 if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) { 433 goto error; 434 } 435 if (first < 0) { 436 scrollPtr->firstFraction = 0; 437 } else if (first > 1.0) { 438 scrollPtr->firstFraction = 1.0; 439 } else { 440 scrollPtr->firstFraction = first; 441 } 442 if (last < scrollPtr->firstFraction) { 443 scrollPtr->lastFraction = scrollPtr->firstFraction; 444 } else if (last > 1.0) { 445 scrollPtr->lastFraction = 1.0; 446 } else { 447 scrollPtr->lastFraction = last; 448 } 449 scrollPtr->flags |= NEW_STYLE_COMMANDS; 450 } else if (argc == 6) { 451 if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) { 452 goto error; 453 } 454 if (totalUnits < 0) { 455 totalUnits = 0; 456 } 457 if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) { 458 goto error; 459 } 460 if (windowUnits < 0) { 461 windowUnits = 0; 462 } 463 if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) { 464 goto error; 465 } 466 if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) { 467 goto error; 468 } 469 if (totalUnits > 0) { 470 if (lastUnit < firstUnit) { 471 lastUnit = firstUnit; 472 } 473 } else { 474 firstUnit = lastUnit = 0; 475 } 476 scrollPtr->totalUnits = totalUnits; 477 scrollPtr->windowUnits = windowUnits; 478 scrollPtr->firstUnit = firstUnit; 479 scrollPtr->lastUnit = lastUnit; 480 if (scrollPtr->totalUnits == 0) { 481 scrollPtr->firstFraction = 0.0; 482 scrollPtr->lastFraction = 1.0; 483 } else { 484 scrollPtr->firstFraction = ((double) firstUnit)/totalUnits; 485 scrollPtr->lastFraction = ((double) (lastUnit+1))/totalUnits; 486 } 487 scrollPtr->flags &= ~NEW_STYLE_COMMANDS; 488 } else { 489 Tcl_AppendResult(interp, "wrong # args: should be \"", 490 argv[0], " set firstFraction lastFraction\" or \"", 491 argv[0], 492 " set totalUnits windowUnits firstUnit lastUnit\"", 493 (char *) NULL); 494 goto error; 495 } 496 TkpComputeScrollbarGeometry(scrollPtr); 497 TkScrollbarEventuallyRedraw(scrollPtr); 498 } else { 499 Tcl_AppendResult(interp, "bad option \"", argv[1], 500 "\": must be activate, cget, configure, delta, fraction, ", 501 "get, identify, or set", (char *) NULL); 502 goto error; 503 } 504 done: 505 Tcl_Release((ClientData) scrollPtr); 506 return result; 507 508 error: 509 Tcl_Release((ClientData) scrollPtr); 510 return TCL_ERROR; 511} 512 513/* 514 *---------------------------------------------------------------------- 515 * 516 * ConfigureScrollbar -- 517 * 518 * This procedure is called to process an argv/argc list, plus 519 * the Tk option database, in order to configure (or 520 * reconfigure) a scrollbar widget. 521 * 522 * Results: 523 * The return value is a standard Tcl result. If TCL_ERROR is 524 * returned, then the interp's result contains an error message. 525 * 526 * Side effects: 527 * Configuration information, such as colors, border width, 528 * etc. get set for scrollPtr; old resources get freed, 529 * if there were any. 530 * 531 *---------------------------------------------------------------------- 532 */ 533 534static int 535ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) 536 Tcl_Interp *interp; /* Used for error reporting. */ 537 register TkScrollbar *scrollPtr; /* Information about widget; may or 538 * may not already have values for 539 * some fields. */ 540 int argc; /* Number of valid entries in argv. */ 541 CONST char **argv; /* Arguments. */ 542 int flags; /* Flags to pass to 543 * Tk_ConfigureWidget. */ 544{ 545 if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, tkpScrollbarConfigSpecs, 546 argc, argv, (char *) scrollPtr, flags) != TCL_OK) { 547 return TCL_ERROR; 548 } 549 550 /* 551 * A few options need special processing, such as setting the 552 * background from a 3-D border. 553 */ 554 555 if (scrollPtr->command != NULL) { 556 scrollPtr->commandSize = strlen(scrollPtr->command); 557 } else { 558 scrollPtr->commandSize = 0; 559 } 560 561 /* 562 * Configure platform specific options. 563 */ 564 565 TkpConfigureScrollbar(scrollPtr); 566 567 /* 568 * Register the desired geometry for the window (leave enough space 569 * for the two arrows plus a minimum-size slider, plus border around 570 * the whole window, if any). Then arrange for the window to be 571 * redisplayed. 572 */ 573 574 TkpComputeScrollbarGeometry(scrollPtr); 575 TkScrollbarEventuallyRedraw(scrollPtr); 576 return TCL_OK; 577} 578 579/* 580 *-------------------------------------------------------------- 581 * 582 * TkScrollbarEventProc -- 583 * 584 * This procedure is invoked by the Tk dispatcher for various 585 * events on scrollbars. 586 * 587 * Results: 588 * None. 589 * 590 * Side effects: 591 * When the window gets deleted, internal structures get 592 * cleaned up. When it gets exposed, it is redisplayed. 593 * 594 *-------------------------------------------------------------- 595 */ 596 597void 598TkScrollbarEventProc(clientData, eventPtr) 599 ClientData clientData; /* Information about window. */ 600 XEvent *eventPtr; /* Information about event. */ 601{ 602 TkScrollbar *scrollPtr = (TkScrollbar *) clientData; 603 604 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { 605 TkScrollbarEventuallyRedraw(scrollPtr); 606 } else if (eventPtr->type == DestroyNotify) { 607 TkpDestroyScrollbar(scrollPtr); 608 if (scrollPtr->tkwin != NULL) { 609 scrollPtr->tkwin = NULL; 610 Tcl_DeleteCommandFromToken(scrollPtr->interp, 611 scrollPtr->widgetCmd); 612 } 613 if (scrollPtr->flags & REDRAW_PENDING) { 614 Tcl_CancelIdleCall(TkpDisplayScrollbar, (ClientData) scrollPtr); 615 } 616 /* 617 * Free up all the stuff that requires special handling, then 618 * let Tk_FreeOptions handle all the standard option-related 619 * stuff. 620 */ 621 622 Tk_FreeOptions(tkpScrollbarConfigSpecs, (char *) scrollPtr, 623 scrollPtr->display, 0); 624 Tcl_EventuallyFree((ClientData) scrollPtr, TCL_DYNAMIC); 625 } else if (eventPtr->type == ConfigureNotify) { 626 TkpComputeScrollbarGeometry(scrollPtr); 627 TkScrollbarEventuallyRedraw(scrollPtr); 628 } else if (eventPtr->type == FocusIn) { 629 if (eventPtr->xfocus.detail != NotifyInferior) { 630 scrollPtr->flags |= GOT_FOCUS; 631 if (scrollPtr->highlightWidth > 0) { 632 TkScrollbarEventuallyRedraw(scrollPtr); 633 } 634 } 635 } else if (eventPtr->type == FocusOut) { 636 if (eventPtr->xfocus.detail != NotifyInferior) { 637 scrollPtr->flags &= ~GOT_FOCUS; 638 if (scrollPtr->highlightWidth > 0) { 639 TkScrollbarEventuallyRedraw(scrollPtr); 640 } 641 } 642 } 643} 644 645/* 646 *---------------------------------------------------------------------- 647 * 648 * ScrollbarCmdDeletedProc -- 649 * 650 * This procedure is invoked when a widget command is deleted. If 651 * the widget isn't already in the process of being destroyed, 652 * this command destroys it. 653 * 654 * Results: 655 * None. 656 * 657 * Side effects: 658 * The widget is destroyed. 659 * 660 *---------------------------------------------------------------------- 661 */ 662 663static void 664ScrollbarCmdDeletedProc(clientData) 665 ClientData clientData; /* Pointer to widget record for widget. */ 666{ 667 TkScrollbar *scrollPtr = (TkScrollbar *) clientData; 668 Tk_Window tkwin = scrollPtr->tkwin; 669 670 /* 671 * This procedure could be invoked either because the window was 672 * destroyed and the command was then deleted (in which case tkwin 673 * is NULL) or because the command was deleted, and then this procedure 674 * destroys the widget. 675 */ 676 677 if (tkwin != NULL) { 678 scrollPtr->tkwin = NULL; 679 Tk_DestroyWindow(tkwin); 680 } 681} 682 683/* 684 *-------------------------------------------------------------- 685 * 686 * TkScrollbarEventuallyRedraw -- 687 * 688 * Arrange for one or more of the fields of a scrollbar 689 * to be redrawn. 690 * 691 * Results: 692 * None. 693 * 694 * Side effects: 695 * None. 696 * 697 *-------------------------------------------------------------- 698 */ 699 700void 701TkScrollbarEventuallyRedraw(scrollPtr) 702 register TkScrollbar *scrollPtr; /* Information about widget. */ 703{ 704 if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) { 705 return; 706 } 707 if ((scrollPtr->flags & REDRAW_PENDING) == 0) { 708 Tcl_DoWhenIdle(TkpDisplayScrollbar, (ClientData) scrollPtr); 709 scrollPtr->flags |= REDRAW_PENDING; 710 } 711} 712