New canvas item "buffer" (long) 
Author Message
 New canvas item "buffer" (long)

This is a multi-part message in MIME format.

--------------2781446B794B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Dear fellow Tclers,

I've implemented a new canvas item "buffer", which stores
everything below it in the drawing list into a Pixmap,
refreshing from this Pixmap when redrawing items above it
in the display list.

The implementation required quite some changes to the canvas
drawing algorithm and is therefore contained in tkCanvas.c.

To properly distribute dirtyness two new canvas API functions
had to be added, namely Tk_CanvasEventuallyRedrawItem and
Tk_CanvasEventuallyRedrawItemPartially; however, only tkCanvImg.c
from the standard distribution had to be changed to make use of these
new functions instead of Tk_CanvasEventuallyRedraw (which is obsolete,
but retained for backwards-compatibility reasons).

This implementation gives a speed improvement for animations
on top of complex backgrounds such as geographic maps of about
10x under Unix and 3x under Windows.

I didn't care about implementing the test suite and writing
documentation yet. Are you people from Sun interested to
incorporate the patch for 8.1?

Regards,
Sebastian Wangnick
--

Office: Eurocontrol Maastricht UAC, Horsterweg 11, NL-6191RX Beek,
        Tel: +31-433661370, Fax: ~300
Home:   Lammersdorfer Str. 61, D-52159 Rott, Tel: +49-2471-2301,

--

GCS/IT d+(-) s:- a C+() U++$ P+ L+ E--- W++(--) N o? K? w++++(---)
!O !M V PS++ PE Y+ PGP?>++ t++ 5-- X- R tv--- b+++ DI? D--(+) G
e+++ h>---- r+++ y++>*

--------------2781446B794B
Content-Type: text/plain; charset=iso-8859-1; name="tk8.0p1.canvbuffer.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline; filename="tk8.0p1.canvbuffer.patch"

diff -rc tk8.0p1.orig/generic/tk.h tk8.0p1/generic/tk.h
*** tk8.0p1.orig/generic/tk.h   Fri Oct 31 17:57:02 1997
--- tk8.0p1/generic/tk.h        Thu Nov 13 13:47:55 1997
***************
*** 642,647 ****
--- 642,653 ----
                                         * items in this canvas.  Later items
                                         * in list are drawn on top of earlier
                                         * ones. */
+     struct Tk_Item *prevBufferPtr;    /* Points to the buffer prior in se=
quence
+                                        * that dirty rectangles are attributed to,
+                                        * or NULL if below us is no buffer,
+                                        * only the canvas background. =

+                                        * Note that buffers point to their
+                                        * predecessor as well. */
      Tk_Uid staticTagSpace[TK_TAG_SPACE];/* Built-in space for limited #=
 of
                                         * tags. */
      Tk_Uid *tagPtr;                   /* Pointer to array of tags.  Usually
***************
*** 1052,1057 ****
--- 1058,1068 ----
  EXTERN void           Tk_CanvasEventuallyRedraw _ANSI_ARGS_((
                            Tk_Canvas canvas, int x1, int y1, int x2,
                            int y2));
+ EXTERN void           Tk_CanvasEventuallyRedrawItem _ANSI_ARGS_((
+                           Tk_Canvas canvas, Tk_Item* itemPtr));
+ EXTERN void           Tk_CanvasEventuallyRedrawItemPartially _ANSI_ARGS_((
+                           Tk_Canvas canvas, Tk_Item* itemPtr, int x1, int y1,
+                           int x2, int y2));
  EXTERN int            Tk_CanvasGetCoord _ANSI_ARGS_((Tcl_Interp *interp,
                            Tk_Canvas canvas, char *string,
                            double *doublePtr));
diff -rc tk8.0p1.orig/generic/tkCanvImg.c tk8.0p1/generic/tkCanvImg.c
*** tk8.0p1.orig/generic/tkCanvImg.c    Sat Sep 21 00:03:05 1996
--- tk8.0p1/generic/tkCanvImg.c Thu Nov 13 13:47:55 1997
***************
*** 667,677 ****
        x =3D y =3D 0;
        width =3D imgWidth;
        height =3D imgHeight;
!       Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1,
!               imgPtr->header.y1, imgPtr->header.x2, imgPtr->header.y2);
      } =

      ComputeImageBbox(imgPtr->canvas, imgPtr);
!     Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1 + x,
!           imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width),
            (int) (imgPtr->header.y1 + y + height));
  }
--- 667,677 ----
        x =3D y =3D 0;
        width =3D imgWidth;
        height =3D imgHeight;
!       Tk_CanvasEventuallyRedrawItem(imgPtr->canvas, &imgPtr->header);
      } =

      ComputeImageBbox(imgPtr->canvas, imgPtr);
!     Tk_CanvasEventuallyRedrawItemPartially(imgPtr->canvas, &imgPtr->hea=
der,
!           imgPtr->header.x1 + x, imgPtr->header.y1 + y,
!           (int) (imgPtr->header.x1 + x + width),
            (int) (imgPtr->header.y1 + y + height));
  }
diff -rc tk8.0p1.orig/generic/tkCanvas.c tk8.0p1/generic/tkCanvas.c
*** tk8.0p1.orig/generic/tkCanvas.c     Mon Aug  4 17:38:12 1997
--- tk8.0p1/generic/tkCanvas.c  Fri Nov 14 14:10:10 1997
***************
*** 149,154 ****
--- 149,495 ----
  extern Tk_ItemType tkOvalType, tkPolygonType;
  extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
  =

+ =0C
+ /*
+  * The structure below defines the record for each buffer item.
+  */
+ =

+ static int            CreateBuffer _ANSI_ARGS_((Tcl_Interp *interp,
+                           Tk_Canvas canvas, Tk_Item *itemPtr,
+                           int argc, char **argv));
+ static void           DeleteBuffer _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, Display *display));
+ static int            ConfigureBuffer _ANSI_ARGS_((Tcl_Interp *interp,
+                           Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
+                           char **argv, int flags));
+ static void           DisplayBuffer _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, Display *display, Drawable dst,
+                           int x, int y, int width, int height));
+ static void           ScaleBuffer _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, double originX, double originY,
+                           double scaleX, double scaleY));
+ static void           TranslateBuffer _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, double deltaX, double deltaY));
+ static int            BufferToArea _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, double *rectPtr));
+ static double         BufferToPoint _ANSI_ARGS_((Tk_Canvas canvas,
+                           Tk_Item *itemPtr, double *pointPtr));
+ =

+ static Tk_ConfigSpec bufferConfigSpecs[] =3D {
+     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+       (char *) NULL, 0, 0}
+ };
+ =

+ typedef struct BufferItem  {
+     Tk_Item header;           /* Generic stuff that's the same for all
+                                * types.  MUST BE FIRST IN STRUCTURE. */
+ =

+     /*
+      * Fields that are set by widget commands other than "configure".
+      */
+      =

+     /*
+      * Configuration settings that are updated by Tk_ConfigureWidget.
+      */
+ =

+     /*
+      * Fields whose values are derived from the current values of the
+      * configuration settings above.
+      */
+ =

+     Pixmap buffer;            /* Buffer caching drawing from below, or None. */
+     int width, height;                /* Size of buffer in non-None. */
+     int x1, y1, x2, y2;               /* Accumulated dirty area that trickled down o=
n
+                                * us, to be redrawn (at least, depending on dirty
+                                * stuff below us) to next buffer or window. */
+     struct BufferItem *nextBufferPtr; /* Pointer to next buffer structu=
re in sequence,
+                                * or NULL if our stuff (and the stuff on top) =

+                                * goes directly into window. */
+ } BufferItem;
+ =0C
+ Tk_ItemType tkBufferType =3D {
+     "buffer",                               /* name */
+     sizeof(BufferItem),                       /* itemSize */
+     CreateBuffer,                     /* createProc */
+     bufferConfigSpecs,                        /* configSpecs */
+     ConfigureBuffer,                  /* configureProc */
+     NULL,                             /* coordProc */
+     DeleteBuffer,                     /* deleteProc */
+     DisplayBuffer,                    /* displayProc */
+     0,                                        /* alwaysRedraw */
+     BufferToPoint,                    /* pointProc */
+     BufferToArea,                     /* areaProc */
+     NULL,                             /* postscriptProc */
+     ScaleBuffer,                      /* scaleProc */
+     TranslateBuffer,                  /* translateProc */
+     NULL,                             /* indexProc */
+     NULL,                             /* icursorProc */
+     NULL,                             /* selectionProc */
+     NULL,                             /* insertProc */
+     NULL,                             /* dTextProc */
+     (Tk_ItemType *) NULL              /* nextPtr */
+ };
+ =0C
+ static void           CanvasEventuallyRedrawBuffer _ANSI_ARGS_((
+                           TkCanvas *canvasPtr, Tk_Item* itemPtr));
+ static int            CanvasIsBuffer _ANSI_ARGS_((Tk_Item* itemPtr));
+ static BufferItem*    CanvasFindBuffer _ANSI_ARGS_((TkCanvas *canvasPtr,
+                           Tk_Item* itemPtr));
+ /*
+  *---------------------------------------------------------------------=
-
+  *
+  * CanvasIsBuffer --
+  *
+  * Results:
+  *    Checks whether an item is a buffer item.
+  *
+  * Side effects:
+  *    None.
+  *
+  *---------------------------------------------------------------------=
-
+  */
+ =

