Tk Source Code

Check-in [9f6ef8e5]
Login

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

Overview
Comment:Properly clean up, when a (Tcl 8.6) thread is canceled. (Backported from Tk 8.6)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: 9f6ef8e5dae68c6db252184beea6f446b75a0608
User & Date: jan.nijtmans 2013-03-27 14:06:11
Original Comment: Properly clean up, when a (Tcl 8.6) thread is canceled.
Context
2013-03-28
07:36
Easier solution, with proper protection and configure warnings. check-in: 6af7f840 user: jan.nijtmans tags: core-8-5-branch
2013-03-27
14:11
merge-mark check-in: 16ea6a46 user: jan.nijtmans tags: trunk
14:06
Properly clean up, when a (Tcl 8.6) thread is canceled. (Backported from Tk 8.6) check-in: 9f6ef8e5 user: jan.nijtmans tags: core-8-5-branch
13:07
Make compiling/running Tk8.5 against 8.6 headers work on Windows as well. In dynamic builds, Tcl_FindExecutable should always be taken from the stub table, even though the 8.6 headers tell otherwise. That's why in Tcl 8.6, the Tcl_FindExecutable() call moved from Tk_MainEx to the Tk_Main() macro. check-in: f7c61c80 user: jan.nijtmans tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tkCmds.c.

18
19
20
21
22
23
24









25
26
27
28
29
30
31
#include "tkWinInt.h"
#elif defined(MAC_OSX_TK)
#include "tkMacOSXInt.h"
#else
#include "tkUnixInt.h"
#endif










/*
 * Forward declarations for functions defined later in this file:
 */

static TkWindow *	GetTopHierarchy(Tk_Window tkwin);
static char *		WaitVariableProc(ClientData clientData,
			    Tcl_Interp *interp, const char *name1,







>
>
>
>
>
>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "tkWinInt.h"
#elif defined(MAC_OSX_TK)
#include "tkMacOSXInt.h"
#else
#include "tkUnixInt.h"
#endif

#if (TCL_MAJOR_VERSION==8) && (TCL_MINOR_VERSION<6)
#   if defined(STATIC_BUILD)
#	define Tcl_Canceled(interp, flags) (TCL_OK)
#   else
#	define Tcl_Canceled \
		(tclStubsPtr->tclCanceled) /* 581 */
#   endif
#endif

/*
 * Forward declarations for functions defined later in this file:
 */

static TkWindow *	GetTopHierarchy(Tk_Window tkwin);
static char *		WaitVariableProc(ClientData clientData,
			    Tcl_Interp *interp, const char *name1,
909
910
911
912
913
914
915

916
917
918
919
920
921
922
    ClientData clientData,	/* Main window associated with interpreter. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tk_Window tkwin = (Tk_Window) clientData;
    int done, index;

    static const char *optionStrings[] = {
	"variable", "visibility", "window", NULL
    };
    enum options {
	TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW
    };








>







918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
    ClientData clientData,	/* Main window associated with interpreter. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tk_Window tkwin = (Tk_Window) clientData;
    int done, index;
    int code = TCL_OK;
    static const char *optionStrings[] = {
	"variable", "visibility", "window", NULL
    };
    enum options {
	TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW
    };

935
936
937
938
939
940
941




942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960




961
962
963
964
965
966
967
968
969
970
	if (Tcl_TraceVar(interp, Tcl_GetString(objv[2]),
		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		WaitVariableProc, (ClientData) &done) != TCL_OK) {
	    return TCL_ERROR;
	}
	done = 0;
	while (!done) {




	    Tcl_DoOneEvent(0);
	}
	Tcl_UntraceVar(interp, Tcl_GetString(objv[2]),
		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		WaitVariableProc, (ClientData) &done);
	break;

    case TKWAIT_VISIBILITY: {
	Tk_Window window;

	window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
	if (window == NULL) {
	    return TCL_ERROR;
	}
	Tk_CreateEventHandler(window,
		VisibilityChangeMask|StructureNotifyMask,
		WaitVisibilityProc, (ClientData) &done);
	done = 0;
	while (!done) {




	    Tcl_DoOneEvent(0);
	}
	if (done != 1) {
	    /*
	     * Note that we do not delete the event handler because it was
	     * deleted automatically when the window was destroyed.
	     */

	    Tcl_ResetResult(interp);
	    Tcl_AppendResult(interp, "window \"", Tcl_GetString(objv[2]),







>
>
>
>



















>
>
>
>


|







945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
	if (Tcl_TraceVar(interp, Tcl_GetString(objv[2]),
		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		WaitVariableProc, (ClientData) &done) != TCL_OK) {
	    return TCL_ERROR;
	}
	done = 0;
	while (!done) {
	    if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
		code = TCL_ERROR;
		break;
	    }
	    Tcl_DoOneEvent(0);
	}
	Tcl_UntraceVar(interp, Tcl_GetString(objv[2]),
		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		WaitVariableProc, (ClientData) &done);
	break;

    case TKWAIT_VISIBILITY: {
	Tk_Window window;

	window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
	if (window == NULL) {
	    return TCL_ERROR;
	}
	Tk_CreateEventHandler(window,
		VisibilityChangeMask|StructureNotifyMask,
		WaitVisibilityProc, (ClientData) &done);
	done = 0;
	while (!done) {
	    if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
		code = TCL_ERROR;
		break;
	    }
	    Tcl_DoOneEvent(0);
	}
	if ((done != 0) && (done != 1)) {
	    /*
	     * Note that we do not delete the event handler because it was
	     * deleted automatically when the window was destroyed.
	     */

	    Tcl_ResetResult(interp);
	    Tcl_AppendResult(interp, "window \"", Tcl_GetString(objv[2]),
984
985
986
987
988
989
990




991
992
993
994
995
996

997
998




999
1000
1001
1002
1003
1004
1005

1006
1007

1008

1009
1010
1011
1012
1013
1014
1015
1016
	if (window == NULL) {
	    return TCL_ERROR;
	}
	Tk_CreateEventHandler(window, StructureNotifyMask,
		WaitWindowProc, (ClientData) &done);
	done = 0;
	while (!done) {




	    Tcl_DoOneEvent(0);
	}

	/*
	 * Note: there's no need to delete the event handler. It was deleted
	 * automatically when the window was destroyed.

	 */





	break;
    }
    }

    /*
     * Clear out the interpreter's result, since it may have been set by event
     * handlers.

     */


    Tcl_ResetResult(interp);

    return TCL_OK;
}

	/* ARGSUSED */
static char *
WaitVariableProc(
    ClientData clientData,	/* Pointer to integer to set to 1. */
    Tcl_Interp *interp,		/* Interpreter containing variable. */







>
>
>
>




|
|
>


>
>
>
>






|
>


>

>
|







1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
	if (window == NULL) {
	    return TCL_ERROR;
	}
	Tk_CreateEventHandler(window, StructureNotifyMask,
		WaitWindowProc, (ClientData) &done);
	done = 0;
	while (!done) {
	    if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
		code = TCL_ERROR;
		break;
	    }
	    Tcl_DoOneEvent(0);
	}

	/*
	 * Note: normally there's no need to delete the event handler. It was
	 * deleted automatically when the window was destroyed; however, if
	 * the wait operation was canceled, we need to delete it.
	 */

	if (done == 0) {
	    Tk_DeleteEventHandler(window, StructureNotifyMask,
		    WaitWindowProc, &done);
	}
	break;
    }
    }

    /*
     * Clear out the interpreter's result, since it may have been set by event
     * handlers. This is skipped if an error occurred above, such as the wait
     * operation being canceled.
     */

    if (code == TCL_OK)
    Tcl_ResetResult(interp);

    return code;
}

	/* ARGSUSED */
