Check-in [ccc996aeff]
Not logged in

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

Overview
Comment:fixes in ttk image management
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ccc996aeffde47f86118ac2675d875ebafdce586
User & Date: chw 2023-12-05 05:11:44
Context
2023-12-05
08:20
add tcllib upstream changes check-in: 9ebda53167 user: chw tags: trunk
05:11
fixes in ttk image management check-in: ccc996aeff user: chw tags: trunk
2023-12-03
14:14
another fix in file dialog check-in: c8e18fbcdc user: chw tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to jni/sdl2tk/generic/tkImage.c.

79
80
81
82
83
84
85



86
87
88
89
90
91
92

/*
 * Prototypes for local functions:
 */

static void		ImageTypeThreadExitProc(ClientData clientData);
static void		DeleteImage(char *blockPtr);



static void		EventuallyDeleteImage(ImageModel *modelPtr,
			    int forgetImageHashNow);

/*
 *----------------------------------------------------------------------
 *
 * ImageTypeThreadExitProc --







>
>
>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

/*
 * Prototypes for local functions:
 */

static void		ImageTypeThreadExitProc(ClientData clientData);
static void		DeleteImage(char *blockPtr);
static void		NullChangeProc(ClientData clientData, int x, int y,
			    int width, int height,
			    int imageWidth, int imageHeight);
static void		EventuallyDeleteImage(ImageModel *modelPtr,
			    int forgetImageHashNow);

/*
 *----------------------------------------------------------------------
 *
 * ImageTypeThreadExitProc --
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
	     * Need to check if the _command_ that we are about to create is
	     * the name of the current model widget command (normally "." but
	     * could have been renamed) and fail in that case before a really
	     * nasty and hard to stop crash happens.
	     */

	    topWin = (TkWindow *) TkToplevelWindowForCommand(interp, name);
	    if (topWin != NULL && winPtr->mainPtr->winPtr == topWin) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"images may not be named the same as the main window",
			-1));
		Tcl_SetErrorCode(interp, "TK", "IMAGE", "SMASH_MAIN", NULL);
		return TCL_ERROR;
	    }
	}







|







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
	     * Need to check if the _command_ that we are about to create is
	     * the name of the current model widget command (normally "." but
	     * could have been renamed) and fail in that case before a really
	     * nasty and hard to stop crash happens.
	     */

	    topWin = (TkWindow *) TkToplevelWindowForCommand(interp, name);
	    if ((topWin != NULL) && (winPtr->mainPtr->winPtr == topWin)) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"images may not be named the same as the main window",
			-1));
		Tcl_SetErrorCode(interp, "TK", "IMAGE", "SMASH_MAIN", NULL);
		return TCL_ERROR;
	    }
	}
721
722
723
724
725
726
727





















































































728
729
730
731
732
733
734
    if (interp) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"image \"%s\" doesn't exist", name));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "IMAGE", name, NULL);
    }
    return NULL;
}






















































































/*
 *----------------------------------------------------------------------
 *
 * Tk_FreeImage --
 *
 *	This function is invoked by a widget when it no longer needs an image







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
    if (interp) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"image \"%s\" doesn't exist", name));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "IMAGE", name, NULL);
    }
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * TkImageForWindow --
 *
 *	This function is invoked to retrieve an image for a particular
 *	window.
 *
 * Results:
 *	The return value is a token for the image. This is allocated
 *	when the input image does not already refer to the window, so
 *	the caller must test for the result being equal with the input
 *	image in order to decide if a Tk_FreeImage() is required.
 *
 * Side effects:
 *	See Tk_GetImage().
 *
 *----------------------------------------------------------------------
 */

Tk_Image
TkImageForWindow(
    Tk_Image image,		/* The input image. */
    Tk_Window tkwin)		/* Token for window in which image will be
				 * used. */
{
    Image *imagePtr = (Image *) image;
    ImageModel *modelPtr = imagePtr->modelPtr;

    if (imagePtr->tkwin == tkwin) {
	return image;
    }
    if (modelPtr->typePtr == NULL) {
	return NULL;
    }
    if (modelPtr->deleted) {
	return NULL;
    }
    imagePtr = (Image *) ckalloc(sizeof(Image));
    imagePtr->tkwin = tkwin;
    imagePtr->display = Tk_Display(tkwin);
    imagePtr->modelPtr = modelPtr;
    imagePtr->instanceData =
	    modelPtr->typePtr->getProc(tkwin, modelPtr->modelData);
    imagePtr->changeProc = NullChangeProc;
    imagePtr->widgetClientData = NULL;
    imagePtr->nextPtr = modelPtr->instancePtr;
    modelPtr->instancePtr = imagePtr;
    return (Tk_Image) imagePtr;
}