+ static int
+ CanvasIsBuffer(itemPtr)
+     Tk_Item *itemPtr;
+ {
+     return itemPtr->typePtr=3D=3D&tkBufferType;
+ }
+ =0C
+ /*
+  *---------------------------------------------------------------------=
-
+  *
+  * CanvasFindBuffer --
+  *
+  *    Given an item, find the first buffer below it, i.e., the one
+  *    that we attribute dirty rectangles induced by the item to.
+  *    In case of the item NULL find the topmost buffer of the canvas,
+  *    i.e., the one to refresh the window from without any item changes.=

+  *
+  * Results:
+  *    The return value is a pointer to the buffer,
+  *    or NULL if there is no buffer below itemPtr.
+  *
+  * Side effects:
+  *    None.
+  *
+  *---------------------------------------------------------------------=
-
+  */
+ =

+ static BufferItem *
+ CanvasFindBuffer(canvasPtr, itemPtr)
+     TkCanvas *canvasPtr;              /* Canvas widget to search. */
+     Tk_Item *itemPtr;
+ {
+     if (itemPtr) {
+       itemPtr =3D itemPtr->prevBufferPtr;
+     } else {
+       itemPtr =3D canvasPtr->lastItemPtr;
+       if (itemPtr && !CanvasIsBuffer(itemPtr)) {
+           itemPtr =3D itemPtr->prevBufferPtr;
+       }
+     }
+     return (BufferItem*) itemPtr;
+ }
+ =0C
+ /*--------------------------------------------------------------
+  *
+  * CreateBuffer --
+  *
+  *    This procedure is invoked to create a new buffer item
+  *    in a canvas.
+  *
+  * Results:
+  *    A standard Tcl return value.  If an error occurred in
+  *    creating the item then an error message is left in
+  *    interp->result;  in this case itemPtr is left uninitialized
+  *    so it can be safely freed by the caller.
+  *
+  * Side effects:
+  *    A new buffer item is created.
+  *
+  *--------------------------------------------------------------
+  */
+ =

+ static int
+ CreateBuffer(interp, canvas, itemPtr, argc, argv)
+     Tcl_Interp *interp;                       /* Interpreter for error reporting. */
+     Tk_Canvas canvas;                 /* Canvas to hold new item. */
+     Tk_Item *itemPtr;                 /* Record to hold new item;  header
+                                        * has been initialized by caller. */
+     int argc;                         /* Number of arguments in argv. */
+     char **argv;                      /* Arguments describing rectangle. */
+ {
+     TkCanvas *canvasPtr =3D (TkCanvas *) canvas;
+     BufferItem *bufferPtr =3D (BufferItem *) itemPtr;
+     BufferItem *prevBufferPtr;
+ =

+     if (argc !=3D 0) {
+       Tcl_AppendResult(interp, "wrong # args: should be \"",
+               Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
+               itemPtr->typePtr->name, "\"", (char *) NULL);
+       return TCL_ERROR;
+     }
+ =

+     /*
+      * Carry out initialization that is needed in order to clean
+      * up after errors during the the remainder of this procedure.
+      */
+ =

+     bufferPtr->buffer      =3D None;
+     bufferPtr->x1  =3D 0;
+     bufferPtr->y1  =3D 0;
+     bufferPtr->x2  =3D 0;
+     bufferPtr->y2  =3D 0;
+ =

+     /* Append to list of buffers. */
+     bufferPtr->nextBufferPtr =3D NULL;
+     prevBufferPtr =3D CanvasFindBuffer((TkCanvas*)canvas,itemPtr);
+     if (prevBufferPtr)
+       prevBufferPtr->nextBufferPtr =3D bufferPtr;
+     else
+         canvasPtr->firstBufferPtr =3D bufferPtr;
+ =

+     CanvasEventuallyRedrawBuffer(canvasPtr, itemPtr);
+ =

+     return TCL_OK;
+ }
+ =0C
+ /*
+  *--------------------------------------------------------------
+  *
+  * DeleteBuffer --
+  *
+  *    This procedure is called to clean up the data structure
+  *    associated with a buffer item.
+  *
+  * Results:
+  *    None.
+  *
+  * Side effects:
+  *    Resources associated with itemPtr are released.
+  *
+  *--------------------------------------------------------------
+  */
+ =

+ static void
+ DeleteBuffer(canvas, itemPtr, display)
+     Tk_Canvas canvas;                 /* Info about overall canvas widget. */
+     Tk_Item *itemPtr;                 /* Item that is being deleted. */
+     Display *display;                 /* Display containing window for
+                                        * canvas. */
+ {
+     TkCanvas *canvasPtr =3D (TkCanvas *) canvas;
+     BufferItem *bufferPtr =3D (BufferItem *) itemPtr;
+     BufferItem *prevBufferPtr;
+ =

+     if (bufferPtr->buffer !=3D None) {
+       Tk_FreePixmap(display, bufferPtr->buffer);
+ =

+     CanvasEventuallyRedrawBuffer(canvasPtr, itemPtr);
+ =

+     /* Unlink from list of buffers. */
+     prevBufferPtr =3D CanvasFindBuffer((TkCanvas*)canvas,itemPtr);
+     if (prevBufferPtr)
+       prevBufferPtr->nextBufferPtr =3D bufferPtr->nextBufferPtr;
+     else
+         canvasPtr->firstBufferPtr =3D bufferPtr->nextBufferPtr;
+     }
+ }
+ =0C
+ /*
+  *--------------------------------------------------------------
+  *
+  * Further Buffer routines --
+  *
+  *    These are the buffer type manager required routines. =

+  *      For buffers, they do nothing and/or return an error.
+  *
+  *--------------------------------------------------------------
+  */
+ =

+ static void
+ CanvasEventuallyRedrawBuffer (canvasPtr, itemPtr)
+     TkCanvas *canvasPtr;              /* Canvas to invalidate. */
+     Tk_Item *itemPtr;                 /* Buffer to be redrawn. */
+ {
+     if (!canvasPtr->tkwin)
+       return;
+     Tk_CanvasEventuallyRedrawItemPartially((Tk_Canvas) canvasPtr, itemP=
tr,
+             canvasPtr->xOrigin, canvasPtr->yOrigin,
+             canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
+             canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
+ }
+ =

+ static int
+ ConfigureBuffer (interp, canvas, itemPtr, argc, argv, flags)
+     Tcl_Interp *interp;               /* Interpreter for error reporting. */
+     Tk_Canvas canvas;         /* Canvas containing itemPtr. */
+     Tk_Item *itemPtr;         /* Buffer item to reconfigure. */
+     int argc;                 /* Number of elements in argv.  */
+     char **argv;              /* Arguments describing things to configure. */
+     int flags;                        /* Flags to pass to Tk_ConfigureWidget. */
+ {
+     if (Tk_ConfigureWidget(interp, Tk_CanvasTkwin(canvas), bufferConfig=
Specs, =

+           argc, argv, (char *) itemPtr, flags) !=3D TCL_OK) {
+       return TCL_ERROR;
+     }
+     return TCL_OK;
+ }
+ =

+ static void
+ DisplayBuffer (canvas, itemPtr, display, drawable, x, y, width, height)=

+     Tk_Canvas canvas;                 /* Canvas that contains item. */
+     Tk_Item *itemPtr;                 /* Item to be displayed. */
+     Display *display;                 /* Display on which to draw item. */
+     Drawable drawable;                        /* Pixmap or window in which to draw
+                                        * item. */
+     int x, y, width, height;          /* Describes region of canvas that
+                                        * must be redisplayed (not used). */
+ {
+     panic("tried to display buffer %d in canvas %s", itemPtr->id,
+           Tk_PathName(Tk_CanvasTkwin(canvas)));
+ }
+ =

+ static void
+ ScaleBuffer (canvas, itemPtr, originX, originY, scaleX, scaleY)
+     Tk_Canvas canvas;                 /* Canvas containing buffer. */
+     Tk_Item *itemPtr;                 /* Buffer to be scaled. */
+     double originX, originY;          /* Origin about which to scale buffer. */=

+     double scaleX;                    /* Amount to scale in X direction. */
+     double scaleY;                    /* Amount to scale in Y direction. */
+ {
+ }
+ =

+ static void
+ TranslateBuffer (canvas, itemPtr, deltaX, deltaY)
+     Tk_Canvas canvas;                 /* Canvas containing buffer. */
+     Tk_Item *itemPtr;                 /* Buffer that is being moved. */
+     double deltaX, deltaY;            /* Amount by which buffer is to be
+                                        * moved. */
+ {
+ }
+ =

+ static int
+ BufferToArea(canvas, itemPtr, rectPtr)
+     Tk_Canvas canvas;         /* Canvas containing itemPtr. */
+     Tk_Item *itemPtr;         /* Item to check against rectangle. */
+     double *rectPtr;          /* Pointer to array of four coordinates
+                                * (x1, y1, x2, y2) describing rectangular
+                                * area.  */
+ {
+     return -1;
+ }
+ =

+ static double
+ BufferToPoint(canvas, itemPtr, pointPtr)
+     Tk_Canvas canvas;         /* Canvas containing itemPtr. */
+     Tk_Item *itemPtr;         /* Item to check against point. */
+     double *pointPtr;         /* Pointer to x and y coordinates. */
+ {
+     return 1.7E308;
+ }
+ =0C
  /*
   * Various Tk_Uid's used by this module (set up during initialization):=

   */
***************
*** 164,169 ****
--- 505,517 ----
  static int numSlowSearches;
  =

  /*
+  * Boolean variable indicating whether or not special debugging code
+  * should be executed.
+  */
+ =

+ int tkCanvasDebug =3D 0;
+ =

+ /*
   * Prototypes for procedures defined later in this file:
   */
  =

***************
*** 176,181 ****
--- 524,534 ----
                            XEvent *eventPtr));
  static void           CanvasEventProc _ANSI_ARGS_((ClientData clientData,
                            XEvent *eventPtr));
