Tk Source Code

Artifact [b5fa176b]
Login

Artifact b5fa176b8dd89c8db30ade95f29e4168bb6d0184b5b8f0009ef1c07cf8ff1705:

Attachment "ttk-image-macos-fixes.diff" to ticket [7caf9e9e] added by mtmcp_ 2026-05-31 14:05:49. (unpublished)
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;