Tk Source Code

Check-in [86db63ba]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add double buffering to frames and toplevels.

Theoretically only needed when drawing background with images, but simpler to do always. Incidentally fixes minor bug in labelframes with redrawing of focus rings, but nobody really used those on labelframes so it was never reported...

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tip-262
Files: files | file ages | folders
SHA3-256: 86db63badc83fbf4052faee929a92942d48e8d0dc5a705a7ed7ac63e64b91aa7
User & Date: dkf 2019-05-17 20:06:39
Original Comment: Add double buffering to frames and toplevels. Theoretically only needed when drawing backgrounds, but simpler to do always.
Context
2019-05-17
20:37
Ugh; misread the code. The highlight ring is drawn first and always on the real window. Because of backgroundless frames. check-in: 0807e606 user: dkf tags: tip-262
20:06
Add double buffering to frames and toplevels.

Theoretically only needed when drawing background with images, but simpler to do always. Incidentally fixes minor bug in labelframes with redrawing of focus rings, but nobody really used those on labelframes so it was never reported... check-in: 86db63ba user: dkf tags: tip-262

2019-05-16
22:22
Fix some tests. Add some test cases. check-in: 42f90406 user: dkf tags: tip-262
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to generic/tkFrame.c.

    97     97       Tcl_Obj *bgimgPtr;		/* Value of -backgroundimage option: specifies
    98     98   				 * image to display on window's background, or
    99     99   				 * NULL if none. */
   100    100       Tk_Image bgimg;		/* Derived from bgimgPtr by calling
   101    101   				 * Tk_GetImage, or NULL if bgimgPtr is
   102    102   				 * NULL. */
   103    103       int tile;			/* Whether to tile the bgimg. */
          104  +#ifndef TK_NO_DOUBLE_BUFFERING
          105  +    GC copyGC;			/* GC for copying when double-buffering. */
          106  +#endif /* TK_NO_DOUBLE_BUFFERING */
   104    107   } Frame;
   105    108   
   106    109   /*
   107    110    * A data structure of the following type is kept for each labelframe widget
   108    111    * managed by this file:
   109    112    */
   110    113   