+ static void             CanvasEventuallyRedrawAll _ANSI_ARGS_((
+                             TkCanvas *canvasPtr));
+ static void             CanvasEventuallyRedrawExpose _ANSI_ARGS_((
+                           TkCanvas *canvasPtr,
+                             int x1, int y1, int x2, int y2));
  static int            CanvasFetchSelection _ANSI_ARGS_((
                            ClientData clientData, int offset,
                            char *buffer, int maxBytes));
***************
*** 293,298 ****
--- 646,652 ----
            (ClientData) canvasPtr, CanvasCmdDeletedProc);
      canvasPtr->firstItemPtr =3D NULL;
      canvasPtr->lastItemPtr =3D NULL;
+     canvasPtr->firstBufferPtr =3D NULL;
      canvasPtr->borderWidth =3D 0;
      canvasPtr->bgBorder =3D NULL;
      canvasPtr->relief =3D TK_RELIEF_FLAT;
***************
*** 647,662 ****
        itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr !=3D NULL) {
            if (argc !=3D 3) {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
            if (itemPtr->typePtr->coordProc !=3D NULL) {
                result =3D (*itemPtr->typePtr->coordProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
            }
            if (argc !=3D 3) {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
        }
      } else if ((c =3D=3D 'c') && (strncmp(argv[1], "create", length) =3D=
=3D 0)
--- 1001,1014 ----
        itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr !=3D NULL) {
            if (argc !=3D 3) {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            }
            if (itemPtr->typePtr->coordProc !=3D NULL) {
                result =3D (*itemPtr->typePtr->coordProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
            }
            if (argc !=3D 3) {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            }
        }
      } else if ((c =3D=3D 'c') && (strncmp(argv[1], "create", length) =3D=
=3D 0)
***************
*** 696,707 ****
        itemPtr->tagSpace =3D TK_TAG_SPACE;
        itemPtr->numTags =3D 0;
        itemPtr->typePtr =3D typePtr;
        if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
                itemPtr, argc-3, argv+3) !=3D TCL_OK) {
            ckfree((char *) itemPtr);
            goto error;
        }
-       itemPtr->nextPtr =3D NULL;
        canvasPtr->hotPtr =3D itemPtr;
        canvasPtr->hotPrevPtr =3D canvasPtr->lastItemPtr;
        if (canvasPtr->lastItemPtr =3D=3D NULL) {
--- 1048,1063 ----
        itemPtr->tagSpace =3D TK_TAG_SPACE;
        itemPtr->numTags =3D 0;
        itemPtr->typePtr =3D typePtr;
+       itemPtr->nextPtr =3D NULL;
+       itemPtr->prevBufferPtr =3D canvasPtr->lastItemPtr;
+       if (itemPtr->prevBufferPtr && !CanvasIsBuffer(itemPtr->prevBufferPtr))=
 {
+           itemPtr->prevBufferPtr =3D itemPtr->prevBufferPtr->prevBufferPtr;
+       }
        if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
                itemPtr, argc-3, argv+3) !=3D TCL_OK) {
            ckfree((char *) itemPtr);
            goto error;
        }
        canvasPtr->hotPtr =3D itemPtr;
        canvasPtr->hotPrevPtr =3D canvasPtr->lastItemPtr;
        if (canvasPtr->lastItemPtr =3D=3D NULL) {
***************
*** 710,717 ****
            canvasPtr->lastItemPtr->nextPtr =3D itemPtr;
        }
        canvasPtr->lastItemPtr =3D itemPtr;
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        canvasPtr->flags |=3D REPICK_NEEDED;
        sprintf(interp->result, "%d", itemPtr->id);
      } else if ((c =3D=3D 'd') && (strncmp(argv[1], "dchars", length) =3D=
=3D 0)
--- 1066,1072 ----
            canvasPtr->lastItemPtr->nextPtr =3D itemPtr;
        }
        canvasPtr->lastItemPtr =3D itemPtr;
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
        canvasPtr->flags |=3D REPICK_NEEDED;
        sprintf(interp->result, "%d", itemPtr->id);
      } else if ((c =3D=3D 'd') && (strncmp(argv[1], "dchars", length) =3D=
=3D 0)
***************
*** 750,761 ****
             * the old area.
             */
  =

!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
                    itemPtr, first, last);
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
      } else if ((c =3D=3D 'd') && (strncmp(argv[1], "delete", length) =3D=
=3D 0)
            && (length >=3D 2)) {
--- 1105,1128 ----
             * the old area.
             */
  =

!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
                    itemPtr, first, last);
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
!       }
!     } else if ((c =3D=3D 'd') && (strncmp(argv[1], "debug", length) =3D=
=3D 0)
!           && (length >=3D 3)) {
!       if (argc > 3) {
!           Tcl_AppendResult(interp, "wrong # args: should be \"",
!                   argv[0], " debug ?boolean?\"", (char *) NULL);
!           goto error;
!       }
!       if (argc =3D=3D 2) {
!           interp->result =3D (tkCanvasDebug) ? "1" : "0";
!       } else {
!           if (Tcl_GetBoolean(interp, argv[2], &tkCanvasDebug) !=3D TCL_OK) {=

!               goto error;
!           }
        }
      } else if ((c =3D=3D 'd') && (strncmp(argv[1], "delete", length) =3D=
=3D 0)
            && (length >=3D 2)) {
***************
*** 764,771 ****
        for (i =3D 2; i < argc; i++) {
            for (itemPtr =3D StartTagSearch(canvasPtr, argv[i], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                if (canvasPtr->bindingTable !=3D NULL) {
                    Tk_DeleteAllBindings(canvasPtr->bindingTable,
                            (ClientData) itemPtr);
--- 1131,1137 ----
        for (i =3D 2; i < argc; i++) {
            for (itemPtr =3D StartTagSearch(canvasPtr, argv[i], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
                if (canvasPtr->bindingTable !=3D NULL) {
                    Tk_DeleteAllBindings(canvasPtr->bindingTable,
                            (ClientData) itemPtr);
***************
*** 858,865 ****
            goto done;
        }
        if ((itemPtr !=3D NULL) && (canvasPtr->textInfo.gotFocus)) {
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
        if (argv[2][0] =3D=3D 0) {
            canvasPtr->textInfo.focusItemPtr =3D NULL;
--- 1224,1230 ----
            goto done;
        }
        if ((itemPtr !=3D NULL) && (canvasPtr->textInfo.gotFocus)) {
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
        }
        if (argv[2][0] =3D=3D 0) {
            canvasPtr->textInfo.focusItemPtr =3D NULL;
***************
*** 876,883 ****
        }
        canvasPtr->textInfo.focusItemPtr =3D itemPtr;
        if (canvasPtr->textInfo.gotFocus) {
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
      } else if ((c =3D=3D 'g') && (strncmp(argv[1], "gettags", length) =3D=
=3D 0)) {
        if (argc !=3D 3) {
--- 1241,1247 ----
        }
        canvasPtr->textInfo.focusItemPtr =3D itemPtr;
        if (canvasPtr->textInfo.gotFocus) {
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
        }
      } else if ((c =3D=3D 'g') && (strncmp(argv[1], "gettags", length) =3D=
=3D 0)) {
        if (argc !=3D 3) {
***************
*** 916,923 ****
                    index);
            if ((itemPtr =3D=3D canvasPtr->textInfo.focusItemPtr)
                    && (canvasPtr->textInfo.cursorOn)) {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
        }
      } else if ((c =3D=3D 'i') && (strncmp(argv[1], "index", length) =3D=
=3D 0)
--- 1280,1286 ----
                    index);
            if ((itemPtr =3D=3D canvasPtr->textInfo.focusItemPtr)
                    && (canvasPtr->textInfo.cursorOn)) {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            }
        }
      } else if ((c =3D=3D 'i') && (strncmp(argv[1], "index", length) =3D=
=3D 0)
***************
*** 973,984 ****
             * larger or smaller than the old area.
             */
  =

!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
                    itemPtr, beforeThis, argv[4]);
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1,
!                   itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
      } else if ((c =3D=3D 'i') && (strncmp(argv[1], "itemcget", length) =
=3D=3D 0)
            && (length >=3D 6)) {
--- 1336,1345 ----
             * larger or smaller than the old area.
             */
  =

!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
                    itemPtr, beforeThis, argv[4]);
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
        }
      } else if ((c =3D=3D 'i') && (strncmp(argv[1], "itemcget", length) =
=3D=3D 0)
            && (length >=3D 6)) {
***************
*** 1013,1025 ****
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        argv[3], 0);
            } else {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                result =3D (*itemPtr->typePtr->configProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,
                        TK_CONFIG_ARGV_ONLY);
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                canvasPtr->flags |=3D REPICK_NEEDED;
            }
            if ((result !=3D TCL_OK) || (argc < 5)) {
--- 1374,1384 ----
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        argv[3], 0);
            } else {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
                result =3D (*itemPtr->typePtr->configProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,
                        TK_CONFIG_ARGV_ONLY);
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
                canvasPtr->flags |=3D REPICK_NEEDED;
            }
            if ((result !=3D TCL_OK) || (argc < 5)) {
***************
*** 1070,1081 ****
        }
        for (itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
                    itemPtr,  xAmount, yAmount);
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            canvasPtr->flags |=3D REPICK_NEEDED;
        }
      } else if ((c =3D=3D 'p') && (strncmp(argv[1], "postscript", length=
) =3D=3D 0)) {
--- 1429,1438 ----
        }
        for (itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
                    itemPtr,  xAmount, yAmount);
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            canvasPtr->flags |=3D REPICK_NEEDED;
        }
      } else if ((c =3D=3D 'p') && (strncmp(argv[1], "postscript", length=
) =3D=3D 0)) {
***************
*** 1134,1145 ****
        }
        for (itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
                    itemPtr, xOrigin, yOrigin, xScale, yScale);