static void
NullChangeProc(ClientData clientData, int x, int y, int width, int height,
    int imageWidth, int imageHeight)
{
}

/*
 *----------------------------------------------------------------------
 *
 * TkImageEqual --
 *
 *	Are two images equal, i.e. referring to the same model?
 *
 * Results:
 *	True or false.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TkImageEqual(Tk_Image image1, Tk_Image image2)
{
    Image *image1Ptr = (Image *) image1;
    Image *image2Ptr = (Image *) image2;

    if ((image1Ptr != NULL) && (image2Ptr != NULL)) {
	return (image1Ptr->modelPtr == image2Ptr->modelPtr);
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_FreeImage --
 *
 *	This function is invoked by a widget when it no longer needs an image

Changes to jni/sdl2tk/generic/tkInt.h.

1293
1294
1295
1296
1297
1298
1299



1300
1301
1302
1303
1304
1305
1306
MODULE_SCOPE int	TkInitFontchooser(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE void	TkpWarpPointer(TkDisplay *dispPtr);
MODULE_SCOPE void	TkpCancelWarp(TkDisplay *dispPtr);
MODULE_SCOPE int	TkListCreateFrame(ClientData clientData,
			    Tcl_Interp *interp, Tcl_Obj *listObj,
			    int toplevel, Tcl_Obj *nameObj);



#ifdef PLATFORM_SDL
MODULE_SCOPE int	TkInitSdltkCmd(Tcl_Interp *interp,
			    ClientData clientData);
#endif

#if defined(_WIN32) && !defined(PLATFORM_SDL)
#define TkParseColor XParseColor







>
>
>







1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
MODULE_SCOPE int	TkInitFontchooser(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE void	TkpWarpPointer(TkDisplay *dispPtr);
MODULE_SCOPE void	TkpCancelWarp(TkDisplay *dispPtr);
MODULE_SCOPE int	TkListCreateFrame(ClientData clientData,
			    Tcl_Interp *interp, Tcl_Obj *listObj,
			    int toplevel, Tcl_Obj *nameObj);
MODULE_SCOPE Tk_Image	TkImageForWindow(Tk_Image image, Tk_Window tkwin);
MODULE_SCOPE int	TkImageEqual(Tk_Image image1, Tk_Image image2);

#ifdef PLATFORM_SDL
MODULE_SCOPE int	TkInitSdltkCmd(Tcl_Interp *interp,
			    ClientData clientData);
#endif

#if defined(_WIN32) && !defined(PLATFORM_SDL)
#define TkParseColor XParseColor

Changes to jni/sdl2tk/generic/ttk/ttkImage.c.

11
12
13
14
15
16
17











18
19
20
21
22
23
24
25
26
27
28
29



30
31
32
33
34
35
36
 */

#include "tkInt.h"
#include "ttkTheme.h"

#undef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))












/*------------------------------------------------------------------------
 * +++ ImageSpec management.
 */

struct TtkImageSpec {
    Tk_Image 		baseImage;	/* Base image to use */
    int 		mapCount;	/* #state-specific overrides */
    Ttk_StateSpec	*states;	/* array[mapCount] of states ... */
    Tk_Image		*images;	/* ... per-state images to use */
    Tk_ImageChangedProc *imageChanged;
    ClientData		imageChangedClientData;



};

/* NullImageChanged --
 * 	Do-nothing Tk_ImageChangedProc.
 */
static void NullImageChanged(ClientData clientData,
    int x, int y, int width, int height, int imageWidth, int imageHeight)







>
>
>
>
>
>
>
>
>
>
>












>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 */

#include "tkInt.h"
#include "ttkTheme.h"

#undef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))

#if defined(PLATFORM_SDL) || defined(_WIN32) || defined(MAC_OSX_TK)
#   define NEED_EXTRA_INFO 0
#else
    /*
     * Images are to be managed per Tk_Window to take the Display
     * into account.
     */
#   define NEED_EXTRA_INFO 1
#endif


/*------------------------------------------------------------------------
 * +++ ImageSpec management.
 */

