10
10
* See the file "license.terms" for information on usage and redistribution
11
11
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
* RCS: @(#) $Id: tkConsole.c,v 1.18.2.2 2005/06/23 22:07:13 das Exp $
13
* RCS: @(#) $Id: tkConsole.c,v 1.18.2.6 2006/09/25 17:28:20 andreas_kupries Exp $
22
* A data structure of the following type holds information for each console
23
* which a handler (i.e. a Tcl command) has been defined for a particular
20
* Each console is associated with an instance of the ConsoleInfo struct.
21
* It keeps track of what interp holds the Tk application that displays
22
* the console, and what interp is controlled by the interactions in that
23
* console. A refCount permits the struct to be shared as instance data
24
* by commands and by channels.
27
27
typedef struct ConsoleInfo {
28
Tcl_Interp *consoleInterp; /* Interpreter for the console. */
29
Tcl_Interp *interp; /* Interpreter to send console commands. */
28
Tcl_Interp *consoleInterp; /* Interpreter displaying the console. */
29
Tcl_Interp *interp; /* Interpreter controlled by console. */
33
* Each interpreter with a console attached stores a reference to the
34
* interpreter's ConsoleInfo in the interpreter's AssocData store. The
35
* alternative is to look the values up by examining the "console"
36
* command and that is fragile. [Bug 1016385]
34
* Each console channel holds an instance of the ChannelData struct as
35
* its instance data. It contains ConsoleInfo, so the channel can work
36
* with the appropriate console window, and a type value to distinguish
37
* the stdout channel from the stderr channel.
39
#define TK_CONSOLE_INFO_KEY "tk::ConsoleInfo"
41
typedef struct ThreadSpecificData {
42
Tcl_Interp *gStdoutInterp;
44
static Tcl_ThreadDataKey dataKey;
45
static int consoleInitialized = 0;
40
typedef struct ChannelData {
42
int type; /* TCL_STDOUT or TCL_STDERR */
48
* The Mutex below is used to lock access to the consoleIntialized flag
51
TCL_DECLARE_MUTEX(consoleMutex)
54
* Forward declarations for procedures defined later in this file:
56
* The first three will be used in the tk app shells...
59
static int ConsoleCmd _ANSI_ARGS_((ClientData clientData,
60
Tcl_Interp *interp, int argc, CONST char **argv));
46
* Prototypes for local procedures defined in this file:
49
static int ConsoleClose _ANSI_ARGS_((ClientData instanceData,
61
51
static void ConsoleDeleteProc _ANSI_ARGS_((ClientData clientData));
62
52
static void ConsoleEventProc _ANSI_ARGS_((ClientData clientData,
63
53
XEvent *eventPtr));
64
static int InterpreterCmd _ANSI_ARGS_((ClientData clientData,
65
Tcl_Interp *interp, int argc, CONST char **argv));
54
static int ConsoleHandle _ANSI_ARGS_((ClientData instandeData,
55
int direction, ClientData *handlePtr));
67
56
static int ConsoleInput _ANSI_ARGS_((ClientData instanceData,
68
57
char *buf, int toRead, int *errorCode));
58
static int ConsoleObjCmd _ANSI_ARGS_((ClientData clientData,
59
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
69
60
static int ConsoleOutput _ANSI_ARGS_((ClientData instanceData,
70
61
CONST char *buf, int toWrite, int *errorCode));
71
static int ConsoleClose _ANSI_ARGS_((ClientData instanceData,
73
62
static void ConsoleWatch _ANSI_ARGS_((ClientData instanceData,
75
static int ConsoleHandle _ANSI_ARGS_((ClientData instanceData,
76
int direction, ClientData *handlePtr));
64
static void DeleteConsoleInterp _ANSI_ARGS_((ClientData clientData));
65
static void InterpDeleteProc _ANSI_ARGS_((ClientData clientData,
67
static int InterpreterObjCmd _ANSI_ARGS_((ClientData clientData,
68
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
79
71
* This structure describes the channel type structure for file based IO:
246
Tcl_MutexLock(&consoleMutex);
247
if (!consoleInitialized) {
249
consoleInitialized = 1;
252
* check for STDIN, otherwise create it
254
* Don't do this check on the Mac, because it is hard to prevent
255
* callbacks from the SIOUX layer from opening stdout & stdin, but
256
* we don't want to use the SIOUX console. Since the console is not
257
* actually created till something is written to the channel, it is
258
* okay to just ignore it here.
260
* This is still a bit of a hack, however, and should be cleaned up
261
* when we have a better abstraction for the console.
264
if (ShouldUseConsoleChannel(TCL_STDIN)) {
265
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0",
266
(ClientData) TCL_STDIN, TCL_READABLE);
267
if (consoleChannel != NULL) {
268
Tcl_SetChannelOption(NULL, consoleChannel,
269
"-translation", "lf");
270
Tcl_SetChannelOption(NULL, consoleChannel,
271
"-buffering", "none");
272
Tcl_SetChannelOption(NULL, consoleChannel,
273
"-encoding", "utf-8");
275
Tcl_SetStdChannel(consoleChannel, TCL_STDIN);
279
* check for STDOUT, otherwise create it
282
if (ShouldUseConsoleChannel(TCL_STDOUT)) {
283
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1",
284
(ClientData) TCL_STDOUT, TCL_WRITABLE);
285
if (consoleChannel != NULL) {
286
Tcl_SetChannelOption(NULL, consoleChannel,
287
"-translation", "lf");
288
Tcl_SetChannelOption(NULL, consoleChannel,
289
"-buffering", "none");
290
Tcl_SetChannelOption(NULL, consoleChannel,
291
"-encoding", "utf-8");
293
Tcl_SetStdChannel(consoleChannel, TCL_STDOUT);
297
* check for STDERR, otherwise create it
300
if (ShouldUseConsoleChannel(TCL_STDERR)) {
301
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2",
302
(ClientData) TCL_STDERR, TCL_WRITABLE);
303
if (consoleChannel != NULL) {
304
Tcl_SetChannelOption(NULL, consoleChannel,
305
"-translation", "lf");
306
Tcl_SetChannelOption(NULL, consoleChannel,
307
"-buffering", "none");
308
Tcl_SetChannelOption(NULL, consoleChannel,
309
"-encoding", "utf-8");
311
Tcl_SetStdChannel(consoleChannel, TCL_STDERR);
314
Tcl_MutexUnlock(&consoleMutex);
247
consoleInitPtr = Tcl_GetThreadData(&consoleInitKey, (int)sizeof(int));
248
if (*consoleInitPtr) {
249
/* We've already initialized console channels in this thread. */
254
doIn = ShouldUseConsoleChannel(TCL_STDIN);
255
doOut = ShouldUseConsoleChannel(TCL_STDOUT);
256
doErr = ShouldUseConsoleChannel(TCL_STDERR);
258
if (!(doIn || doOut || doErr)) {
260
* No std channels should be tied to the console;
261
* Thus, no need to create the console
267
* At least one std channel wants to be tied to the console,
268
* so create the interp for it to live in.
271
info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
272
info->consoleInterp = NULL;
277
ChannelData *data = (ChannelData *) ckalloc(sizeof(ChannelData));
279
data->info->refCount++;
280
data->type = TCL_STDIN;
281
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0",
282
(ClientData) data, TCL_READABLE);
283
if (consoleChannel != NULL) {
284
Tcl_SetChannelOption(NULL, consoleChannel,
285
"-translation", "lf");
286
Tcl_SetChannelOption(NULL, consoleChannel,
287
"-buffering", "none");
288
Tcl_SetChannelOption(NULL, consoleChannel,
289
"-encoding", "utf-8");
291
Tcl_SetStdChannel(consoleChannel, TCL_STDIN);
292
Tcl_RegisterChannel(NULL, consoleChannel);
296
ChannelData *data = (ChannelData *) ckalloc(sizeof(ChannelData));
298
data->info->refCount++;
299
data->type = TCL_STDOUT;
300
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1",
301
(ClientData) data, TCL_WRITABLE);
302
if (consoleChannel != NULL) {
303
Tcl_SetChannelOption(NULL, consoleChannel,
304
"-translation", "lf");
305
Tcl_SetChannelOption(NULL, consoleChannel,
306
"-buffering", "none");
307
Tcl_SetChannelOption(NULL, consoleChannel,
308
"-encoding", "utf-8");
310
Tcl_SetStdChannel(consoleChannel, TCL_STDOUT);
311
Tcl_RegisterChannel(NULL, consoleChannel);
315
ChannelData *data = (ChannelData *) ckalloc(sizeof(ChannelData));
317
data->info->refCount++;
318
data->type = TCL_STDERR;
319
consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2",
320
(ClientData) data, TCL_WRITABLE);
321
if (consoleChannel != NULL) {
322
Tcl_SetChannelOption(NULL, consoleChannel,
323
"-translation", "lf");
324
Tcl_SetChannelOption(NULL, consoleChannel,
325
"-buffering", "none");
326
Tcl_SetChannelOption(NULL, consoleChannel,
327
"-encoding", "utf-8");
329
Tcl_SetStdChannel(consoleChannel, TCL_STDERR);
330
Tcl_RegisterChannel(NULL, consoleChannel);
336
353
Tk_CreateConsoleWindow(interp)
337
354
Tcl_Interp *interp; /* Interpreter to use for prompting. */
339
Tcl_Interp *consoleInterp;
340
357
ConsoleInfo *info;
341
Tk_Window mainWindow = Tk_MainWindow(interp);
342
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
343
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
358
Tk_Window mainWindow;
361
int haveConsoleChannel = 1;
345
364
static const char *initCmd = "if {[catch {source $tk_library:console.tcl}]} {source -rsrc console}";
347
366
static const char *initCmd = "source $tk_library/console.tcl";
350
consoleInterp = Tcl_CreateInterp();
351
if (consoleInterp == NULL) {
356
* Initialized Tcl and Tk.
369
/* Init an interp with Tcl and Tk */
370
Tcl_Interp *consoleInterp = Tcl_CreateInterp();
359
371
if (Tcl_Init(consoleInterp) != TCL_OK) {
362
374
if (Tk_Init(consoleInterp) != TCL_OK) {
365
tsdPtr->gStdoutInterp = interp;
379
* Fetch the instance data from whatever std channel is a
380
* console channel. If none, create fresh instance data.
383
if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDIN))
384
== &consoleChannelType) {
385
} else if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDOUT))
386
== &consoleChannelType) {
387
} else if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDERR))
388
== &consoleChannelType) {
390
haveConsoleChannel = 0;
393
if (haveConsoleChannel) {
394
ChannelData *data = (ChannelData *)Tcl_GetChannelInstanceData(chan);
396
if (info->consoleInterp) {
397
/* New ConsoleInfo for a new console window */
398
info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
401
/* Update any console channels to make use of the new console */
402
if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDIN))
403
== &consoleChannelType) {
404
data = (ChannelData *)Tcl_GetChannelInstanceData(chan);
405
data->info->refCount--;
407
data->info->refCount++;
409
if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDOUT))
410
== &consoleChannelType) {
411
data = (ChannelData *)Tcl_GetChannelInstanceData(chan);
412
data->info->refCount--;
414
data->info->refCount++;
416
if (Tcl_GetChannelType(chan = Tcl_GetStdChannel(TCL_STDERR))
417
== &consoleChannelType) {
418
data = (ChannelData *)Tcl_GetChannelInstanceData(chan);
419
data->info->refCount--;
421
data->info->refCount++;
425
info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
429
info->consoleInterp = consoleInterp;
430
info->interp = interp;
432
Tcl_CallWhenDeleted(consoleInterp, InterpDeleteProc, (ClientData) info);
434
Tcl_CreateThreadExitHandler(DeleteConsoleInterp,
435
(ClientData) consoleInterp);
368
438
* Add console commands to the interp
370
info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
371
info->interp = interp;
372
info->consoleInterp = consoleInterp;
373
Tcl_CreateCommand(interp, "console", ConsoleCmd, (ClientData) info,
374
(Tcl_CmdDeleteProc *) ConsoleDeleteProc);
375
Tcl_CreateCommand(consoleInterp, "consoleinterp", InterpreterCmd,
376
(ClientData) info, (Tcl_CmdDeleteProc *) NULL);
377
Tcl_SetAssocData(interp, TK_CONSOLE_INFO_KEY, NULL, (ClientData) info);
379
Tk_CreateEventHandler(mainWindow, StructureNotifyMask, ConsoleEventProc,
441
token = Tcl_CreateObjCommand(interp, "console", ConsoleObjCmd,
442
(ClientData) info, ConsoleDeleteProc);
446
* We don't have to count the ref held by the [consoleinterp] command
447
* in the consoleInterp. The ref held by the consoleInterp delete
448
* handler takes care of us.
450
Tcl_CreateObjCommand(consoleInterp, "consoleinterp", InterpreterObjCmd,
451
(ClientData) info, NULL);
453
mainWindow = Tk_MainWindow(interp);
455
Tk_CreateEventHandler(mainWindow, StructureNotifyMask,
456
ConsoleEventProc, (ClientData) info);
382
460
Tcl_Preserve((ClientData) consoleInterp);
383
if (Tcl_Eval(consoleInterp, initCmd) == TCL_ERROR) {
384
/* goto error; -- no problem for now... */
385
printf("Eval error: %s", consoleInterp->result);
461
result = Tcl_GlobalEval(consoleInterp, initCmd);
462
if (result == TCL_ERROR) {
463
Tcl_Obj *objPtr = Tcl_GetVar2Ex(consoleInterp, "errorCode", NULL,
465
Tcl_ResetResult(interp);
467
Tcl_SetObjErrorCode(interp, objPtr);
470
objPtr = Tcl_GetVar2Ex(consoleInterp, "errorInfo", NULL,
474
CONST char *message = Tcl_GetStringFromObj(objPtr, &numBytes);
475
Tcl_AddObjErrorInfo(interp, message, numBytes);
477
Tcl_SetObjResult(interp, Tcl_GetObjResult(consoleInterp));
387
479
Tcl_Release((ClientData) consoleInterp);
480
if (result == TCL_ERROR) {
481
Tcl_DeleteCommandFromToken(interp, token);
482
mainWindow = Tk_MainWindow(interp);
484
Tk_DeleteEventHandler(mainWindow, StructureNotifyMask,
485
ConsoleEventProc, (ClientData) info);
486
if (--info->refCount <= 0) {
487
ckfree((char *) info);
391
if (consoleInterp != NULL) {
392
Tcl_DeleteInterp(consoleInterp);
495
Tcl_AddErrorInfo(interp, "\n (creating console window)");
496
if (!Tcl_InterpDeleted(consoleInterp)) {
497
Tcl_DeleteInterp(consoleInterp);
394
499
return TCL_ERROR;
552
677
*----------------------------------------------------------------------
556
681
* The console command implements a Tcl interface to the various console
685
* A standard Tcl result.
688
* See the user documentation.
565
690
*----------------------------------------------------------------------
569
ConsoleCmd(clientData, interp, argc, argv)
570
ClientData clientData; /* Not used. */
571
Tcl_Interp *interp; /* Current interpreter. */
572
int argc; /* Number of arguments. */
573
CONST char **argv; /* Argument strings. */
694
ConsoleObjCmd(clientData, interp, objc, objv)
695
ClientData clientData; /* Access to the console interp */
696
Tcl_Interp *interp; /* Current interpreter */
697
int objc; /* Number of arguments */
698
Tcl_Obj *CONST objv[]; /* Argument objects */
701
static CONST char *options[] = {"eval", "hide", "show", "title", NULL};
702
enum option {CON_EVAL, CON_HIDE, CON_SHOW, CON_TITLE};
575
704
ConsoleInfo *info = (ConsoleInfo *) clientData;
579
Tcl_Interp *consoleInterp;
582
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
583
" option ?arg arg ...?\"", (char *) NULL);
588
length = strlen(argv[1]);
590
consoleInterp = info->consoleInterp;
591
Tcl_Preserve((ClientData) consoleInterp);
593
if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) {
596
Tcl_DStringInit(&dString);
597
Tcl_DStringAppend(&dString, "wm title . ", -1);
599
Tcl_DStringAppendElement(&dString, argv[2]);
601
Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString));
602
Tcl_DStringFree(&dString);
603
} else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) {
604
Tcl_Eval(consoleInterp, "wm withdraw .");
605
} else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) {
606
Tcl_Eval(consoleInterp, "wm deiconify .");
607
} else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
609
result = Tcl_Eval(consoleInterp, argv[2]);
610
Tcl_AppendResult(interp, Tcl_GetStringResult(consoleInterp),
613
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
614
" eval command\"", (char *) NULL);
705
Tcl_Interp *consoleInterp = info->consoleInterp;
708
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
711
if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index)
716
switch ((enum option) index) {
719
Tcl_WrongNumArgs(interp, 2, objv, "script");
726
Tcl_WrongNumArgs(interp, 2, objv, NULL);
729
cmd = Tcl_NewStringObj("wm withdraw .", -1);
733
Tcl_WrongNumArgs(interp, 2, objv, NULL);
736
cmd = Tcl_NewStringObj("wm deiconify .", -1);
740
Tcl_WrongNumArgs(interp, 2, objv, "?title?");
743
cmd = Tcl_NewStringObj("wm title .", -1);
745
Tcl_ListObjAppendElement(NULL, cmd, objv[2]);
750
Tcl_IncrRefCount(cmd);
751
if (consoleInterp && !Tcl_InterpDeleted(consoleInterp)) {
752
Tcl_Preserve((ClientData) consoleInterp);
753
result = Tcl_GlobalEvalObj(consoleInterp, cmd);
754
if (result == TCL_ERROR) {
755
Tcl_Obj *objPtr = Tcl_GetVar2Ex(consoleInterp, "errorCode",
756
NULL, TCL_GLOBAL_ONLY);
757
Tcl_ResetResult(interp);
759
Tcl_SetObjErrorCode(interp, objPtr);
762
objPtr = Tcl_GetVar2Ex(consoleInterp, "errorInfo",
763
NULL, TCL_GLOBAL_ONLY);
766
CONST char *message = Tcl_GetStringFromObj(objPtr, &numBytes);
767
Tcl_AddObjErrorInfo(interp, message, numBytes);
770
Tcl_SetObjResult(interp, Tcl_GetObjResult(consoleInterp));
771
Tcl_Release((ClientData) consoleInterp);
618
Tcl_AppendResult(interp, "bad option \"", argv[1],
619
"\": should be hide, show, or title",
773
Tcl_AppendResult(interp, "no active console interp", NULL);
623
Tcl_Release((ClientData) consoleInterp);
776
Tcl_DecrRefCount(cmd);
628
781
*----------------------------------------------------------------------
783
* InterpreterObjCmd --
632
785
* This command allows the console interp to communicate with the
633
786
* main interpreter.
789
* A standard Tcl result.
641
791
*----------------------------------------------------------------------
645
InterpreterCmd(clientData, interp, argc, argv)
646
ClientData clientData; /* Not used. */
647
Tcl_Interp *interp; /* Current interpreter. */
648
int argc; /* Number of arguments. */
649
CONST char **argv; /* Argument strings. */
795
InterpreterObjCmd(clientData, interp, objc, objv)
796
ClientData clientData; /* Not used */
797
Tcl_Interp *interp; /* Current interpreter */
798
int objc; /* Number of arguments */
799
Tcl_Obj *CONST objv[]; /* Argument objects */
801
int index, result = TCL_OK;
802
static CONST char *options[] = {"eval", "record", NULL};
803
enum option {OTHER_EVAL, OTHER_RECORD};
651
804
ConsoleInfo *info = (ConsoleInfo *) clientData;
655
Tcl_Interp *consoleInterp;
656
Tcl_Interp *otherInterp;
659
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
660
" option ?arg arg ...?\"", (char *) NULL);
665
length = strlen(argv[1]);
666
consoleInterp = info->consoleInterp;
667
Tcl_Preserve((ClientData) consoleInterp);
668
otherInterp = info->interp;
805
Tcl_Interp *otherInterp = info->interp;
808
Tcl_WrongNumArgs(interp, 1, objv, "option arg");
811
if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index)
817
Tcl_WrongNumArgs(interp, 2, objv, "script");
821
if ((otherInterp == NULL) || Tcl_InterpDeleted(otherInterp)) {
822
Tcl_AppendResult(interp, "no active master interp", NULL);
669
826
Tcl_Preserve((ClientData) otherInterp);
670
if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
671
result = Tcl_GlobalEval(otherInterp, argv[2]);
672
Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
673
} else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) {
674
Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL);
676
Tcl_ResetResult(interp);
677
Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
679
Tcl_AppendResult(interp, "bad option \"", argv[1],
680
"\": should be eval or record",
827
switch ((enum option) index) {
829
result = Tcl_GlobalEvalObj(otherInterp, objv[2]);
831
* TODO: Should exceptions be filtered here?
833
if (result == TCL_ERROR) {
834
Tcl_Obj *objPtr = Tcl_GetVar2Ex(otherInterp, "errorCode",
835
NULL, TCL_GLOBAL_ONLY);
836
Tcl_ResetResult(interp);
838
Tcl_SetObjErrorCode(interp, objPtr);
841
objPtr = Tcl_GetVar2Ex(otherInterp, "errorInfo",
842
NULL, TCL_GLOBAL_ONLY);
845
CONST char *message = Tcl_GetStringFromObj(objPtr, &numBytes);
846
Tcl_AddObjErrorInfo(interp, message, numBytes);
849
Tcl_SetObjResult(interp, Tcl_GetObjResult(otherInterp));
852
Tcl_RecordAndEvalObj(otherInterp, objv[2], TCL_EVAL_GLOBAL);
854
* By not setting result, we discard any exceptions or errors here
855
* and always return TCL_OK. All the caller wants is the
856
* interp result to display, whether that's result or error message.
858
Tcl_SetObjResult(interp, Tcl_GetObjResult(otherInterp));
684
861
Tcl_Release((ClientData) otherInterp);
685
Tcl_Release((ClientData) consoleInterp);
690
866
*----------------------------------------------------------------------
868
* DeleteConsoleInterp --
870
* Thread exit handler to destroy a console interp when the
871
* thread it lives in gets torn down.
873
*----------------------------------------------------------------------
877
DeleteConsoleInterp(clientData)
878
ClientData clientData;
880
Tcl_Interp *interp = (Tcl_Interp *)clientData;
881
Tcl_DeleteInterp(interp);
885
*----------------------------------------------------------------------
887
* InterpDeleteProc --
889
* React when the interp in which the console is displayed is deleted
897
InterpDeleteProc(clientData, interp)
898
ClientData clientData;
901
ConsoleInfo *info = (ConsoleInfo *) clientData;
903
if(info->consoleInterp == interp) {
904
Tcl_DeleteThreadExitHandler(DeleteConsoleInterp,
905
(ClientData) info-> consoleInterp);
906
info->consoleInterp = NULL;
908
if (--info->refCount <= 0) {
909
ckfree((char *) info);
914
*----------------------------------------------------------------------
692
916
* ConsoleDeleteProc --
694
* If the console command is deleted we destroy the console window
695
* and all associated data structures.
918
* If the console command is deleted we destroy the console window and
919
* all associated data structures.
701
* A new console it created.
925
* A new console is created.
703
927
*----------------------------------------------------------------------
707
ConsoleDeleteProc(clientData)
931
ConsoleDeleteProc(clientData)
708
932
ClientData clientData;
710
934
ConsoleInfo *info = (ConsoleInfo *) clientData;
711
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
712
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
715
* Also need to null this out to prevent any further use.
719
if (tsdPtr != NULL) {
720
tsdPtr->gStdoutInterp = NULL;
723
Tcl_DeleteInterp(info->consoleInterp);
724
info->consoleInterp = NULL;
936
if (info->consoleInterp) {
937
Tcl_DeleteInterp(info->consoleInterp);
939
if (--info->refCount <= 0) {
940
ckfree((char *) info);
748
964
ClientData clientData;
749
965
XEvent *eventPtr;
751
ConsoleInfo *info = (ConsoleInfo *) clientData;
752
Tcl_Interp *consoleInterp;
754
967
if (eventPtr->type == DestroyNotify) {
756
consoleInterp = info->consoleInterp;
759
* It is possible that the console interpreter itself has
760
* already been deleted. In that case the consoleInterp
761
* field will be set to NULL. If the interpreter is already
762
* gone, we do not have to do any work here.
765
if (consoleInterp == (Tcl_Interp *) NULL) {
768
Tcl_Preserve((ClientData) consoleInterp);
769
Tcl_Eval(consoleInterp, "::tk::ConsoleExit");
770
Tcl_Release((ClientData) consoleInterp);
776
*----------------------------------------------------------------------
780
* Prints to the give text to the console. Given the main interp
781
* this functions find the appropiate console interp and forwards
782
* the text to be added to that console.
790
*----------------------------------------------------------------------
794
TkConsolePrint(interp, devId, buffer, size)
795
Tcl_Interp *interp; /* Main interpreter. */
796
int devId; /* TCL_STDOUT for stdout, TCL_STDERR for
798
CONST char *buffer; /* Text buffer. */
799
long size; /* Size of text buffer. */
801
Tcl_DString command, output;
803
Tcl_Interp *consoleInterp;
805
if (interp == NULL) {
809
info = (ConsoleInfo *) Tcl_GetAssocData(interp, TK_CONSOLE_INFO_KEY, NULL);
810
if (info == NULL || info->consoleInterp == NULL) {
814
Tcl_DStringInit(&command);
815
if (devId == TCL_STDERR) {
816
Tcl_DStringAppend(&command, "::tk::ConsoleOutput stderr ", -1);
818
Tcl_DStringAppend(&command, "::tk::ConsoleOutput stdout ", -1);
821
Tcl_DStringInit(&output);
822
Tcl_DStringAppend(&output, buffer, size);
823
Tcl_DStringAppendElement(&command, Tcl_DStringValue(&output));
824
Tcl_DStringFree(&output);
826
consoleInterp = info->consoleInterp;
827
Tcl_Preserve((ClientData) consoleInterp);
828
Tcl_Eval(consoleInterp, Tcl_DStringValue(&command));
829
Tcl_Release((ClientData) consoleInterp);
831
Tcl_DStringFree(&command);
968
ConsoleInfo *info = (ConsoleInfo *) clientData;
969
Tcl_Interp *consoleInterp = info->consoleInterp;
971
if (consoleInterp && !Tcl_InterpDeleted(consoleInterp)) {
972
Tcl_GlobalEval(consoleInterp, "tk::ConsoleExit");
975
if (--info->refCount <= 0) {
976
ckfree((char *) info);