!           Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                   itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            canvasPtr->flags |=3D REPICK_NEEDED;
        }
      } else if ((c =3D=3D 's') && (strncmp(argv[1], "scan", length) =3D=3D=
 0)
--- 1491,1500 ----
        }
        for (itemPtr =3D StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
                    itemPtr, xOrigin, yOrigin, xScale, yScale);
!           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
            canvasPtr->flags |=3D REPICK_NEEDED;
        }
      } else if ((c =3D=3D 's') && (strncmp(argv[1], "scan", length) =3D=3D=
 0)
***************
*** 1240,1250 ****
                goto error;
            }
            if (canvasPtr->textInfo.selItemPtr !=3D NULL) {
!               Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!                       canvasPtr->textInfo.selItemPtr->x1,
!                       canvasPtr->textInfo.selItemPtr->y1,
!                       canvasPtr->textInfo.selItemPtr->x2,
!                       canvasPtr->textInfo.selItemPtr->y2);
                canvasPtr->textInfo.selItemPtr =3D NULL;
            }
            goto done;
--- 1595,1602 ----
                goto error;
            }
            if (canvasPtr->textInfo.selItemPtr !=3D NULL) {
!               Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr,
!                       canvasPtr->textInfo.selItemPtr);
                canvasPtr->textInfo.selItemPtr =3D NULL;
            }
            goto done;
***************
*** 1567,1576 ****
  =

      CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);=

      canvasPtr->flags |=3D UPDATE_SCROLLBARS|REDRAW_BORDERS;
!     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!           canvasPtr->xOrigin, canvasPtr->yOrigin,
!           canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
!           canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
      return TCL_OK;
  }
  =0C
--- 1919,1925 ----
  =

      CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);=

      canvasPtr->flags |=3D UPDATE_SCROLLBARS|REDRAW_BORDERS;
!     CanvasEventuallyRedrawAll(canvasPtr);
      return TCL_OK;
  }
  =0C
***************
*** 1605,1622 ****
      canvasPtr =3D (TkCanvas *) instanceData;
      itemPtr =3D canvasPtr->firstItemPtr;
      for ( ; itemPtr !=3D NULL; itemPtr =3D itemPtr->nextPtr) {
!       result =3D (*itemPtr->typePtr->configProc)(canvasPtr->interp,
!               (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
!               TK_CONFIG_ARGV_ONLY);
!       if (result !=3D TCL_OK) {
!           Tcl_ResetResult(canvasPtr->interp);
        }
      }
      canvasPtr->flags |=3D REPICK_NEEDED;
!     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!           canvasPtr->xOrigin, canvasPtr->yOrigin,
!           canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
!           canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
  }
  =0C
  /*
--- 1954,1970 ----
      canvasPtr =3D (TkCanvas *) instanceData;
      itemPtr =3D canvasPtr->firstItemPtr;
      for ( ; itemPtr !=3D NULL; itemPtr =3D itemPtr->nextPtr) {
!       if (itemPtr->typePtr->configProc) {
!               result =3D (*itemPtr->typePtr->configProc)(canvasPtr->interp,
!                       (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
!                       TK_CONFIG_ARGV_ONLY);
!               if (result !=3D TCL_OK) {
!                   Tcl_ResetResult(canvasPtr->interp);
!           }
        }
      }
      canvasPtr->flags |=3D REPICK_NEEDED;
!     CanvasEventuallyRedrawAll(canvasPtr);
  }
  =0C
  /*
***************
*** 1636,1642 ****
   *
   *--------------------------------------------------------------
   */
! =

  static void
  DisplayCanvas(clientData)
      ClientData clientData;    /* Information about widget. */
--- 1984,1990 ----
   *
   *--------------------------------------------------------------
   */
!  =

  static void
  DisplayCanvas(clientData)
      ClientData clientData;    /* Information about widget. */
***************
*** 1644,1655 ****
      TkCanvas *canvasPtr =3D (TkCanvas *) clientData;
      Tk_Window tkwin =3D canvasPtr->tkwin;
      Tk_Item *itemPtr;
!     Pixmap pixmap;
!     int screenX1, screenX2, screenY1, screenY2, width, height;
! =

      if (canvasPtr->tkwin =3D=3D NULL) {
        return;
      }
      if (!Tk_IsMapped(tkwin)) {
        goto done;
      }
--- 1992,2011 ----
      TkCanvas *canvasPtr =3D (TkCanvas *) clientData;
      Tk_Window tkwin =3D canvasPtr->tkwin;
      Tk_Item *itemPtr;
!     Tk_Item *lastItemPtr;
!     Pixmap tempForClipping =3D None;
!     int sx1, sy1, sx2, sy2;
! =

!     if (tkCanvasDebug) {
!       Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL,
!               Tcl_GetCommandName(canvasPtr->interp, canvasPtr->widgetCmd),
!                 TCL_GLOBAL_ONLY);
!     }
!                     =

      if (canvasPtr->tkwin =3D=3D NULL) {
        return;
      }
+     =

      if (!Tk_IsMapped(tkwin)) {
        goto done;
      }
***************
*** 1671,1724 ****
      }
  =

      /*
!      * Compute the intersection between the area that needs redrawing
!      * and the area that's visible on the screen.
       */
  =

!     if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
!           && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
!       screenX1 =3D canvasPtr->xOrigin + canvasPtr->inset;
!       screenY1 =3D canvasPtr->yOrigin + canvasPtr->inset;
!       screenX2 =3D canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
!       screenY2 =3D canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;=

!       if (canvasPtr->redrawX1 > screenX1) {
!           screenX1 =3D canvasPtr->redrawX1;
!       }
!       if (canvasPtr->redrawY1 > screenY1) {
!           screenY1 =3D canvasPtr->redrawY1;
        }
!       if (canvasPtr->redrawX2 < screenX2) {
!           screenX2 =3D canvasPtr->redrawX2;
        }
!       if (canvasPtr->redrawY2 < screenY2) {
!           screenY2 =3D canvasPtr->redrawY2;
        }
!       if ((screenX1 >=3D screenX2) || (screenY1 >=3D screenY2)) {
!           goto borders;
        }
      =

        /*
         * Redrawing is done in a temporary pixmap that is allocated
         * here and freed at the end of the procedure.  All drawing
         * is done to the pixmap, and the pixmap is copied to the
         * screen at the end of the procedure. The temporary pixmap
!        * serves two purposes:
!        *
!        * 1. It provides a smoother visual effect (no clearing and
!        *    gradual redraw will be visible to users).
!        * 2. It allows us to redraw only the objects that overlap
!        *    the redraw area.  Otherwise incorrect results could
!        *        occur from redrawing things that stick outside of
!        *        the redraw area (we'd have to redraw everything in
!        *    order to make the overlaps look right).
         *
!        * Some tricky points about the pixmap:
         *
!        * 1. We only allocate a large enough pixmap to hold the
!        *    area that has to be redisplayed.  This saves time in
!        *    in the X server for large objects that cover much
!        *    more than the area being redisplayed:  only the area
!        *    of the pixmap will actually have to be redrawn.
         * 2. Some X servers (e.g. the one for DECstations) have troubles
         *    with characters that overlap an edge of the pixmap (on the
         *    DEC servers, as of 8/18/92, such characters are drawn one
--- 2027,2236 ----
      }
  =

      /*
!      * Compute in advance the item area of the canvas (i.e., the area
!      * of the window not covered by the highlight frame and the border.=

!      */
! =

!     sx1 =3D canvasPtr->xOrigin + canvasPtr->inset;
!     sy1 =3D canvasPtr->yOrigin + canvasPtr->inset;
!     sx2 =3D canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
!     sy2 =3D canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
! =

!     if (tkCanvasDebug) {
!       char string[80];
!       sprintf(string,"area {%d %d %d %d}",
!               sx1, sy1, sx2, sy2);
!       Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, strin=
g,
!                 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!     }
! =

!     /*
!      * Start to iterate over all buffers and items.
       */
  =