static char *
WaitVariableProc(
    ClientData clientData,	/* Pointer to integer to set to 1. */
    Tcl_Interp *interp,		/* Interpreter containing variable. */
1076
1077
1078
1079
1080
1081
1082

1083
1084
1085
1086
1087
1088
1089
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    static const char *updateOptions[] = {"idletasks", NULL};
    int flags, index;
    TkDisplay *dispPtr;


    if (objc == 1) {
	flags = TCL_DONT_WAIT;
    } else if (objc == 2) {
	if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0,
		&index) != TCL_OK) {
	    return TCL_ERROR;







>







1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    static const char *updateOptions[] = {"idletasks", NULL};
    int flags, index;
    TkDisplay *dispPtr;
    int code = TCL_OK;

    if (objc == 1) {
	flags = TCL_DONT_WAIT;
    } else if (objc == 2) {
	if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0,
		&index) != TCL_OK) {
	    return TCL_ERROR;
1100
1101
1102
1103
1104
1105
1106





1107



1108



1109
1110
1111
1112












1113
1114
1115
1116
1117
1118
1119
1120

1121
1122

1123

1124
1125
1126
1127
1128
1129
1130
1131
     * possible that the entire application could be destroyed by an event
     * handler that occurs during the update. Thus, don't use any information
     * from tkwin after calling Tcl_DoOneEvent.
     */

    while (1) {
	while (Tcl_DoOneEvent(flags) != 0) {





	    /* Empty loop body */



	}



	for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
		dispPtr = dispPtr->nextPtr) {
	    XSync(dispPtr->display, False);
	}












	if (Tcl_DoOneEvent(flags) == 0) {
	    break;
	}
    }

    /*
     * Must clear the interpreter's result because event handlers could have
     * executed commands.

     */


    Tcl_ResetResult(interp);

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_WinfoObjCmd --
 *







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




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







|
>


>

>
|







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
     * possible that the entire application could be destroyed by an event
     * handler that occurs during the update. Thus, don't use any information
     * from tkwin after calling Tcl_DoOneEvent.
     */

    while (1) {
	while (Tcl_DoOneEvent(flags) != 0) {
	    if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
		code = TCL_ERROR;
		break;
	    }
	}

	/*
	 * If event processing was canceled proceed no further.
	 */

	if (code == TCL_ERROR)
	    break;

	for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
		dispPtr = dispPtr->nextPtr) {
	    XSync(dispPtr->display, False);
	}

	/*
	 * Check again if event processing has been canceled because the inner
	 * loop (above) may not have checked (i.e. no events were processed and
	 * the loop body was skipped).
	 */

	if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
	    code = TCL_ERROR;
	    break;
	}

	if (Tcl_DoOneEvent(flags) == 0) {
	    break;
	}
    }

    /*
     * Must clear the interpreter's result because event handlers could have
     * executed commands. This is skipped if an error occurred above, such as
     * the wait operation being canceled.
     */

    if (code == TCL_OK)
    Tcl_ResetResult(interp);

    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_WinfoObjCmd --
 *