struct TtkImageSpec {
    Tk_Image 		baseImage;	/* Base image to use */
    int 		mapCount;	/* #state-specific overrides */
    Ttk_StateSpec	*states;	/* array[mapCount] of states ... */
    Tk_Image		*images;	/* ... per-state images to use */
    Tk_ImageChangedProc *imageChanged;
    ClientData		imageChangedClientData;
#if NEED_EXTRA_INFO
    Tk_Image 		useImage;
#endif
};

/* NullImageChanged --
 * 	Do-nothing Tk_ImageChangedProc.
 */
static void NullImageChanged(ClientData clientData,
    int x, int y, int width, int height, int imageWidth, int imageHeight)
78
79
80
81
82
83
84



85
86
87
88
89
90
91
    imageSpec = ckalloc(sizeof(*imageSpec));
    imageSpec->baseImage = 0;
    imageSpec->mapCount = 0;
    imageSpec->states = 0;
    imageSpec->images = 0;
    imageSpec->imageChanged = imageChangedProc;
    imageSpec->imageChangedClientData = imageChangedClientData;




    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
	goto error;
    }

    if ((objc % 2) != 1) {
	if (interp) {







>
>
>







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    imageSpec = ckalloc(sizeof(*imageSpec));
    imageSpec->baseImage = 0;
    imageSpec->mapCount = 0;
    imageSpec->states = 0;
    imageSpec->images = 0;
    imageSpec->imageChanged = imageChangedProc;
    imageSpec->imageChangedClientData = imageChangedClientData;
#if NEED_EXTRA_INFO
    imageSpec->useImage = 0;
#endif

    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
	goto error;
    }

    if ((objc % 2) != 1) {
	if (interp) {
146
147
148
149
150
151
152



153
154
155
156
157
158
159
160

161




162
163
164
165

166
167

168
















169
170
171
172
173
174
175
    for (i=0; i < imageSpec->mapCount; ++i) {
	Tk_FreeImage(imageSpec->images[i]);
    }

    if (imageSpec->baseImage) { Tk_FreeImage(imageSpec->baseImage); }
    if (imageSpec->states) { ckfree(imageSpec->states); }
    if (imageSpec->images) { ckfree(imageSpec->images); }




    ckfree(imageSpec);
}

/* TtkSelectImage --
 * 	Return a state-specific image from an ImageSpec
 */
Tk_Image TtkSelectImage(Ttk_ImageSpec *imageSpec, Ttk_State state)

{




    int i;
    for (i = 0; i < imageSpec->mapCount; ++i) {
	if (Ttk_StateMatches(state, imageSpec->states+i)) {
	    return imageSpec->images[i];

	}
    }

    return imageSpec->baseImage;
















}

/*------------------------------------------------------------------------
 * +++ Drawing utilities.
 */

/* LPadding, CPadding, RPadding --







>
>
>







|
>

>
>
>
>



|
>


>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    for (i=0; i < imageSpec->mapCount; ++i) {
	Tk_FreeImage(imageSpec->images[i]);
    }

    if (imageSpec->baseImage) { Tk_FreeImage(imageSpec->baseImage); }
    if (imageSpec->states) { ckfree(imageSpec->states); }
    if (imageSpec->images) { ckfree(imageSpec->images); }
#if NEED_EXTRA_INFO
    if (imageSpec->useImage) { Tk_FreeImage(imageSpec->useImage); }
#endif

    ckfree(imageSpec);
}

/* TtkSelectImage --
 * 	Return a state-specific image from an ImageSpec
 */
Tk_Image TtkSelectImage(Ttk_ImageSpec *imageSpec, Tk_Window tkwin,
    Ttk_State state)
{
    Tk_Image result = 0;
#if NEED_EXTRA_INFO
    Tk_Image image;
#endif
    int i;
    for (i = 0; i < imageSpec->mapCount; ++i) {
	if (Ttk_StateMatches(state, imageSpec->states+i)) {
	    result = imageSpec->images[i];
	    break;
	}
    }
    if (!result) {
	result = imageSpec->baseImage;
    }
#if NEED_EXTRA_INFO
    if (tkwin) {
	image = TkImageForWindow(result, tkwin);
	if (image != result) {
	    if (imageSpec->useImage) {
		Tk_FreeImage(imageSpec->useImage);
	    }
	    imageSpec->useImage = image;
	    if (image) {
		result = image;
	    }
	}
    }
#endif
    return result;
}

/*------------------------------------------------------------------------
 * +++ Drawing utilities.
 */

/* LPadding, CPadding, RPadding --
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    if (imageData->imageMap) {
	Tcl_Obj *imageObj = Ttk_StateMapLookup(NULL,imageData->imageMap,state);
	if (imageObj) {
	    image = Ttk_UseImage(imageData->cache, tkwin, imageObj);
	}
    }
    if (!image) {
	image = TtkSelectImage(imageData->imageSpec, state);
    }
#else
    image = TtkSelectImage(imageData->imageSpec, state);
#endif

    if (!image) {
	return;
    }

    Tk_SizeOfImage(image, &imgWidth, &imgHeight);







|


|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
    if (imageData->imageMap) {
	Tcl_Obj *imageObj = Ttk_StateMapLookup(NULL,imageData->imageMap,state);
	if (imageObj) {
	    image = Ttk_UseImage(imageData->cache, tkwin, imageObj);
	}
    }
    if (!image) {
	image = TtkSelectImage(imageData->imageSpec, tkwin, state);
    }
#else
    image = TtkSelectImage(imageData->imageSpec, tkwin, state);
#endif

    if (!image) {
	return;
    }

    Tk_SizeOfImage(image, &imgWidth, &imgHeight);

Changes to jni/sdl2tk/generic/ttk/ttkLabel.c.

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    if (!image->imageObj) {
	return 0;
    }
    image->imageSpec = TtkGetImageSpec(NULL, tkwin, image->imageObj);
    if (!image->imageSpec) {
	return 0;
    }
    image->tkimg = TtkSelectImage(image->imageSpec, state);
    if (!image->tkimg) {
	TtkFreeImageSpec(image->imageSpec);
	return 0;
    }
    Tk_SizeOfImage(image->tkimg, &image->width, &image->height);

    return 1;







|







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    if (!image->imageObj) {
	return 0;
    }
    image->imageSpec = TtkGetImageSpec(NULL, tkwin, image->imageObj);
    if (!image->imageSpec) {
	return 0;
    }
    image->tkimg = TtkSelectImage(image->imageSpec, tkwin, state);
    if (!image->tkimg) {
	TtkFreeImageSpec(image->imageSpec);
	return 0;
    }
    Tk_SizeOfImage(image->tkimg, &image->width, &image->height);

    return 1;
389
390
391
392
393
394
395
396

397
398
399
400
401
402
403
     * @@@ it's ugly and out of fashion.
     * Do not stipple at all under Aqua, just draw the image: it shows up
     * as a white rectangle otherwise.
     */


    if (state & TTK_STATE_DISABLED) {
	if (TtkSelectImage(image->imageSpec, 0ul) == image->tkimg) {

#ifndef MAC_OSX_TK
	    StippleOver(image, tkwin, d, b.x,b.y);
#endif
	}
    }
}








|
>







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
     * @@@ it's ugly and out of fashion.
     * Do not stipple at all under Aqua, just draw the image: it shows up
     * as a white rectangle otherwise.
     */


    if (state & TTK_STATE_DISABLED) {
	if (TkImageEqual(TtkSelectImage(image->imageSpec, 0, 0ul),
		image->tkimg)) {
#ifndef MAC_OSX_TK
	    StippleOver(image, tkwin, d, b.x,b.y);
#endif
	}
    }
}

Changes to jni/sdl2tk/generic/ttk/ttkTheme.h.

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
 */

typedef struct TtkImageSpec Ttk_ImageSpec;
TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *);
TTKAPI Ttk_ImageSpec *TtkGetImageSpecEx(Tcl_Interp *, Tk_Window, Tcl_Obj *,
					Tk_ImageChangedProc *, ClientData);
TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *);
TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State);

/*------------------------------------------------------------------------
 * +++ Miscellaneous enumerations.
 * 	Other stuff that element implementations need to know about.
 */
typedef enum 			/* -default option values */
{







|







375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
 */

typedef struct TtkImageSpec Ttk_ImageSpec;
TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *);
TTKAPI Ttk_ImageSpec *TtkGetImageSpecEx(Tcl_Interp *, Tk_Window, Tcl_Obj *,
					Tk_ImageChangedProc *, ClientData);
TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *);
TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Tk_Window, Ttk_State);

/*------------------------------------------------------------------------
 * +++ Miscellaneous enumerations.
 * 	Other stuff that element implementations need to know about.
 */
typedef enum 			/* -default option values */
{