!     itemPtr =3D canvasPtr->firstItemPtr;
!     do {
!       BufferItem *bufferPtr;      /* Buffer to copy from, or =

!                                    * NULL if to paint background. */
!       BufferItem *nextBufferPtr;  /* Buffer to draw into, or =

!                                    * NULL if to draw to window. */
!       int x1, y1, x2, y2;         /* Dirty rectangle, grows while
!                                    * refreshing from bottom to top. */
!       int screenX1, screenX2,     /* Dirty rectancle confined to screen.=
 */
!           screenY1, screenY2;
!       int width, height;
! =

!       int sourceXOrigin,
!           sourceYOrigin;
! =

!       Drawable drawInto;          /* Drawable to draw into, either =

!                                    * tempForClipping or target. */
!       Drawable target;            /* Drawable to finally place drawing into=
,
!                                    * either nextBufferPtr->buffer or tkwin. */
!       int targetXOrigin,
!           targetYOrigin;
! =

!       if (itemPtr =3D=3D canvasPtr->firstItemPtr) {
!           bufferPtr =3D NULL;
!           nextBufferPtr =3D canvasPtr->firstBufferPtr;
!           x1 =3D canvasPtr->redrawX1;
!           y1 =3D canvasPtr->redrawY1;
!           x2 =3D canvasPtr->redrawX2;
!           y2 =3D canvasPtr->redrawY2;
!           canvasPtr->redrawX1 =3D canvasPtr->redrawX2 =3D 0;
!           canvasPtr->redrawY1 =3D canvasPtr->redrawY2 =3D 0;
!       } else {
!           bufferPtr =3D (BufferItem*) itemPtr;
!           itemPtr =3D itemPtr->nextPtr;
!           nextBufferPtr =3D bufferPtr->nextBufferPtr;
!           if (bufferPtr->x1 < bufferPtr->x2 && bufferPtr->y1 < bufferPtr->y2=
) {
!               if (x1 < x2 && y1 < y2) {
!                   if (bufferPtr->x1 < x1)
!                       x1 =3D bufferPtr->x1;
!                   if (bufferPtr->y1 < y1)
!                       y1 =3D bufferPtr->y1;
!                   if (bufferPtr->x2 > x2)
!                       x2 =3D bufferPtr->x2;
!                   if (bufferPtr->y2 > y2)
!                       y2 =3D bufferPtr->y2;
!               } else {
!                   x1 =3D bufferPtr->x1;
!                   y1 =3D bufferPtr->y1;
!                   x2 =3D bufferPtr->x2;
!                   y2 =3D bufferPtr->y2;
!               }
!           }
!           bufferPtr->x1 =3D bufferPtr->x2 =3D 0;
!           bufferPtr->y1 =3D bufferPtr->y2 =3D 0;
!       }
! =

!       if (tkCanvasDebug) {
!           char string[80];
!           if (bufferPtr) {
!               sprintf(string,"dirtybuf %d {%d %d %d %d}",
!                       bufferPtr->header.id, x1, y1, x2, y2);
!           } else {
!               sprintf(string,"dirty {%d %d %d %d}",
!                       x1, y1, x2, y2);
!           }
!           Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, =

!                   string, TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
        }
! =

!         /*
!          * Compute the intersection between the area that needs redrawi=
ng
!          * and the area that's visible on the screen.
!          */
!       =

!       if (x1 < x2 && y1 < y2) {
!           screenX1 =3D sx1;
!           screenY1 =3D sy1;
!           screenX2 =3D sx2;
!           screenY2 =3D sy2;
!           if (screenX1 < x1)
!               screenX1 =3D x1;
!           if (screenY1 < y1)
!               screenY1 =3D y1;
!           if (screenX2 > x2)
!               screenX2 =3D x2;
!           if (screenY2 > y2)
!               screenY2 =3D y2;
!       } else {
!           screenX1 =3D screenY1 =3D screenX2 =3D screenY2 =3D 0;
        }
!  =

!         /*
!          * We skip this buffer if nothing is dirty.
!          */
! =

!       if (screenX1 >=3D screenX2 || screenY1 >=3D screenY2) {
!           itemPtr =3D (Tk_Item*) nextBufferPtr;
!           continue;
        }
! =

!       /*
!        * The buffer pixmaps serve two purposes:
!        *
!        * 1. They provides a smoother visual effect (no clearing and
!        *    gradual redraw will be visible to users) when necessary.
!        * 2. They allow a fast animation on top of already-drawn
!        *    background without reverting to those obscure video
!        *    buffer resp. colormap segmentation tricks that Windows =

!        *    anyhow doesn't support.
!        */
! =

!       if (nextBufferPtr) {
!           target =3D nextBufferPtr->buffer;
!           if (target !=3D None && (nextBufferPtr->width < sx2 - sx1
!                   || nextBufferPtr->height < sy2 - sy1)) {
!               Tk_FreePixmap(Tk_Display(tkwin), target);
!               target =3D None;
!           }
!           if (target =3D=3D None) {
!               nextBufferPtr->width =3D sx2-sx1;
!               nextBufferPtr->height =3D sy2-sy1;
!               target =3D Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
!                       nextBufferPtr->width+60, nextBufferPtr->height+60, Tk_Depth(tkwi=
n));
!               screenX1 =3D sx1;
!               if (x1>screenX1)
!                   x1 =3D screenX1;
!               screenY1 =3D sy1;
!               if (y1>screenY1)
!                   y1 =3D screenY1;
!               screenX2 =3D sx2;
!               if (x2<screenX2)
!                   x2 =3D screenX2;
!               screenY2 =3D sy2;
!               if (y2<screenY2)
!                   y2 =3D screenY2;
!               /* In principle it would be sufficient to redraw this pixmap,
!                * and then copy only the originally flagged dirty parts. However, =

!                * the buffer gets allocated only upon resizing, and in this case
!                * everything is dirty anyhow ... */
!           }
!           nextBufferPtr->buffer =3D target;
!           targetXOrigin =3D sx1 - 30;
!           targetYOrigin =3D sy1 - 30;
!       } else {
!           target =3D Tk_WindowId(tkwin);
!           targetXOrigin =3D canvasPtr->xOrigin;
!           targetYOrigin =3D canvasPtr->yOrigin;
!       }    =

! =

!       if (tkCanvasDebug) {
!           char string[80];
!           sprintf(string,"dirtyarea {%d %d %d %d}",
!                   screenX1, screenY1, screenX2, screenY2);
!           Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, s=
tring,
!                     TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);=

!           if (nextBufferPtr)
!               sprintf(string,"target %d", nextBufferPtr->header.id);
!           else
!               sprintf(string,"target window");
!           Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, s=
tring,
!                     TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);=

        }
      =

+       width =3D screenX2 - screenX1;
+       height =3D screenY2 - screenY1;
+ =

        /*
         * Redrawing is done in a temporary pixmap that is allocated
         * here and freed at the end of the procedure.  All drawing
         * is done to the pixmap, and the pixmap is copied to the
         * screen at the end of the procedure. The temporary pixmap
!        * allows us to redraw only the objects that overlap
!        * the redraw area.  Otherwise incorrect results will
!        * occur from redrawing things that stick outside of
!        * the redraw area. This could only be avoided by clipping all
!        * gc's used during the redraw process to the rectangle being redrawn.=

!        * This is not currently supported by neither the canvas items
!        * nor the Tk GC handling.
         *
!        * Some tricky points about the temporary pixmap:
         *
!        * 1. We allocate a pixmap large enough to cover the item area
!        *    since we don't know yet the final dirty size of the window.
         * 2. Some X servers (e.g. the one for DECstations) have troubles
         *    with characters that overlap an edge of the pixmap (on the
         *    DEC servers, as of 8/18/92, such characters are drawn one
***************
*** 1727,1801 ****
         *    so that for normal-sized fonts the characters that overlap
         *    the edge of the pixmap will be outside the area we care
         *    about.
         */
!     =

!       canvasPtr->drawableXOrigin =3D screenX1 - 30;
!       canvasPtr->drawableYOrigin =3D screenY1 - 30;
!       pixmap =3D Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
!           (screenX2 + 30 - canvasPtr->drawableXOrigin),
!           (screenY2 + 30 - canvasPtr->drawableYOrigin),
!           Tk_Depth(tkwin));
!     =

        /*
         * Clear the area to be redrawn.
         */
      =

!       width =3D screenX2 - screenX1;
!       height =3D screenY2 - screenY1;
!     =

!       XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
!               screenX1 - canvasPtr->drawableXOrigin,
!               screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
!               (unsigned int) height);
      =

        /*
         * Scan through the item list, redrawing those items that need it.
!        * An item must be redraw if either (a) it intersects the smaller
         * on-screen area or (b) it intersects the full canvas area and its
         * type requests that it be redrawn always (e.g. so subwindows can
         * be unmapped when they move off-screen).
         */
      =

!       for (itemPtr =3D canvasPtr->firstItemPtr; itemPtr !=3D NULL;
!               itemPtr =3D itemPtr->nextPtr) {
            if ((itemPtr->x1 >=3D screenX2)
                    || (itemPtr->y1 >=3D screenY2)
                    || (itemPtr->x2 < screenX1)
                    || (itemPtr->y2 < screenY1)) {
                if (!itemPtr->typePtr->alwaysRedraw
!                       || (itemPtr->x1 >=3D canvasPtr->redrawX2)
!                       || (itemPtr->y1 >=3D canvasPtr->redrawY2)
!                       || (itemPtr->x2 < canvasPtr->redrawX1)
!                       || (itemPtr->y2 < canvasPtr->redrawY1)) {
                    continue;
                }
            }
            (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
!                   canvasPtr->display, pixmap, screenX1, screenY1, width,
                    height);
        }
