Tk Source Code

Check-in [42ad10c0]
Login

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

Overview
Comment:Changes to make use of TIP 638 routine Tcl_GetNumberFromObj
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tip-638
Files: files | file ages | folders
SHA3-256: 42ad10c0b55dec60f1d617b45579bd5782191bbb12339a7a2e29d9dbacca6814
User & Date: dgp 2022-09-30 12:27:23.593
Context
2022-10-07
09:33
Add some backwards compatibility, so it still works without TIP #638 (with Tcl 8.6). Can be simplified as soon as TIP #638 arrives in Tcl 9.0. check-in: 73479389 user: jan.nijtmans tags: tip-638
2022-09-30
12:27
Changes to make use of TIP 638 routine Tcl_GetNumberFromObj check-in: 42ad10c0 user: dgp tags: tip-638
2022-09-27
17:47
Fix [f326f30e82]: DestroyMenuInstance(): clear stale pointer. Patch from Christopher Chavez. check-in: 5c8e8017 user: fvogel tags: trunk, main
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tkObj.c.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#define SET_COMPLEXPIXEL(objPtr, repPtr)		\
    (objPtr)->internalRep.twoPtrValue.ptr1 = NULL;		\
    (objPtr)->internalRep.twoPtrValue.ptr2 = repPtr

#define GET_COMPLEXPIXEL(objPtr)			\
    ((PixelRep *) (objPtr)->internalRep.twoPtrValue.ptr2)

/*
 * One of these structures is created per thread to store thread-specific
 * data. In this case, it is used to contain references to selected
 * Tcl_ObjTypes that we can use as screen distances without conversion. The
 * "dataKey" below is used to locate the ThreadSpecificData for the current
 * thread.
 */

