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