!     =

        /*
!        * Copy from the temporary pixmap to the screen, then free up
!        * the temporary pixmap.
         */
      =

!       XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
!               canvasPtr->pixmapGC,
!               screenX1 - canvasPtr->drawableXOrigin,
!               screenY1 - canvasPtr->drawableYOrigin,
!               (unsigned) (screenX2 - screenX1),
!               (unsigned) (screenY2 - screenY1),
!               screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
!       Tk_FreePixmap(Tk_Display(tkwin), pixmap);
!     }
  =

      /*
       * Draw the window borders, if needed.
       */
  =

-     borders:
      if (canvasPtr->flags & REDRAW_BORDERS) {
        canvasPtr->flags &=3D ~REDRAW_BORDERS;
        if (canvasPtr->borderWidth > 0) {
            Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
--- 2239,2433 ----
         *    so that for normal-sized fonts the characters that overlap
         *    the edge of the pixmap will be outside the area we care
         *    about.
+        *
+        * Note that the buffer pixmap allocation code above already =

+        * respects point 2. although this isn't necessary as long as
+        * we use the temporary pixmap to draw into -- and maybe, after
+        * five years, DEC has found and fixed the X server bug?
+        *
+        * IDEA: =

+        * Add a canvas usage refcount to GC's. Add Tk_GetCanvasGC, =

+        * Tk_FreeCanvasGC and change all canvas items to use them.
+        * Add Tk_ClipCanvasGC, call it for each dirty rectangle, and
+        * unclip all canvas GC's again prior to leaving DisplayCanvas.
         */
! =

!       if (    /* =

!                * If we use buffers (i.e., need not to be backwards-
!                * compatible) ...
!                */
!               canvasPtr->firstBufferPtr
!               /* =

!                * and the whole target gets redrawn (including the =

!                * borders in case of the window,
!                */
!               && width=3D=3Dsx2-sx1 && height=3D=3Dsy2-sy1
!               && (nextBufferPtr || canvasPtr->flags & REDRAW_BORDERS)
!               /* =

!                * or if there are no items within this buffer at all =

!                * that might destroy information due to not clipping
!                */
!               || itemPtr=3D=3D(Tk_Item*)nextBufferPtr) {
!               =

!           /*
!            * we may directly draw to the target.
!            */ =

!         =

!           drawInto =3D target;
!           canvasPtr->drawableXOrigin =3D targetXOrigin;
!           canvasPtr->drawableYOrigin =3D targetYOrigin;
!       } else {
!           if (tempForClipping=3D=3DNone) {
!               if (nextBufferPtr) {
!                   /*
!                    * We don't know the final amount of damage because there
!                    * is still a buffer in front of us which might be damaged
!                    * worse! We allocate the full widget size for the
!                    * temporary pixmap (we could alternatively create
!                    * a new pixmap and destroy the former for every buffer!).
!                    * IDEA: Calculate the minimum necessary size of the
!                    * temporary pixmap.
!                    */
!                   tempForClipping =3D Tk_GetPixmap(Tk_Display(tkwin), =

!                       Tk_WindowId(tkwin), sx2 - sx1 + 60, sy2 - sy1 + 60,
!                       Tk_Depth(tkwin));
!                   canvasPtr->drawableXOrigin =3D sx1 - 30;
!                   canvasPtr->drawableYOrigin =3D sy1 - 30;
!               } else {
!                   /*
!                    * We know the final damage here since out target is the wind=
ow!
!                    */
!                   tempForClipping =3D Tk_GetPixmap(Tk_Display(tkwin), =

!                       Tk_WindowId(tkwin), screenX2 - screenX1 + 60, =

!                       screenY2 - screenY1 + 60, Tk_Depth(tkwin));
!                   canvasPtr->drawableXOrigin =3D screenX1 - 30;
!                   canvasPtr->drawableYOrigin =3D screenY1 - 30;
!               }
!           }
!           drawInto =3D tempForClipping;
!           if (tkCanvasDebug) {
!               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL,
!                       "drawinto temporary",
!                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!           }
!       }
! =

        /*
         * Clear the area to be redrawn.
         */
      =

!       if (!bufferPtr) {
!           XFillRectangle(Tk_Display(tkwin), drawInto, canvasPtr->pixmapGC,
!                   screenX1 - canvasPtr->drawableXOrigin,
!                   screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
!                   (unsigned int) height);
!       } else {
!           sourceXOrigin =3D sx1 - 30;
!           sourceYOrigin =3D sy1 - 30;
!           XCopyArea(Tk_Display(tkwin), bufferPtr->buffer, drawInto,
!                   canvasPtr->pixmapGC,
!                   screenX1 - sourceXOrigin,
!                   screenY1 - sourceYOrigin,
!                   (unsigned int) width,
!                   (unsigned int) height,
!                   screenX1 - canvasPtr->drawableXOrigin, =

!                   screenY1 - canvasPtr->drawableYOrigin);
!       }
      =

        /*
         * Scan through the item list, redrawing those items that need it.
!        * An item must be redrawn if either (a) it intersects the smaller
         * on-screen area or (b) it intersects the full canvas area and its
         * type requests that it be redrawn always (e.g. so subwindows can
         * be unmapped when they move off-screen).
         */
      =

!       if (tkCanvasDebug) {
!           if (itemPtr !=3D (Tk_Item*) nextBufferPtr) {
!               char string[80];
!               sprintf(string, "item start %d", itemPtr->id);
!               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, stri=
ng,
!                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!             }
!             lastItemPtr =3D NULL;
!       }
! =

!       for (; itemPtr !=3D (Tk_Item*) nextBufferPtr; itemPtr =3D itemPtr->nex=
tPtr) {
!           lastItemPtr =3D itemPtr;
            if ((itemPtr->x1 >=3D screenX2)
                    || (itemPtr->y1 >=3D screenY2)
                    || (itemPtr->x2 < screenX1)
                    || (itemPtr->y2 < screenY1)) {
                if (!itemPtr->typePtr->alwaysRedraw
!                       || (itemPtr->x1 >=3D x2)
!                       || (itemPtr->y1 >=3D y2)
!                       || (itemPtr->x2 < x1)
!                       || (itemPtr->y2 < y1)) {
                    continue;
                }
            }
+           if (tkCanvasDebug) {
+               char string[80];
+               sprintf(string, "item display %d", itemPtr->id);
+               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, stri=
ng,
+                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
+           }
            (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
!                   canvasPtr->display, drawInto, screenX1, screenY1, width,
                    height);
        }
!       =

!       if (tkCanvasDebug) {
!           if (lastItemPtr) {
!               char string[80];
!               sprintf(string, "item end %d", lastItemPtr->id);
!               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, stri=
ng,
!                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!             }
!       }
! =

        /*
!        * Copy from the temporary pixmap to the target drawable
!        * (next buffer, or window).
         */
      =

!       if (drawInto!=3Dtarget) {
!           if (tkCanvasDebug) {
!               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL,
!                       "copying temporary",
!                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!           }
!           XCopyArea(Tk_Display(tkwin), drawInto, target,
!                   canvasPtr->pixmapGC,
!                   screenX1 - canvasPtr->drawableXOrigin,
!                   screenY1 - canvasPtr->drawableYOrigin,
!                   (unsigned int) width,
!                   (unsigned int) height,
!                   screenX1 - targetXOrigin, screenY1 - targetYOrigin);
!       }
!     } while (itemPtr);
! =

!     /*
!      * Free up the temporary pixmap, if necessary.
!      */
!     =

!     if (tempForClipping!=3DNone)
!       Tk_FreePixmap(Tk_Display(tkwin), tempForClipping);
  =

      /*
       * Draw the window borders, if needed.
       */
  =

      if (canvasPtr->flags & REDRAW_BORDERS) {
+ =

+       if (tkCanvasDebug) {
+           char string[80];
+           sprintf(string, "borders %d %d", canvasPtr->borderWidth,
+                   canvasPtr->highlightWidth);
+           Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, s=
tring,
+                     TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);=

+       }
+ =

        canvasPtr->flags &=3D ~REDRAW_BORDERS;
        if (canvasPtr->borderWidth > 0) {
            Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
***************
*** 1822,1830 ****
  =

      done:
      canvasPtr->flags &=3D ~REDRAW_PENDING;
!     canvasPtr->redrawX1 =3D canvasPtr->redrawX2 =3D 0;
!     canvasPtr->redrawY1 =3D canvasPtr->redrawY2 =3D 0;
!     if (canvasPtr->flags & UPDATE_SCROLLBARS) {
        CanvasUpdateScrollbars(canvasPtr);
      }
  }
--- 2454,2465 ----
  =

      done:
      canvasPtr->flags &=3D ~REDRAW_PENDING;
!       if (canvasPtr->flags & UPDATE_SCROLLBARS) {
!           if (tkCanvasDebug) {
!               Tcl_SetVar2(canvasPtr->interp, "tk_canvasRedraw", (char *) NULL, =

!                       "scrollbars",
!                       TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
!           }
        CanvasUpdateScrollbars(canvasPtr);
      }
  }
***************
*** 1859,1865 ****
  =

        x =3D eventPtr->xexpose.x + canvasPtr->xOrigin;
        y =3D eventPtr->xexpose.y + canvasPtr->yOrigin;
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
                x + eventPtr->xexpose.width,
                y + eventPtr->xexpose.height);
        if ((eventPtr->xexpose.x < canvasPtr->inset)
--- 2494,2501 ----
  =

        x =3D eventPtr->xexpose.x + canvasPtr->xOrigin;
        y =3D eventPtr->xexpose.y + canvasPtr->yOrigin;
!       CanvasEventuallyRedrawExpose(canvasPtr, =

!               x, y,
                x + eventPtr->xexpose.width,
                y + eventPtr->xexpose.height);
        if ((eventPtr->xexpose.x < canvasPtr->inset)
***************
*** 1889,1898 ****
         */
  =

        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
!               canvasPtr->yOrigin,
!               canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
!               canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
        canvasPtr->flags |=3D REDRAW_BORDERS;
      } else if (eventPtr->type =3D=3D FocusIn) {
        if (eventPtr->xfocus.detail !=3D NotifyInferior) {
--- 2525,2531 ----
         */
  =

        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
!       CanvasEventuallyRedrawAll(canvasPtr);
        canvasPtr->flags |=3D REDRAW_BORDERS;
      } else if (eventPtr->type =3D=3D FocusIn) {
        if (eventPtr->xfocus.detail !=3D NotifyInferior) {
***************
*** 1976,1981 ****
--- 2609,2638 ----
   *--------------------------------------------------------------
   */
  =

+ static void RectAdd (x1, y1, x2, y2, tox1, toy1, tox2, toy2)
+     int x1, y1;                       /* Upper left corner of area to be added.*/
+     int x2, y2;                       /* Lower right corner of area to be added. */
+     int *tox1, *toy1;         /* Upper left corner of area to add to.*/
+     int *tox2, *toy2;         /* Lower right corner of area to add to. */
+ {
+     if (*tox1=3D=3D*tox2) {
+       *tox1 =3D x1;
+       *toy1 =3D y1;
+       *tox2 =3D x2;
+       *toy2 =3D y2;
+     } else {
+       if (x1<*tox1)
+           *tox1 =3D x1;
+       if (y1<*toy1)
+           *toy1 =3D y1;
+       if (x2>*tox2)
+           *tox2 =3D x2;
+       if (y2>*toy2)
+           *toy2 =3D y2;
+     }
+ }
+ =

+ =

  void
  Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
      Tk_Canvas canvas;         /* Information about widget. */
***************
*** 1985,2011 ****
                                 * Pixels on edge are not redrawn. */
  {
      TkCanvas *canvasPtr =3D (TkCanvas *) canvas;
      if ((x1 =3D=3D x2) || (y1 =3D=3D y2)) {
        return;
      }
!     if (canvasPtr->flags & REDRAW_PENDING) {
!       if (x1 <=3D canvasPtr->redrawX1) {
!           canvasPtr->redrawX1 =3D x1;
!       }
!       if (y1 <=3D canvasPtr->redrawY1) {
!           canvasPtr->redrawY1 =3D y1;
!       }
!       if (x2 >=3D canvasPtr->redrawX2) {
!           canvasPtr->redrawX2 =3D x2;
!       }
!       if (y2 >=3D canvasPtr->redrawY2) {
!           canvasPtr->redrawY2 =3D y2;
!       }
      } else {
!       canvasPtr->redrawX1 =3D x1;
!       canvasPtr->redrawY1 =3D y1;
!       canvasPtr->redrawX2 =3D x2;
!       canvasPtr->redrawY2 =3D y2;
        Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
        canvasPtr->flags |=3D REDRAW_PENDING;
      }
--- 2642,2708 ----
                                 * Pixels on edge are not redrawn. */
  {
      TkCanvas *canvasPtr =3D (TkCanvas *) canvas;
+     Tk_CanvasEventuallyRedrawItemPartially(canvasPtr,
+           canvasPtr->firstItemPtr, x1, y1, x2, y2);
+ }
+ =

+ static void
+ CanvasEventuallyRedrawAll (canvasPtr)
+     TkCanvas *canvasPtr;      /* Canvas to invalidate. */
+ {
+     if (!canvasPtr->tkwin)
+       return;
+     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
+             canvasPtr->xOrigin, canvasPtr->yOrigin,
+             canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
+             canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
+ }
+ =

+ static void
+ CanvasEventuallyRedrawExpose (canvasPtr, x1, y1, x2, y2)
+     TkCanvas *canvasPtr;      /* Canvas to invalidate. */
+     int x1, y1;                       /* Upper left corner of area to redraw.
+                                * Pixels on edge are redrawn. */
+     int x2, y2;                       /* Lower right corner of area to redraw.
+                                * Pixels on edge are not redrawn. */
+ {
+     Tk_CanvasEventuallyRedrawItemPartially((Tk_Canvas) canvasPtr, NULL,=

+           x1, y1, x2, y2);
+ }
+ =

+ void
+ Tk_CanvasEventuallyRedrawItem(canvas, itemPtr)
+     Tk_Canvas canvas;         /* Information about widget. */
+     Tk_Item *itemPtr;         /* Item to know which buffer to mark dirty. */
+ {
+     Tk_CanvasEventuallyRedrawItemPartially(canvas, itemPtr, =

+           itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
+ }
+ =

+ =

+ void
+ Tk_CanvasEventuallyRedrawItemPartially(canvas, itemPtr, x1, y1, x2, y2)=

+     Tk_Canvas canvas;         /* Information about widget. */
+     Tk_Item *itemPtr;         /* Item to know which buffer to mark dirty. */
+     int x1, y1;                       /* Upper left corner of area to redraw.
+                                * Pixels on edge are redrawn. */
+     int x2, y2;                       /* Lower right corner of area to redraw.
+                                * Pixels on edge are not redrawn. */
+ {
+     TkCanvas *canvasPtr =3D (TkCanvas *) canvas;
+     BufferItem* bufferPtr;
      if ((x1 =3D=3D x2) || (y1 =3D=3D y2)) {
        return;
      }
!     bufferPtr =3D CanvasFindBuffer(canvasPtr,itemPtr);
!     if (bufferPtr) {
!       RectAdd(x1,y1,x2,y2,&bufferPtr->x1,&bufferPtr->y1,
!               &bufferPtr->x2,&bufferPtr->y2);
      } else {
!       RectAdd(x1,y1,x2,y2,&canvasPtr->redrawX1,&canvasPtr->redrawY1,
!               &canvasPtr->redrawX2,&canvasPtr->redrawY2);
!     }
!     if (!(canvasPtr->flags & REDRAW_PENDING)) {
        Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
        canvasPtr->flags |=3D REDRAW_PENDING;
      }
***************
*** 2114,2120 ****
      if (typeList !=3D NULL) {
        return;
      }
!     typeList =3D &tkRectangleType;
      tkRectangleType.nextPtr =3D &tkTextType;
      tkTextType.nextPtr =3D &tkLineType;
      tkLineType.nextPtr =3D &tkPolygonType;
--- 2811,2818 ----
      if (typeList !=3D NULL) {
        return;
      }
!     typeList =3D &tkBufferType;
!     tkBufferType.nextPtr =3D &tkRectangleType;
      tkRectangleType.nextPtr =3D &tkTextType;
      tkTextType.nextPtr =3D &tkLineType;
      tkLineType.nextPtr =3D &tkPolygonType;
***************
*** 2767,2780 ****
      firstMovePtr =3D lastMovePtr =3D NULL;
      for (itemPtr =3D StartTagSearch(canvasPtr, tag, &search);
            itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
        if (itemPtr =3D=3D prevPtr) {
            /*
             * Item after which insertion is to occur is being
!            * moved!  Switch to insert after its predecessor.
             */
  =

            prevPtr =3D search.prevPtr;
        }
        if (search.prevPtr =3D=3D NULL) {
            canvasPtr->firstItemPtr =3D itemPtr->nextPtr;
        } else {
--- 3465,3490 ----
      firstMovePtr =3D lastMovePtr =3D NULL;
      for (itemPtr =3D StartTagSearch(canvasPtr, tag, &search);
            itemPtr !=3D NULL; itemPtr =3D NextItem(&search)) {
+       if (CanvasIsBuffer(itemPtr)) {
+           CanvasEventuallyRedrawBuffer(canvasPtr, itemPtr);
+       } else {
+           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
+       }
+       canvasPtr->flags |=3D REPICK_NEEDED;
+       =

        if (itemPtr =3D=3D prevPtr) {
            /*
             * Item after which insertion is to occur is being
!            * moved!  Switch to insert after its predecessor
!            * -- we passed by already so it won't move.
             */
  =

            prevPtr =3D search.prevPtr;
        }
+       =

+       /*
+        * Remove from list.
+        */
        if (search.prevPtr =3D=3D NULL) {
            canvasPtr->firstItemPtr =3D itemPtr->nextPtr;
        } else {
***************
*** 2783,2797 ****
        if (canvasPtr->lastItemPtr =3D=3D itemPtr) {
            canvasPtr->lastItemPtr =3D search.prevPtr;
        }
        if (firstMovePtr =3D=3D NULL) {
            firstMovePtr =3D itemPtr;
        } else {
            lastMovePtr->nextPtr =3D itemPtr;
        }
        lastMovePtr =3D itemPtr;
-       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr-=

Quote:
>y1,

-               itemPtr->x2, itemPtr->y2);
-       canvasPtr->flags |=3D REPICK_NEEDED;
      }
  =

      /*
--- 3493,3522 ----
        if (canvasPtr->lastItemPtr =3D=3D itemPtr) {
            canvasPtr->lastItemPtr =3D search.prevPtr;
        }
+ =

+       /*
+        * We untie buffer from the list. The prevBufferPtr of the next =

+        * buffer is corrected as well, so if that one is also removed,
+        * the buffer pointers above it get properly set.
+        */     =

+       if (CanvasIsBuffer(itemPtr)) {
+           Tk_Item *item2Ptr;
+           for (item2Ptr =3D itemPtr->nextPtr; =

+                   item2Ptr && item2Ptr->prevBufferPtr =3D=3D itemPtr;
+                   item2Ptr =3D item2Ptr->nextPtr) {
+               item2Ptr->prevBufferPtr =3D itemPtr->prevBufferPtr;
+           } =

+       }
+       =

+       /*
+        * Link into auxiliary list.
+        */
        if (firstMovePtr =3D=3D NULL) {
            firstMovePtr =3D itemPtr;
        } else {
            lastMovePtr->nextPtr =3D itemPtr;
        }
        lastMovePtr =3D itemPtr;
      }
  =

      /*
***************
*** 2812,2817 ****
--- 3537,3577 ----
      if (canvasPtr->lastItemPtr =3D=3D prevPtr) {
        canvasPtr->lastItemPtr =3D lastMovePtr;
      }
+     =

+     /*
+      * Reinvalidate the area to be redrawn, since further buffers
+      * may be affected by a down-move. Regenerate the buffer sequence
+      * properly before invalidating!
+      *
+      * Invalidation is in principle necessary only once, either here =

+      * or above, depending on whether we move up or down. However, we
+      * don't know which direction we moved!
+      */
+     =

+     for (itemPtr =3D firstMovePtr; itemPtr!=3DlastMovePtr->nextPtr; =

+           itemPtr =3D itemPtr->nextPtr) {
+       itemPtr->prevBufferPtr =3D prevPtr;
+       if (itemPtr->prevBufferPtr && !CanvasIsBuffer(itemPtr->prevBufferPtr))=
 {
+           itemPtr->prevBufferPtr =3D itemPtr->prevBufferPtr->prevBufferPtr;
+       }
+       if (CanvasIsBuffer(itemPtr)) {
+           CanvasEventuallyRedrawBuffer(canvasPtr, itemPtr);
+       } else {
+           Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
+       }
+       prevPtr =3D itemPtr;
+     }
+     =

+     /*
+      * Regenerate the buffer sequence properly after the insertion poin=
t.
+      */
+     if (itemPtr && itemPtr->prevBufferPtr !=3D lastMovePtr->prevBufferP=
tr) {
+       for (; itemPtr; itemPtr =3D itemPtr->nextPtr) {
+           itemPtr->prevBufferPtr =3D lastMovePtr->prevBufferPtr;
+           if (CanvasIsBuffer(itemPtr))
+               break;
+       }
+     }
  }
  =0C
  /*
***************
*** 3282,3292 ****
                (ClientData) canvasPtr);
      }
      if (canvasPtr->textInfo.focusItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.focusItemPtr->x1,
!               canvasPtr->textInfo.focusItemPtr->y1,
!               canvasPtr->textInfo.focusItemPtr->x2,
!               canvasPtr->textInfo.focusItemPtr->y2);
      }
  }
  =0C
--- 4042,4049 ----
                (ClientData) canvasPtr);
      }
      if (canvasPtr->textInfo.focusItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.focusItemPtr);
      }
  }
  =0C
***************
*** 3329,3339 ****
        canvasPtr->insertBlinkHandler =3D (Tcl_TimerToken) NULL;
      }
      if (canvasPtr->textInfo.focusItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.focusItemPtr->x1,
!               canvasPtr->textInfo.focusItemPtr->y1,
!               canvasPtr->textInfo.focusItemPtr->x2,
!               canvasPtr->textInfo.focusItemPtr->y2);
      }
      if (canvasPtr->highlightWidth > 0) {
        canvasPtr->flags |=3D REDRAW_BORDERS;
--- 4086,4093 ----
        canvasPtr->insertBlinkHandler =3D (Tcl_TimerToken) NULL;
      }
      if (canvasPtr->textInfo.focusItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.focusItemPtr);
      }
      if (canvasPtr->highlightWidth > 0) {
        canvasPtr->flags |=3D REDRAW_BORDERS;
***************
*** 3383,3393 ****
        Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
                (ClientData) canvasPtr);
      } else if (canvasPtr->textInfo.selItemPtr !=3D itemPtr) {
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.selItemPtr->x1,
!               canvasPtr->textInfo.selItemPtr->y1,
!               canvasPtr->textInfo.selItemPtr->x2,
!               canvasPtr->textInfo.selItemPtr->y2);
      }
      canvasPtr->textInfo.selItemPtr =3D itemPtr;
  =

--- 4137,4144 ----
        Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
                (ClientData) canvasPtr);
      } else if (canvasPtr->textInfo.selItemPtr !=3D itemPtr) {
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.selItemPtr);
      }
      canvasPtr->textInfo.selItemPtr =3D itemPtr;
  =

***************
*** 3405,3412 ****
      if ((canvasPtr->textInfo.selectFirst !=3D oldFirst)
            || (canvasPtr->textInfo.selectLast !=3D oldLast)
            || (itemPtr !=3D oldSelPtr)) {
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
      }
  }
  =0C
--- 4156,4162 ----
      if ((canvasPtr->textInfo.selectFirst !=3D oldFirst)
            || (canvasPtr->textInfo.selectLast !=3D oldLast)
            || (itemPtr !=3D oldSelPtr)) {
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
      }
  }
  =0C
***************
*** 3480,3490 ****
      TkCanvas *canvasPtr =3D (TkCanvas *) clientData;
  =

      if (canvasPtr->textInfo.selItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.selItemPtr->x1,
!               canvasPtr->textInfo.selItemPtr->y1,
!               canvasPtr->textInfo.selItemPtr->x2,
!               canvasPtr->textInfo.selItemPtr->y2);
      }
      canvasPtr->textInfo.selItemPtr =3D NULL;
  }
--- 4230,4237 ----
      TkCanvas *canvasPtr =3D (TkCanvas *) clientData;
  =

      if (canvasPtr->textInfo.selItemPtr !=3D NULL) {
!       Tk_CanvasEventuallyRedrawItem((Tk_Canvas) canvasPtr,
!               canvasPtr->textInfo.selItemPtr);
      }
      canvasPtr->textInfo.selItemPtr =3D NULL;
  }
***************
*** 3777,3791 ****
       * so they can explicitly undisplay themselves.
       */
  =

!     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!           canvasPtr->xOrigin, canvasPtr->yOrigin,
!           canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
!           canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
      canvasPtr->xOrigin =3D xOrigin;
      canvasPtr->yOrigin =3D yOrigin;
      canvasPtr->flags |=3D UPDATE_SCROLLBARS;
!     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
!           canvasPtr->xOrigin, canvasPtr->yOrigin,
!           canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
!           canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
  }
--- 4524,4532 ----
       * so they can explicitly undisplay themselves.
       */
  =

!     CanvasEventuallyRedrawAll(canvasPtr);
      canvasPtr->xOrigin =3D xOrigin;
      canvasPtr->yOrigin =3D yOrigin;
      canvasPtr->flags |=3D UPDATE_SCROLLBARS;
!     CanvasEventuallyRedrawAll(canvasPtr);
  }
diff -rc tk8.0p1.orig/generic/tkCanvas.h tk8.0p1/generic/tkCanvas.h
*** tk8.0p1.orig/generic/tkCanvas.h     Sat Sep 21 00:03:25 1996
--- tk8.0p1/generic/tkCanvas.h  Thu Nov 13 13:47:56 1997
***************
*** 208,213 ****
--- 208,216 ----
                                 * Postscript for the canvas.  NULL means
                                 * no Postscript is currently being
                                 * generated. */
+ =

+     struct BufferItem *firstBufferPtr;        /* First in list of all buffers =
in canvas,
+                                * or NULL if canvas has no buffers at all. */
  } TkCanvas;
  =

  /*

--------------2781446B794B--



Mon, 08 May 2000 03:00:00 GMT  
 
 [ 1 post ] 

 Relevant Pages 

1. New canvas item "buffer"

2. AGAIN: New canvas item "buffer".

3. new "b" buffer output

4. "copy" and drag a canvas item: strange "current" item

5. ANNOUNCE: new "plus"- and "dash"-patches available for Tcl7.5a2/Tk4.1a2

6. How to move a canvas item from C-Code (another new item)

7. string.join(["Tk 4.2p2", "Python 1.4", "Win32", "free"], "for")

8. CD 3.1 "Buffer Overflow" in report

9. Sending text to the "paste buffer"

10. Use of "buffer" type ports

11. NameError on "buffer"?

12. can't read "expect_out(buffer)": no such variable

 

 
Powered by phpBB® Forum Software