typedef struct {
    const Tcl_ObjType *doubleTypePtr;
    const Tcl_ObjType *intTypePtr;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;

/*
 * The following structure is the internal representation for mm objects.
 */

typedef struct MMRep {
    double value;
    int units;







<
<
<
<
<
<
<
<
<
<
<
<
<
<







35
36
37
38
39
40
41














42
43
44
45
46
47
48
#define SET_COMPLEXPIXEL(objPtr, repPtr)		\
    (objPtr)->internalRep.twoPtrValue.ptr1 = NULL;		\
    (objPtr)->internalRep.twoPtrValue.ptr2 = repPtr

#define GET_COMPLEXPIXEL(objPtr)			\
    ((PixelRep *) (objPtr)->internalRep.twoPtrValue.ptr2)















/*
 * The following structure is the internal representation for mm objects.
 */

typedef struct MMRep {
    double value;
    int units;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

static void		DupMMInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		DupPixelInternalRep(Tcl_Obj *srcPtr, Tcl_Obj*copyPtr);
static void		DupWindowInternalRep(Tcl_Obj *srcPtr,Tcl_Obj*copyPtr);
static void		FreeMMInternalRep(Tcl_Obj *objPtr);
static void		FreePixelInternalRep(Tcl_Obj *objPtr);
static void		FreeWindowInternalRep(Tcl_Obj *objPtr);
static ThreadSpecificData *GetTypeCache(void);
static void		UpdateStringOfMM(Tcl_Obj *objPtr);
static int		SetMMFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static int		SetPixelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static int		SetWindowFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);

#if TCL_MAJOR_VERSION < 9
#ifdef __cplusplus







<







73
74
75
76
77
78
79

80
81
82
83
84
85
86

static void		DupMMInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		DupPixelInternalRep(Tcl_Obj *srcPtr, Tcl_Obj*copyPtr);
static void		DupWindowInternalRep(Tcl_Obj *srcPtr,Tcl_Obj*copyPtr);
static void		FreeMMInternalRep(Tcl_Obj *objPtr);
static void		FreePixelInternalRep(Tcl_Obj *objPtr);
static void		FreeWindowInternalRep(Tcl_Obj *objPtr);

static void		UpdateStringOfMM(Tcl_Obj *objPtr);
static int		SetMMFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static int		SetPixelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static int		SetWindowFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);

#if TCL_MAJOR_VERSION < 9
#ifdef __cplusplus
162
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
static const Tcl_ObjType windowObjType = {
    "window",			/* name */
    FreeWindowInternalRep,	/* freeIntRepProc */
    DupWindowInternalRep,	/* dupIntRepProc */
    NULL,			/* updateStringProc */
    NULL			/* setFromAnyProc */
};

/*
 *----------------------------------------------------------------------
 *
 * GetTypeCache --
 *
 *	Get (and build if necessary) the cache of useful Tcl object types for
 *	comparisons in the conversion functions.  This allows optimized checks
 *	for standard cases.
 *
 *----------------------------------------------------------------------
 */

static ThreadSpecificData *
GetTypeCache(void)
{
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    if (tsdPtr->doubleTypePtr == NULL) {
	/* Smart initialization of doubleTypePtr/intTypePtr without
	 * hash-table lookup or creating complete Tcl_Obj's */
	Tcl_Obj obj;
	obj.bytes = (char *)"0.0";
	obj.length = 3;
	obj.typePtr = NULL;
	Tcl_GetDoubleFromObj(NULL, &obj, &obj.internalRep.doubleValue);
	tsdPtr->doubleTypePtr = obj.typePtr;
	obj.bytes = (char *)"0";
	obj.length = 1;
	obj.typePtr = NULL;
	Tcl_GetLongFromObj(NULL, &obj, &obj.internalRep.longValue);
	tsdPtr->intTypePtr = obj.typePtr;
    }
    return tsdPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TkGetIntForIndex --
 *
 *	Almost the same as Tcl_GetIntForIndex, but it return an int. Accepts







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







147
148
149
150
151
152
153




































154
155
156
157
158
159
160
static const Tcl_ObjType windowObjType = {
    "window",			/* name */
    FreeWindowInternalRep,	/* freeIntRepProc */
    DupWindowInternalRep,	/* dupIntRepProc */
    NULL,			/* updateStringProc */
    NULL			/* setFromAnyProc */
};





































/*
 *----------------------------------------------------------------------
 *
 * TkGetIntForIndex --
 *
 *	Almost the same as Tcl_GetIntForIndex, but it return an int. Accepts
278
279
280
281
282
283
284

285
286
287
288
289
290
291
292
293
294
295
296
297
298

299
300
301



302
303
304
305
306
307



308
309
310
311
312





313
314
315
316
317
318
319
    Tk_Window tkwin,
    Tcl_Obj *objPtr,		/* The object from which to get pixels. */
    int *intPtr,
    double *dblPtr)		/* Places to store resulting pixels. */
{
    int result, fresh;
    double d;

    PixelRep *pixelPtr;
    static const double bias[] = {
	1.0,	10.0,	25.4,	0.35278 /*25.4 / 72.0*/
    };

    /*
     * Special hacks where the type of the object is known to be something
     * that is just numeric and cannot require distance conversion. This pokes
     * holes in Tcl's abstractions, but they are just for optimization, not
     * semantics.
     */

    if (objPtr->typePtr != &pixelObjType) {
	ThreadSpecificData *typeCache = GetTypeCache();


	if (objPtr->typePtr == typeCache->doubleTypePtr) {
	    (void) Tcl_GetDoubleFromObj(interp, objPtr, &d);



	    if (dblPtr != NULL) {
		*dblPtr = d;
	    }
	    *intPtr = (int) (d<0 ? d-0.5 : d+0.5);
	    return TCL_OK;
	} else if (objPtr->typePtr == typeCache->intTypePtr) {



	    (void) Tcl_GetIntFromObj(interp, objPtr, intPtr);
	    if (dblPtr) {
		*dblPtr = (double) (*intPtr);
	    }
	    return TCL_OK;





	}
    }

 retry:
    fresh = (objPtr->typePtr != &pixelObjType);
    if (fresh) {
	result = SetPixelFromAny(interp, objPtr);







>





<
<
<
<
<
<
<

|
>

<
|
>
>
>
|
|
|
|
|
|
>
>
>
|
|
|
|
|
>
>
>
>
>







227
228
229
230
231
232
233
234
235
236
237
238
239







240
241
242
243

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    Tk_Window tkwin,
    Tcl_Obj *objPtr,		/* The object from which to get pixels. */
    int *intPtr,
    double *dblPtr)		/* Places to store resulting pixels. */
{
    int result, fresh;
    double d;
    Tcl_WideInt w;
    PixelRep *pixelPtr;
    static const double bias[] = {
	1.0,	10.0,	25.4,	0.35278 /*25.4 / 72.0*/
    };








    if (objPtr->typePtr != &pixelObjType) {
	int type;
	void *ptr;


	if (TCL_OK == Tcl_GetNumberFromObj(interp, objPtr, &ptr, &type)) {
	    switch (type) {
	    case TCL_NUMBER_DOUBLE: 
		d = *(const double *)ptr;
		if (dblPtr) {
		    *dblPtr = d;
		}
		*intPtr = (int) (d<0 ? d-0.5 : d+0.5);
		return TCL_OK;

	    case TCL_NUMBER_INT:
		w = *(const Tcl_WideInt *)ptr;
		if (w <= INT_MAX && w >= INT_MIN) {
		    *intPtr = (int) w;
		    if (dblPtr) {
			*dblPtr = (double) (*intPtr);
		    }
		    return TCL_OK;
		}

	    /* Unhandled cases fall through */

	    }
	}
    }

 retry:
    fresh = (objPtr->typePtr != &pixelObjType);
    if (fresh) {
	result = SetPixelFromAny(interp, objPtr);
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
 */

static int
SetMMFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr)		/* The object to convert. */
{
    ThreadSpecificData *typeCache = GetTypeCache();
    const Tcl_ObjType *typePtr;
    const char *string;
    char *rest;
    double d;
    int units;
    MMRep *mmPtr;




    if (objPtr->typePtr == typeCache->doubleTypePtr) {

	Tcl_GetDoubleFromObj(interp, objPtr, &d);




	units = -1;

    } else if (objPtr->typePtr == typeCache->intTypePtr) {




	Tcl_GetIntFromObj(interp, objPtr, &units);
	d = (double) units;
	units = -1;

	/*
	 * In the case of ints, we need to ensure that a valid string exists
	 * in order for int-but-not-string objects to be converted back to
	 * ints again from mm obj types.


	 */

	(void) Tcl_GetString(objPtr);



    } else {

	/*
	 * It wasn't a known int or double, so parse it.
	 */

	string = Tcl_GetString(objPtr);

	d = strtod(string, &rest);







<







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

|
|
|
|
>
>
|

|
>
>
>
|
>







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
 */

static int
SetMMFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr)		/* The object to convert. */
{

    const Tcl_ObjType *typePtr;
    const char *string;
    char *rest;
    double d;
    int units;
    MMRep *mmPtr;

    int type, needParse = 1;
    void *ptr;
    Tcl_WideInt w;

    if (TCL_OK == Tcl_GetNumberFromObj(NULL, objPtr, &ptr, &type)) {

	switch (type) {
	case TCL_NUMBER_DOUBLE: 
	    needParse = 0;
	    d = *(const double *)ptr;
	    units = -1;
	    break;

	case TCL_NUMBER_INT:
	    w = *(const Tcl_WideInt *)ptr;
	    if (w <= INT_MAX && w >= INT_MIN) {
		needParse = 0;
		units = (int) w;
		d = (double) units;
		units = -1;

		/*
		 * In the case of ints, we need to ensure that a valid
		 * string exists in order for int-but-not-string objects
		 * to be converted back to ints again from mm obj types.
		 *
		 * TODO: Is this really necessary?
		 */

		(void) Tcl_GetString(objPtr);
	    }
	}
    }

    if (needParse) {
	/*
	 * It wasn't a known int or double, so parse it.
	 */

	string = Tcl_GetString(objPtr);

	d = strtod(string, &rest);