Attachment "ttk-image-macos-fixes.diff" to
ticket [7caf9e9e]
added by
mtmcp_
2026-05-31 14:05:49.
Index: generic/ttk/ttkImage.c
==================================================================
--- generic/ttk/ttkImage.c
+++ generic/ttk/ttkImage.c
@@ -274,26 +274,32 @@
#ifdef TILE_07_COMPAT
Ttk_ResourceCache cache; /* Resource cache for images */
Ttk_StateMap imageMap; /* State-based lookup table for images */
#endif
+#ifndef TK_NO_DOUBLE_BUFFERING
Pixmap cachedPixmap; /* Cached composed element, or None */
int cachedWidth; /* Width of cached pixmap */
int cachedHeight; /* Height of cached pixmap */
int cachedX; /* X position of cached render */
int cachedY; /* Y position of cached render */
Ttk_State cachedState; /* State at which pixmap was rendered */
Display *cachedDisplay; /* Display owning cachedPixmap */
+#endif
} ImageData;
+#ifndef TK_NO_DOUBLE_BUFFERING
static void InvalidateImageCache(ImageData *imageData)
{
if (imageData->cachedPixmap != None) {
Tk_FreePixmap(imageData->cachedDisplay, imageData->cachedPixmap);
imageData->cachedPixmap = None;
imageData->cachedWidth = 0;
imageData->cachedHeight = 0;
+ imageData->cachedX = 0;
+ imageData->cachedY = 0;
+ imageData->cachedState = 0;
}
}
static void ImageElementImageChanged(
void *clientData,
@@ -305,15 +311,18 @@
TCL_UNUSED(int))
{
ImageData *imageData = (ImageData *)clientData;
InvalidateImageCache(imageData);
}
+#endif /* !TK_NO_DOUBLE_BUFFERING */
static void FreeImageData(void *clientData)
{
ImageData *imageData = (ImageData *)clientData;
+#ifndef TK_NO_DOUBLE_BUFFERING
InvalidateImageCache(imageData);
+#endif
if (imageData->imageSpec) { TtkFreeImageSpec(imageData->imageSpec); }
#ifdef TILE_07_COMPAT
if (imageData->imageMap) { Tcl_DecrRefCount(imageData->imageMap); }
#endif
Tcl_Free(clientData);
@@ -377,11 +386,19 @@
Tk_SizeOfImage(image, &imgWidth, &imgHeight);
src = Ttk_MakeBox(0, 0, imgWidth, imgHeight);
dst = Ttk_StickBox(b, imgWidth, imgHeight, imageData->sticky);
- /* Fast path: blit cached pixmap if size, position, and state match. */
+#ifndef TK_NO_DOUBLE_BUFFERING
+ /*
+ * Element pixmap cache. Compiled in only where XCopyArea accepts a
+ * Pixmap; on macOS it returns BadDrawable for a Pixmap source or
+ * destination, so the copies below would draw nothing and that platform
+ * falls through to the direct draw.
+ */
+
+ /* Fast path: copy cached pixmap if size, position, and state match. */
if (imageData->cachedPixmap != None
&& imageData->cachedWidth == dst.width
&& imageData->cachedHeight == dst.height
&& imageData->cachedX == dst.x
&& imageData->cachedY == dst.y
@@ -432,20 +449,21 @@
imageData->cachedX = dst.x;
imageData->cachedY = dst.y;
imageData->cachedState = state;
imageData->cachedDisplay = display;
- /* Blit composited result to destination. */
+ /* Copy composited result to destination. */
XCopyArea(display, pixmap, d, gc,
0, 0, (unsigned)dst.width, (unsigned)dst.height,
dst.x, dst.y);
Tk_FreeGC(display, gc);
return;
}
}
+#endif /* !TK_NO_DOUBLE_BUFFERING */
- /* Fallback: window not realized or pixmap alloc failed. */
+ /* Direct draw: cache disabled, window not realized, or alloc failed. */
Ttk_Tile(tkwin, d, image, src, dst, imageData->border);
}
static const Ttk_ElementSpec ImageElementSpec =
{
@@ -481,18 +499,22 @@
"Must supply a base image", -1));
Tcl_SetErrorCode(interp, "TTK", "IMAGE", "BASE", (char *)NULL);
return TCL_ERROR;
}
- imageData = (ImageData *)ckalloc(sizeof(*imageData));
+ imageData = (ImageData *)Tcl_Alloc(sizeof(*imageData));
memset(imageData, 0, sizeof(*imageData));
- imageData->cachedPixmap = None;
+#ifndef TK_NO_DOUBLE_BUFFERING
+ imageData->cachedPixmap = None;
imageSpec = TtkGetImageSpecEx(interp, Tk_MainWindow(interp), objv[0],
ImageElementImageChanged, imageData);
+#else
+ imageSpec = TtkGetImageSpec(interp, Tk_MainWindow(interp), objv[0]);
+#endif
if (!imageSpec) {
- ckfree(imageData);
+ Tcl_Free(imageData);
return TCL_ERROR;
}
imageData->imageSpec = imageSpec;
imageData->minWidth = imageData->minHeight = -1;