................................................................................
   328    331   			    int objc, Tcl_Obj *const objv[]);
   329    332   static int		CreateFrame(ClientData clientData, Tcl_Interp *interp,
   330    333   			    int objc, Tcl_Obj *const argv[],
   331    334   			    enum FrameType type, const char *appName);
   332    335   static void		DestroyFrame(void *memPtr);
   333    336   static void		DestroyFramePartly(Frame *framePtr);
   334    337   static void		DisplayFrame(ClientData clientData);
   335         -static void		DrawFrameBackground(Tk_Window tkwin,
          338  +static void		DrawFrameBackground(Tk_Window tkwin, Pixmap pixmap,
   336    339   			    int highlightWidth, int borderWidth,
   337    340   			    Tk_Image bgimg, int bgtile);
   338    341   static void		FrameBgImageProc(ClientData clientData,
   339    342   			    int x, int y, int width, int height,
   340    343   			    int imgWidth, int imgHeight);
   341    344   static void		FrameCmdDeletedProc(ClientData clientData);
   342    345   static void		FrameEventProc(ClientData clientData,
................................................................................
   893    896   
   894    897       if (framePtr->type == TYPE_LABELFRAME) {
   895    898   	Tk_FreeTextLayout(labelframePtr->textLayout);
   896    899   	if (labelframePtr->textGC != NULL) {
   897    900   	    Tk_FreeGC(framePtr->display, labelframePtr->textGC);
   898    901   	}
   899    902       }
          903  +#ifndef TK_NO_DOUBLE_BUFFERING
          904  +    if (framePtr->copyGC != NULL) {
          905  +	Tk_FreeGC(framePtr->display, framePtr->copyGC);
          906  +    }
          907  +#endif /* TK_NO_DOUBLE_BUFFERING */
   900    908       if (framePtr->colormap != None) {
   901    909   	Tk_FreeColormap(framePtr->display, framePtr->colormap);
   902    910       }
   903    911       if (framePtr->bgimg) {
   904    912   	Tk_FreeImage(framePtr->bgimg);
   905    913       }
   906    914       ckfree(framePtr);
................................................................................
  1152   1160   
  1153   1161       anyTextLabel = (framePtr->type == TYPE_LABELFRAME) &&
  1154   1162   	    (labelframePtr->textPtr != NULL) &&
  1155   1163   	    (labelframePtr->labelWin == NULL);
  1156   1164       anyWindowLabel = (framePtr->type == TYPE_LABELFRAME) &&
  1157   1165   	    (labelframePtr->labelWin != NULL);
  1158   1166   
         1167  +#ifndef TK_NO_DOUBLE_BUFFERING
         1168  +    gcValues.graphics_exposures = False;
         1169  +    gc = Tk_GetGC(tkwin, GCGraphicsExposures, &gcValues);
         1170  +    if (framePtr->copyGC != NULL) {
         1171  +	Tk_FreeGC(framePtr->display, framePtr->copyGC);
         1172  +    }
         1173  +    framePtr->copyGC = gc;
         1174  +#endif /* TK_NO_DOUBLE_BUFFERING */
         1175  +
  1159   1176       if (framePtr->type == TYPE_LABELFRAME) {
  1160   1177   	/*
  1161   1178   	 * The textGC is needed even in the labelWin case, so it's always
  1162   1179   	 * created for a labelframe.
  1163   1180   	 */
  1164   1181   
  1165   1182   	gcValues.font = Tk_FontId(labelframePtr->tkfont);
................................................................................
  1496   1513        * If -background is set to "", no interior is drawn.
  1497   1514        */
  1498   1515   
  1499   1516       if (framePtr->border == NULL) {
  1500   1517   	return;
  1501   1518       }
  1502   1519   
         1520  +#ifndef TK_NO_DOUBLE_BUFFERING
         1521  +    /*
         1522  +     * In order to avoid screen flashes, this function redraws the frame into
         1523  +     * off-screen memory, then copies it back on-screen in a single operation.
         1524  +     * This means there's no point in time where the on-screen image has been
         1525  +     * cleared.
         1526  +     */
         1527  +
         1528  +    pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin),
         1529  +	    Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
         1530  +#else
         1531  +    pixmap = Tk_WindowId(tkwin);
         1532  +#endif /* TK_NO_DOUBLE_BUFFERING */
         1533  +
  1503   1534       if (framePtr->type != TYPE_LABELFRAME) {
  1504   1535   	/*
  1505   1536   	 * Pass to platform specific draw function. In general, it just draws
  1506   1537   	 * a simple rectangle, but it may "theme" the background.
  1507   1538   	 */
  1508   1539   
  1509   1540       noLabel:
  1510         -	TkpDrawFrame(tkwin, framePtr->border, hlWidth,
         1541  +	TkpDrawFrameEx(tkwin, pixmap, framePtr->border, hlWidth,
  1511   1542   		framePtr->borderWidth, framePtr->relief);
  1512   1543   	if (framePtr->bgimg) {
  1513         -	    DrawFrameBackground(tkwin, hlWidth, framePtr->borderWidth,
         1544  +	    DrawFrameBackground(tkwin, pixmap, hlWidth, framePtr->borderWidth,
  1514   1545   		    framePtr->bgimg, framePtr->tile);
  1515   1546   	}
  1516   1547       } else {
  1517   1548   	Labelframe *labelframePtr = (Labelframe *) framePtr;
  1518   1549   
  1519   1550   	if ((labelframePtr->textPtr == NULL) &&
  1520   1551   		(labelframePtr->labelWin == NULL)) {
  1521   1552   	    goto noLabel;
  1522   1553   	}
  1523   1554   
  1524         -#ifndef TK_NO_DOUBLE_BUFFERING
  1525         -	/*
  1526         -	 * In order to avoid screen flashes, this function redraws the frame
  1527         -	 * into off-screen memory, then copies it back on-screen in a single
  1528         -	 * operation. This means there's no point in time where the on-screen
  1529         -	 * image has been cleared.
  1530         -	 */
  1531         -
  1532         -	pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin),
  1533         -		Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  1534         -#else
  1535         -	pixmap = Tk_WindowId(tkwin);
  1536         -#endif /* TK_NO_DOUBLE_BUFFERING */
  1537         -
  1538   1555   	/*
  1539   1556   	 * Clear the pixmap.
  1540   1557   	 */
  1541   1558   
  1542   1559   	Tk_Fill3DRectangle(tkwin, pixmap, framePtr->border, 0, 0,
  1543   1560   		Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  1544   1561   
................................................................................
  1642   1659   	    } else {
  1643   1660   		Tk_MaintainGeometry(labelframePtr->labelWin, framePtr->tkwin,
  1644   1661   			labelframePtr->labelBox.x, labelframePtr->labelBox.y,
  1645   1662   			labelframePtr->labelBox.width,
  1646   1663   			labelframePtr->labelBox.height);
  1647   1664   	    }
  1648   1665   	}
         1666  +    }
  1649   1667   
  1650   1668   #ifndef TK_NO_DOUBLE_BUFFERING
  1651         -	/*
  1652         -	 * Everything's been redisplayed; now copy the pixmap onto the screen
  1653         -	 * and free up the pixmap.
  1654         -	 */
         1669  +    /*
         1670  +     * Everything's been redisplayed; now copy the pixmap onto the screen and
         1671  +     * free up the pixmap.
         1672  +     */
  1655   1673   
  1656         -	XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin),
  1657         -		labelframePtr->textGC, hlWidth, hlWidth,
  1658         -		(unsigned) (Tk_Width(tkwin) - 2 * hlWidth),
  1659         -		(unsigned) (Tk_Height(tkwin) - 2 * hlWidth),
  1660         -		hlWidth, hlWidth);
  1661         -	Tk_FreePixmap(framePtr->display, pixmap);
         1674  +    XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), framePtr->copyGC,
         1675  +	    0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
         1676  +	    0, 0);
         1677  +    Tk_FreePixmap(framePtr->display, pixmap);
  1662   1678   #endif /* TK_NO_DOUBLE_BUFFERING */
  1663         -    }
         1679  +}
         1680  +
         1681  +/*
         1682  + *----------------------------------------------------------------------
         1683  + *
         1684  + * TkpDrawFrame --
         1685  + *
         1686  + *	This procedure draws the rectangular frame area.
         1687  + *
         1688  + * Results:
         1689  + *	None.
         1690  + *
         1691  + * Side effects:
         1692  + *	Draws inside the tkwin area.
         1693  + *
         1694  + *----------------------------------------------------------------------
         1695  + */
  1664   1696   
         1697  +void
         1698  +TkpDrawFrame(
         1699  +    Tk_Window tkwin,
         1700  +    Tk_3DBorder border,
         1701  +    int highlightWidth,
         1702  +    int borderWidth,
         1703  +    int relief)
         1704  +{
         1705  +    /*
         1706  +     * Legacy shim to allow for external callers. Internal ones use
         1707  +     * non-exposed TkpDrawFrameEx directly so they can use double-buffering.
         1708  +     */
         1709  +
         1710  +    TkpDrawFrameEx(tkwin, Tk_WindowId(tkwin), border,
         1711  +	    highlightWidth, borderWidth, relief);
  1665   1712   }
  1666   1713   
  1667   1714   /*
  1668   1715    *--------------------------------------------------------------
  1669   1716    *
  1670   1717    * FrameEventProc --
  1671   1718    *
................................................................................
  2135   2182    *
  2136   2183    *----------------------------------------------------------------------
  2137   2184    */
  2138   2185   
  2139   2186   static void
  2140   2187   DrawFrameBackground(
  2141   2188       Tk_Window tkwin,
         2189  +    Pixmap pixmap,
  2142   2190       int highlightWidth,
  2143   2191       int borderWidth,
  2144   2192       Tk_Image bgimg,
  2145   2193       int bgtile)
  2146   2194   {
  2147   2195       int width, height;			/* Area to paint on. */
  2148   2196       int imageWidth, imageHeight;	/* Dimensions of image. */
................................................................................
  2165   2213   		w = (width + bw) - x;
  2166   2214   	    }
  2167   2215   	    for (y = bw; y < height + bw; y += imageHeight) {
  2168   2216   		int h = imageHeight;
  2169   2217   		if (y - bw + imageHeight > height) {
  2170   2218   		    h = (height + bw) - y;
  2171   2219   		}
  2172         -		Tk_RedrawImage(bgimg, 0, 0, w, h, Tk_WindowId(tkwin), x, y);
         2220  +		Tk_RedrawImage(bgimg, 0, 0, w, h, pixmap, x, y);
  2173   2221   	    }
  2174   2222   	}
  2175   2223       } else {
  2176   2224   	/*
  2177   2225   	 * Draw the image centred in the widget (inside the border).
  2178   2226   	 */
  2179   2227   
................................................................................
  2193   2241   	    yOff = (Tk_Height(tkwin) - imageHeight) / 2;
  2194   2242   	    h = imageHeight;
  2195   2243   	} else {
  2196   2244   	    y = (imageHeight - height) / 2;
  2197   2245   	    yOff = bw;
  2198   2246   	    h = height;
  2199   2247   	}
  2200         -	Tk_RedrawImage(bgimg, x, y, w, h, Tk_WindowId(tkwin), xOff, yOff);
         2248  +	Tk_RedrawImage(bgimg, x, y, w, h, pixmap, xOff, yOff);
  2201   2249       }
  2202   2250   }
  2203   2251   
  2204   2252   /*
  2205   2253    * Local Variables:
  2206   2254    * mode: c
  2207   2255    * c-basic-offset: 4
  2208   2256    * fill-column: 78
  2209   2257    * End:
  2210   2258    */

