tkScrollbar.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

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