Changes to generic/tkInt.h.

  1239   1239   			    int *lengthPtr);
  1240   1240   MODULE_SCOPE void	TkUnderlineCharsInContext(Display *display,
  1241   1241   			    Drawable drawable, GC gc, Tk_Font tkfont,
  1242   1242   			    const char *string, int numBytes, int x, int y,
  1243   1243   			    int firstByte, int lastByte);
  1244   1244   MODULE_SCOPE void	TkpGetFontAttrsForChar(Tk_Window tkwin, Tk_Font tkfont,
  1245   1245   			    int c, struct TkFontAttributes *faPtr);
         1246  +MODULE_SCOPE void	TkpDrawFrameEx(Tk_Window tkwin, Drawable drawable,
         1247  +			    Tk_3DBorder border, int highlightWidth,
         1248  +			    int borderWidth, int relief);
  1246   1249   MODULE_SCOPE Tcl_Obj *	TkNewWindowObj(Tk_Window tkwin);
  1247   1250   MODULE_SCOPE void	TkpShowBusyWindow(TkBusy busy);
  1248   1251   MODULE_SCOPE void	TkpHideBusyWindow(TkBusy busy);
  1249   1252   MODULE_SCOPE void	TkpMakeTransparentWindowExist(Tk_Window tkwin,
  1250   1253   			    Window parent);
  1251   1254   MODULE_SCOPE void	TkpCreateBusy(Tk_FakeWin *winPtr, Tk_Window tkRef,
  1252   1255   			    Window *parentPtr, Tk_Window tkParent,

Changes to macosx/tkMacOSXDraw.c.

  2023   2023   	}
  2024   2024       }
  2025   2025   }
  2026   2026   
  2027   2027   /*
  2028   2028    *----------------------------------------------------------------------
  2029   2029    *
  2030         - * TkpDrawFrame --
         2030  + * TkpDrawFrameEx --
  2031   2031    *
  2032   2032    *	This procedure draws the rectangular frame area. If the user has
  2033   2033    *	requested themeing, it draws with the background theme.
  2034   2034    *
  2035   2035    * Results:
  2036   2036    *	None.
  2037   2037    *
................................................................................
  2038   2038    * Side effects:
  2039   2039    *	Draws inside the tkwin area.
  2040   2040    *
  2041   2041    *----------------------------------------------------------------------
  2042   2042    */
  2043   2043   
  2044   2044   void
  2045         -TkpDrawFrame(
         2045  +TkpDrawFrameEx(
  2046   2046       Tk_Window tkwin,
         2047  +    Drawable drawable,
  2047   2048       Tk_3DBorder border,
  2048   2049       int highlightWidth,
  2049   2050       int borderWidth,
  2050   2051       int relief)
  2051   2052   {
  2052   2053       if (useThemedToplevel && Tk_IsTopLevel(tkwin)) {
  2053   2054   	static Tk_3DBorder themedBorder = NULL;
................................................................................
  2057   2058   		    "systemWindowHeaderBackground");
  2058   2059   	}
  2059   2060   	if (themedBorder) {
  2060   2061   	    border = themedBorder;
  2061   2062   	}
  2062   2063       }
  2063   2064   
  2064         -    Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
  2065         -	    border, highlightWidth, highlightWidth,
  2066         -	    Tk_Width(tkwin) - 2 * highlightWidth,
  2067         -	    Tk_Height(tkwin) - 2 * highlightWidth,
  2068         -	    borderWidth, relief);
         2065  +    Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth,
         2066  +	    highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth,
         2067  +	    Tk_Height(tkwin) - 2 * highlightWidth, borderWidth, relief);
  2069   2068   }
  2070   2069   
  2071   2070   /*
  2072   2071    * Local Variables:
  2073   2072    * mode: objc
  2074   2073    * c-basic-offset: 4
  2075   2074    * fill-column: 79
  2076   2075    * coding: utf-8
  2077   2076    * End:
  2078   2077    */

Changes to unix/tkUnixDraw.c.

   204    204   {
   205    205       TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0);
   206    206   }
   207    207   
   208    208   /*
   209    209    *----------------------------------------------------------------------
   210    210    *
   211         - * TkpDrawFrame --
          211  + * TkpDrawFrameEx --
   212    212    *
   213    213    *	This function draws the rectangular frame area.
   214    214    *
   215    215    * Results:
   216    216    *	None.
   217    217    *
   218    218    * Side effects:
   219    219    *	Draws inside the tkwin area.
   220    220    *
   221    221    *----------------------------------------------------------------------
   222    222    */
   223    223   
   224    224   void
   225         -TkpDrawFrame(
          225  +TkpDrawFrameEx(
   226    226       Tk_Window tkwin,
          227  +    Drawable drawable,
   227    228       Tk_3DBorder border,
   228    229       int highlightWidth,
   229    230       int borderWidth,
   230    231       int relief)
   231    232   {
   232         -    Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth,
          233  +    Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth,
   233    234   	    highlightWidth, Tk_Width(tkwin) - 2*highlightWidth,
   234    235   	    Tk_Height(tkwin) - 2*highlightWidth, borderWidth, relief);
   235    236   }
   236    237   
   237    238   /*
   238    239    * Local Variables:
   239    240    * mode: c
   240    241    * c-basic-offset: 4
   241    242    * fill-column: 78
   242    243    * End:
   243    244    */

Changes to win/tkWinDraw.c.

  1491   1491   {
  1492   1492       TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0);
  1493   1493   }
  1494   1494   
  1495   1495   /*
  1496   1496    *----------------------------------------------------------------------
  1497   1497    *
  1498         - * TkpDrawFrame --
         1498  + * TkpDrawFrameEx --
  1499   1499    *
  1500   1500    *	This function draws the rectangular frame area.
  1501   1501    *
  1502   1502    * Results:
  1503   1503    *	None.
  1504   1504    *
  1505   1505    * Side effects:
  1506   1506    *	Draws inside the tkwin area.
  1507   1507    *
  1508   1508    *----------------------------------------------------------------------
  1509   1509    */
  1510   1510   
  1511   1511   void
  1512         -TkpDrawFrame(
         1512  +TkpDrawFrameEx(
  1513   1513       Tk_Window tkwin,
         1514  +    Drawable drawable,
  1514   1515       Tk_3DBorder border,
  1515   1516       int highlightWidth,
  1516   1517       int borderWidth,
  1517   1518       int relief)
  1518   1519   {
  1519         -    Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth,
         1520  +    Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth,
  1520   1521   	    highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth,
  1521   1522   	    Tk_Height(tkwin) - 2 * highlightWidth, borderWidth, relief);
  1522   1523   }
  1523   1524   
  1524   1525   /*
  1525   1526    * Local Variables:
  1526   1527    * mode: c
  1527   1528    * c-basic-offset: 4
  1528   1529    * fill-column: 78
  1529   1530    * End:
  1530   1531    */