1 /*
2 Copyright (c) 1995-2004 Nick Ing-Simmons. All rights reserved.
3 This program is free software; you can redistribute it and/or
4 modify it under the same terms as Perl itself.
5 */
6 #define PERL_NO_GET_CONTEXT
7 #include <EXTERN.h>
8 #include <perl.h>
9 #include <XSUB.h>
10 #include <patchlevel.h>
11 #ifdef __CYGWIN__
12 # undef XS
13 # define XS(name) void name(pTHXo_ CV* cv)
14 #endif
15
16 #define Tkgv_fullname(x,y,z) gv_fullname3(x,y,z)
17
18 #include "tkGlue.def"
19 #include "pTk/tkPort.h"
20 #include "pTk/tkInt.h"
21 #include "pTk/tix.h" /* for form */
22 #include "pTk/tkImgPhoto.h"
23 #include "pTk/tkImgPhoto.m"
24 #include "pTk/imgInt.h"
25 #include "pTk/imgInt.m"
26 #include "pTk/tkOption.h"
27 #include "pTk/tkOption_f.h"
28 #include "pTk/Lang_f.h"
29 #include "pTk/Xlib.h"
30 #include "pTk/tk_f.h"
31 #include "pTk/tkInt_f.h"
32 #include "pTk/Xlib_f.h"
33 #include "pTk/tclDecls_f.h"
34 #include "pTk/tkDecls_f.h"
35 #include "pTk/tkIntDecls_f.h"
36 #include "pTk/tkEvent.h"
37 #include "pTk/tkEvent.m"
38 #if defined(WIN32) || (defined(__WIN32__) && defined(__CYGWIN__))
39 #include "pTk/tkWin.h"
40 #include "pTk/tkWinInt.h"
41 #include "pTk/tkIntXlibDecls_f.h"
42 #include "pTk/tkIntPlatDecls_f.h"
43 #include "pTk/tkPlatDecls_f.h"
44 #else
45 # ifdef OS2
46 # include "pTk/tkOS2Int.h"
47 # else
48 # include "pTk/tkUnixInt.h"
49 # endif
50 #endif
51 #include "tkGlue.h"
52 #include "tkGlue_f.h"
53
54 DECLARE_EVENT;
55
56 /* #define DEBUG_REFCNT /* */
57
58 #ifdef WIN32
59 long DCcount = 0;
60 void
LangNoteDC(HDC dc,int inc)61 LangNoteDC(HDC dc,int inc)
62 {
63 #ifdef DEBUGGING
64 DCcount += inc;
65 #endif
66 }
67
68 void
LangCheckDC(const char * file,int line)69 LangCheckDC(const char *file,int line)
70 {
71 #ifdef DEBUGGING
72 if (DCcount)
73 LangDebug("%s:%d DCcount %ld\n",file,line,DCcount);
74 #endif
75 }
76 #else
77 void
LangCheckDC(const char * file,int line)78 LangCheckDC(const char *file,int line)
79 {
80 }
81 #endif
82
83
84 extern Tk_PhotoImageFormat imgFmtBMP;
85 #if 0
86 extern Tk_PhotoImageFormat imgFmtGIF;
87 #else
88 extern Tk_PhotoImageFormat tkImgFmtGIF;
89 #endif
90 extern Tk_PhotoImageFormat imgFmtXBM;
91 extern Tk_PhotoImageFormat imgFmtXPM;
92
93 typedef struct
94 {
95 Lang_VarTraceProc *proc;
96 ClientData clientData;
97 Tcl_Interp *interp;
98 char *part2;
99 SV *sv;
100 } Tk_TraceInfo;
101
102 typedef struct
103 {
104 Tcl_Interp *interp;
105 SV *cb;
106 } GenericInfo;
107
108 typedef struct Assoc_s
109 {
110 Tcl_InterpDeleteProc *proc;
111 ClientData clientData;
112 } Assoc_t;
113
114 static int initialized = 0;
115
116
117 static I32 ec = 0;
118 static SV *my_watch;
119
120 static char XEVENT_KEY[] = "_XEvent_";
121 static char GEOMETRY_KEY[] = "_ManageGeometry_";
122 static char CM_KEY[] = "_ClientMessage_";
123 static char ASSOC_KEY[] = "_AssocData_";
124 static char FONTS_KEY[] = "_Fonts_";
125 static char CMD_KEY[] = "_CmdInfo_";
126
127 #ifndef BASEEXT
128 #define BASEEXT "Tk"
129 #endif
130
131 typedef XSdec((*XSptr));
132
133 static XSdec(XStoSubCmd);
134 static XSdec(XStoDisplayof);
135 static XSdec(XStoTk);
136 static XSdec(XStoBind);
137 static XSdec(XStoEvent);
138
139 extern XSdec(XS_Tk__Widget_SelectionGet);
140 extern XSdec(XS_Tk__Widget_ManageGeometry);
141 extern XSdec(XS_Tk__MainWindow_Create);
142 extern XSdec(XS_Tk__Interp_DESTROY);
143 extern XSdec(XS_Tk__Widget_BindClientMessage);
144 extern XSdec(XS_Tk__Widget_PassEvent);
145 extern XSdec(XS_Tk_INIT);
146 extern XSdec(XS_Tk_DoWhenIdle);
147 extern XSdec(XS_Tk_CreateGenericHandler);
148
149 #ifdef PERL_MG_UFUNC
150 #define DECL_MG_UFUNC(name,a,b) PERL_MG_UFUNC(name,a,b)
151 #else
152 #define DECL_MG_UFUNC(name,a,b) I32 name(IV a, SV *b)
153 #endif
154
155 extern void LangPrint _((SV *sv));
156
157 static void handle_idle _((ClientData clientData));
158 static void LangCatArg _((SV * out, SV * sv, int refs));
159 static SV *NameFromCv _((CV * cv));
160 static AV *FindAv _((pTHX_ Tcl_Interp *interp, char *who, int create, char *key));
161 static HV *FindHv _((pTHX_ HV *interp, char *who, int create, char *key));
162 static SV *Blessed _((char *package, SV * sv));
163 static int PushObjCallbackArgs _((Tcl_Interp *interp, SV **svp,EventAndKeySym *obj));
164 static int Check_Eval _((Tcl_Interp *interp));
165 static int handle_generic _((ClientData clientData, XEvent * eventPtr));
166 static void HandleBgErrors _((ClientData clientData));
167 static void SetTclResult _((Tcl_Interp *interp,int count));
168 static int InfoFromArgs _((Lang_CmdInfo *info,Tcl_ObjCmdProc *proc,int mwcd, int items, SV **args));
169 static I32 InsertArg _((SV **mark,I32 posn,SV *sv));
170 extern Tk_Window TkToMainWindow _((Tk_Window tkwin));
171 static int isSwitch _((char *arg));
172 static void Lang_ClearErrorInfo _((Tcl_Interp *interp));
173 static void Lang_MaybeError _((Tcl_Interp *interp,int code,char *why));
174 static void Set_widget _((SV *widget));
175 static SV *tilde_magic _((SV *hv, SV *sv));
176 static SV *struct_sv _((void *ptr, STRLEN sz));
177 static int SelGetProc _((ClientData clientData,
178 Tcl_Interp *interp,
179 long *portion,
180 int numItems,
181 int format,
182 Atom type,
183 Tk_Window tkwin));
184 static void Perl_GeomRequest _((ClientData clientData,Tk_Window tkwin));
185 static void Perl_GeomLostSlave _((ClientData clientData, Tk_Window tkwin));
186
187 Tcl_ObjCmdProc *LangOptionCommand = (Tcl_ObjCmdProc *)Tk_OptionObjCmd;
188
189 static GV *current_widget;
190 static GV *current_event;
191
192 static int
Expire(int code)193 Expire(int code)
194 {
195 return code;
196 }
197
198 #define EXPIRE(args) \
199 ( Tcl_SprintfResult args, Expire(TCL_ERROR) )
200
201 #ifdef DEBUG_TAINT
202 #define do_watch() do { if (PL_tainting) taint_proper("tainted", __FUNCTION__); } while (0)
203 #else
204 extern void do_watch _((void));
205 void
do_watch()206 do_watch()
207 {
208
209 }
210 #endif
211
212 static void
LangCatAv(pTHX_ SV * out,AV * av,int refs,char * bra)213 LangCatAv(pTHX_ SV *out, AV *av, int refs, char *bra)
214 {
215 int n = av_len(av) + 1;
216 int i = 0;
217 sv_catpvn(out, bra, 1);
218 while (i < n)
219 {
220 SV **x = av_fetch(av, i, 0);
221 LangCatArg(out, (x) ? (*x) : &PL_sv_undef, refs);
222 if (++i < n)
223 sv_catpv(out, ",");
224 }
225 sv_catpvn(out, bra+1, 1);
226 }
227
228 static void
LangCatArg(out,sv,refs)229 LangCatArg(out, sv, refs)
230 SV *out;
231 SV *sv;
232 int refs;
233 {
234 dTHX;
235 char buf[80];
236 if (sv)
237 {
238 STRLEN na;
239 switch(SvTYPE(sv))
240 {
241 case SVt_PVAV:
242 LangCatAv(aTHX_ out, (AV *) sv, refs,"()");
243 break;
244 case SVt_PVGV:
245 {SV *tmp = newSVpv("", 0);
246 Tkgv_fullname(tmp,(GV *) sv, Nullch);
247 sv_catpv(out,"*");
248 sv_catpv(out,SvPV(tmp,na));
249 SvREFCNT_dec(tmp);
250 }
251 break;
252 case SVt_PVCV:
253 if (CvGV(sv))
254 {
255 SV *tmp = newSVpv("", 0);
256 Tkgv_fullname(tmp, CvGV(sv), Nullch);
257 sv_catpv(out,"&");
258 sv_catpv(out,SvPV(tmp,na));
259 SvREFCNT_dec(tmp);
260 break;
261 }
262 default:
263 if (SvOK(sv))
264 {
265 char *s = "";
266 if (SvROK(sv))
267 {
268 if (SvTYPE(SvRV(sv)) == SVt_PVAV)
269 LangCatAv(aTHX_ out, (AV *) SvRV(sv), refs,"[]");
270 else if (SvTYPE(SvRV(sv)) == SVt_PVHV)
271 {
272 SV *hv = SvRV(sv);
273 sv_catpv(out,"{}");
274 if (refs)
275 {
276 sprintf(buf, "(%ld%s", (long) SvREFCNT(hv), SvTEMP(hv) ? "t)" : ")");
277 sv_catpv(out, buf);
278 }
279 }
280 else
281 {
282 sv_catpv(out,"\\");
283 LangCatArg(out, SvRV(sv), refs);
284 }
285 }
286 else
287 {
288 if (refs && !SvPOK(sv))
289 {
290 sprintf(buf, "f=%08lX ", (unsigned long) SvFLAGS(sv));
291 sv_catpv(out, buf);
292 }
293 s = SvPV(sv, na);
294 }
295 sv_catpv(out, s);
296 }
297 else
298 {
299 sv_catpv(out, "undef");
300 }
301 break;
302 }
303 }
304 if (refs)
305 {
306 sprintf(buf, "(%ld%s", (long) SvREFCNT(sv), SvTEMP(sv) ? "t)" : ")");
307 sv_catpv(out, buf);
308 }
309 }
310
311 int
LangNull(sv)312 LangNull(sv)
313 Tcl_Obj * sv;
314 {
315 STRLEN len = 0;
316 if (!sv || !SvOK(sv) || (SvPOK(sv) && !SvCUR(sv)))
317 return 1;
318 return 0;
319 }
320
321 char *
LangMergeString(argc,args)322 LangMergeString(argc, args)
323 int argc;
324 SV **args;
325 {
326 dTHX;
327 SV *sv = newSVpv("", 0);
328 STRLEN i = 0;
329 STRLEN na;
330 char *s;
331 while (i < (STRLEN) argc)
332 {
333 LangCatArg(sv, args[i++], 0);
334 if (i < (STRLEN) argc)
335 sv_catpvn(sv, " ", 1);
336 }
337 SvPV(sv, i);
338 s = strncpy(ckalloc(i + 1), SvPV(sv, na), i);
339 s[i] = '\0';
340 SvREFCNT_dec(sv);
341 return s;
342 }
343
344 void
LangPrint(sv)345 LangPrint(sv)
346 SV *sv;
347 {
348 dTHX;
349 static char *type_name[] =
350 {
351 "NULL",
352 "IV",
353 "NV",
354 "RV",
355 "PV",
356 "PVIV",
357 "PVNV",
358 "PVMG",
359 "PVBM",
360 "PVLV",
361 "PVAV",
362 "PVHV",
363 "PVCV",
364 "PVGV",
365 "PVFM",
366 "PVIO"
367 };
368 if (sv)
369 {
370 SV *tmp = newSVpv("", 0);
371 int type = SvTYPE(sv);
372 STRLEN na;
373 LangCatArg(tmp, sv, 1);
374 PerlIO_printf(PerlIO_stderr(), "0x%p %4s f=%08lx %s\n",
375 sv, (type < 16) ? type_name[type] : "?",
376 (unsigned long) SvFLAGS(sv), SvPV(tmp, na));
377 SvREFCNT_dec(tmp);
378 }
379 else
380 {
381 PerlIO_printf(PerlIO_stderr(), "0x%p <<!!!\n",sv);
382 }
383 }
384
385
386 #ifdef DEBUG_REFCNT
387 static Tcl_Interp *IncInterp(Tcl_Interp *interp,char *why);
388 static Tcl_Interp *DecInterp(Tcl_Interp *interp,char *why);
389
390 static Tcl_Interp *
IncInterp(interp,why)391 IncInterp(interp,why)
392 Tcl_Interp *interp;
393 char *why;
394 {
395 dTHX;
396 SvREFCNT_inc((SV *) interp);
397 PerlIO_printf(PerlIO_stdout(),"%s %p %ld\n",why,interp,SvREFCNT((SV *) interp));
398 return interp;
399 }
400
401 static Tcl_Interp *
DecInterp(interp,why)402 DecInterp(interp,why)
403 Tcl_Interp *interp;
404 char *why;
405 {
406 dTHX;
407 SvREFCNT_dec((SV *) interp);
408 PerlIO_printf(PerlIO_stdout(),"%s %p %ld\n",why,interp,SvREFCNT((SV *) interp));
409 return interp;
410 }
411 #else
412 #define DecInterp(interp,why) SvREFCNT_dec(interp)
413 #define IncInterp(interp,why) SvREFCNT_inc(interp)
414 #endif
415
416 #ifdef DEBUG_REFCNT
417
418 static SV *
Decrement(SV * sv,char * who)419 Decrement(SV * sv, char *who)
420 {
421 do_watch();
422 if (sv)
423 {
424 fprintf(stderr, "DEC %s ", who);
425 LangPrint(sv);
426 SvREFCNT_dec(sv);
427 do_watch();
428 }
429 else
430 Tcl_Panic("No sv");
431 return sv;
432 }
433
434 static SV *
Increment(SV * sv,char * who)435 Increment(SV * sv, char *who)
436 {
437 do_watch();
438 if (sv)
439 {
440 fprintf(stderr, "INC %s ", who);
441 LangPrint(sv);
442 SvREFCNT_inc(sv);
443 }
444 else
445 Tcl_Panic("No sv");
446 return sv;
447 }
448 #else
449 #define Decrement(x,y) SvREFCNT_dec(x)
450 #define Increment(x,y) SvREFCNT_inc(x)
451 #endif
452
453 SV *
MakeReference(sv)454 MakeReference(sv)
455 SV *sv;
456 {
457 dTHX;
458 SV *rv = newRV(sv); /* REFCNT of sv now 2 */
459 SvREFCNT_dec(sv);
460 return rv;
461 }
462
463 static SV *
Blessed(package,sv)464 Blessed(package, sv)
465 char *package;
466 SV *sv;
467 {
468 dTHX;
469 HV *stash = gv_stashpv(package, TRUE);
470 return sv_bless(sv, stash);
471 }
472
473 #if 0
474 SV *
475 TagIt(SV *sv, char *type)
476 {
477 char buffer[1024];
478 sprintf(buffer,"Tk::%s_Type",type);
479 if (SvROK(sv))
480 Blessed(buffer,sv);
481 else
482 {
483 SV *rv = newRV(sv);
484 Blessed(buffer,rv);
485 SvREFCNT_dec(rv);
486 }
487 return sv;
488 }
489 #else
490 #define TagIt(sv,type) (sv)
491 #endif
492
493 Tcl_Interp *
Tcl_CreateInterp(void)494 Tcl_CreateInterp _((void))
495 {
496 dTHX;
497 HV *hv = newHV();
498
499 #ifdef switch_to_global_locale
500 /* X uses setlocale(), which is not thread safe, and is incompatible with the
501 * POSIX 2008 thread-safe locale handling functions that perl normally uses on
502 * threaded POSIX builds. The function below does nothing except in
503 * situations where needed, it tells this thread to pay attention to
504 * setlocale(). As long as only one thread calls it, everything works. */
505 switch_to_global_locale();
506 #endif
507
508 SvREFCNT_dec(Blessed("Tk::Interp",newRV((SV *) hv)));
509 return hv;
510 }
511
512 HV *
InterpHv(interp,fatal)513 InterpHv(interp,fatal)
514 Tcl_Interp *interp;
515 int fatal;
516 {
517 if (interp && SvTYPE((SV *) interp) == SVt_PVHV)
518 {
519 return interp;
520 }
521 else if (fatal)
522 {
523 dTHX;
524 STRLEN na;
525 warn("%p is not a hash", interp);
526 abort();
527 }
528 return NULL;
529 }
530
531 typedef SV *(*createProc_t)(pTHX);
532
533 static SV *
FindXv(pTHX_ Tcl_Interp * interp,char * who,int create,char * key,U32 type,createProc_t createProc)534 FindXv(pTHX_ Tcl_Interp *interp, char *who, int create,
535 char *key, U32 type , createProc_t createProc)
536 {
537 STRLEN len = strlen(key);
538 HV *hv = InterpHv(interp,create != 0);
539 if (hv)
540 {
541 if (hv_exists(hv, key, len))
542 {
543 SV **x = hv_fetch(hv, key, len, 0);
544 if (x)
545 {
546 SV *sv = *x;
547 if (type >= SVt_PVAV)
548 {
549 if (!SvROK(sv) || SvTYPE(SvRV(sv)) != type)
550 {
551 Tcl_Panic("%s not a %u reference %s", key, type, SvPV_nolen(sv));
552 }
553 else
554 {
555 sv = SvRV(sv);
556 }
557 }
558 if (create < 0)
559 {
560 SvREFCNT_inc((SV *) sv);
561 hv_delete(hv, key, len, G_DISCARD);
562 }
563 return sv;
564 }
565 else
566 Tcl_Panic("%s exists but can't be fetched", key);
567 }
568 else if (create > 0)
569 {
570 SV *sv = (*createProc)(aTHX);
571 if (sv)
572 {
573 TagIt(sv,key);
574 if (type >= SVt_PVAV)
575 {
576 hv_store(hv, key, len, MakeReference(sv), 0);
577 }
578 else
579 hv_store(hv, key, len, sv, 0);
580 }
581 return sv;
582 }
583 }
584 return NULL;
585 }
586
587 static SV *
createHV(pTHX)588 createHV(pTHX)
589 {
590 return (SV *) newHV();
591 }
592
593 static HV *
FindHv(pTHX_ HV * hv,char * who,int create,char * key)594 FindHv(pTHX_ HV *hv, char *who, int create, char *key)
595 {
596 return (HV *) FindXv(aTHX_ hv, who, create, key, SVt_PVHV, createHV);
597 }
598
599 static SV *
createAV(pTHX)600 createAV(pTHX)
601 {
602 return (SV *) newAV();
603 }
604
605 static AV *
FindAv(pTHX_ HV * hv,char * who,int create,char * key)606 FindAv(pTHX_ HV *hv, char *who, int create, char *key)
607 {
608 return (AV *) FindXv(aTHX_ hv, who, create, key, SVt_PVAV, createAV);
609 }
610
611 static SV *
createSV(pTHX)612 createSV(pTHX)
613 {
614 return newSVsv(&PL_sv_undef);
615 }
616
617 static SV *
FindSv(pTHX_ HV * hv,char * who,int create,char * key)618 FindSv(pTHX_ HV *hv, char *who, int create, char *key)
619 {
620 return FindXv(aTHX_ hv, who, create, key, SVt_NULL, createSV);
621 }
622
623
624 /* Result return handling
625 Use the FindXv scheme to create an SV in the interp.
626 */
627 Tcl_Obj *
Tcl_GetObjResult(interp)628 Tcl_GetObjResult(interp)
629 Tcl_Interp *interp;
630 {
631 dTHX;
632 return FindSv(aTHX_ interp, "Tcl_GetObjResult", 1, "_TK_RESULT_");
633 }
634
635 void
Tcl_ResetResult(interp)636 Tcl_ResetResult(interp)
637 Tcl_Interp *interp;
638 {
639 dTHX;
640 if (InterpHv(interp,0))
641 {
642 /* We delete the entry in the interp.
643 This means we are forever create/delete.
644 Leaving an SV in the interp might be better, as might
645 having Tcl_SetObjResult() which everything now uses
646 just store the SV.
647 */
648 SV *sv = FindSv(aTHX_ interp, "Tcl_ResetResult", -1, "_TK_RESULT_");
649 if (sv)
650 {
651 SvREFCNT_dec(sv);
652 }
653 }
654 }
655
656 void
Tcl_SetObjResult(interp,sv)657 Tcl_SetObjResult(interp, sv)
658 Tcl_Interp *interp;
659 SV *sv;
660 {
661 dTHX;
662 if (InterpHv(interp,0))
663 {
664 SV *result = Tcl_GetObjResult(interp);
665 if (result == sv)
666 {
667 /* Recent Tk does
668 save = Tcl_GetObjResult();
669 Tcl_IncrRefCount(save);
670 ...
671 Tcl_SetObjResult(save);
672 Tcl_DecrRefCount(save);
673 So nothing more to do here.
674 */
675 return;
676 }
677 else
678 {
679 Tcl_ResetResult(interp);
680 SvSetMagicSV(Tcl_GetObjResult(interp), sv);
681 }
682 }
683 /* normal coding in Tk is equivalent to
684 Tcl_SetObjResult(interp,Tcl_NewXxxObj());
685 and then forget about the Tcl_Obj - i.e. ownership
686 is handed to the interp.
687 As we have taken a _copy_ we no longer need the
688 original.
689 */
690 Tcl_DecrRefCount(sv);
691 }
692
693 void
Lang_SetBinaryResult(interp,string,len,freeProc)694 Lang_SetBinaryResult(interp, string, len, freeProc)
695 Tcl_Interp *interp;
696 char *string;
697 int len;
698 Tcl_FreeProc *freeProc;
699 {
700 dTHX;
701 do_watch();
702 if (string)
703 {
704 SV *sv = newSVpv(string, len);
705 Tcl_SetObjResult(interp, sv);
706 if (freeProc != TCL_STATIC && freeProc != TCL_VOLATILE)
707 (*freeProc) (string);
708 }
709 else
710 Tcl_ResetResult(interp);
711 do_watch();
712 }
713
714 void
Tcl_SetResult(interp,string,freeProc)715 Tcl_SetResult(interp, string, freeProc)
716 Tcl_Interp *interp;
717 char *string;
718 Tcl_FreeProc *freeProc;
719 {
720 STRLEN len = (string) ? strlen(string) : 0;
721 Lang_SetBinaryResult(interp, string, len, freeProc);
722 }
723
724 void
Tcl_CallWhenDeleted(interp,proc,clientData)725 Tcl_CallWhenDeleted(interp, proc, clientData)
726 Tcl_Interp *interp;
727 Tcl_InterpDeleteProc *proc;
728 ClientData clientData;
729 {
730 dTHX;
731 HV *hv = InterpHv(interp,1);
732 AV *av = FindAv(aTHX_ interp, "Tcl_CallWhenDeleted", 1, "_When_Deleted_");
733 av_push(av, newSViv(PTR2IV(proc)));
734 av_push(av, newSViv(PTR2IV(clientData)));
735 }
736
XS(XS_Tk__Interp_DESTROY)737 XS(XS_Tk__Interp_DESTROY)
738 {
739 dXSARGS;
740 Tcl_Interp *interp = (Tcl_Interp *) SvRV(ST(0));
741 #if 0
742 fprintf(stderr,"InterpDestroy %ld\n",SvREFCNT((SV *) interp));
743 #endif
744 /* Tk_CheckHash((SV *)interp,NULL); */
745 hv_undef(interp);
746 }
747
748 static void
DeleteInterp(char * cd)749 DeleteInterp(char *cd)
750 {
751 Tcl_Interp *interp = (Tcl_Interp *) cd;
752 dTHX;
753 SV *exiting = FindSv(aTHX_ interp, "DeleteInterp", -1, "_TK_EXIT_");
754 AV *av = FindAv(aTHX_ interp, "DeleteInterp", -1, "_When_Deleted_");
755 HV *hv = FindHv(aTHX_ interp, "DeleteInterp", -1, ASSOC_KEY);
756 if (av)
757 {
758 while (av_len(av) > 0)
759 {
760 SV *cd = av_pop(av);
761 SV *pr = av_pop(av);
762 Tcl_InterpDeleteProc *proc = INT2PTR(Tcl_InterpDeleteProc *, SvIV(pr));
763 ClientData clientData = INT2PTR(ClientData, SvIV(cd));
764 (*proc) (clientData, interp);
765 SvREFCNT_dec(cd);
766 SvREFCNT_dec(pr);
767 }
768 SvREFCNT_dec((SV *) av);
769 }
770 if (hv)
771 {HE *he;
772 /* Tk_CheckHash((SV *)hv,NULL); */
773 hv_iterinit(hv);
774 while ((he = hv_iternext(hv)))
775 {
776 STRLEN sz;
777 SV *val = hv_iterval(hv,he);
778 Assoc_t *info = (Assoc_t *) SvPV(val,sz);
779 if (sz != sizeof(*info))
780 croak("%s corrupted",ASSOC_KEY);
781 if (info->proc)
782 (*info->proc)(info->clientData, interp);
783 }
784 hv_undef(hv);
785 }
786 DecInterp(interp, "DeleteInterp");
787 if (exiting)
788 {
789 sv_2mortal(exiting);
790 my_exit(SvIV(exiting));
791 }
792 }
793
794 int
Tcl_InterpDeleted(Tcl_Interp * interp)795 Tcl_InterpDeleted(Tcl_Interp *interp)
796 {
797 dTHX;
798 SV *sv = FindSv(aTHX_ interp, "Tcl_InterpDeleted", 0, "_DELETED_");
799 if (sv)
800 {
801 return SvTRUE(sv);
802 }
803 return 0;
804 }
805
806 void
Tcl_DeleteInterp(interp)807 Tcl_DeleteInterp(interp)
808 Tcl_Interp *interp;
809 {
810 dTHX;
811 SV *del = FindSv(aTHX_ interp, "Tcl_DeleteInterp", 1, "_DELETED_");
812 sv_setiv(del,1);
813 Tcl_EventuallyFree((ClientData) interp, DeleteInterp);
814 }
815
816 /*
817 * We just deleted the last window in the application. Delete
818 * the TkMainInfo structure too and replace all of Tk's commands
819 * with dummy commands that return errors (except don't replace
820 * the "exit" command, since it may be needed for the application
821 * to exit).
822 */
823
824 void
Lang_DeadMainWindow(interp,tkwin)825 Lang_DeadMainWindow(interp,tkwin)
826 Tcl_Interp *interp;
827 Tk_Window tkwin;
828 {
829 dTHX;
830 HV *hv = InterpHv(interp,1);
831 HV *fonts = FindHv(aTHX_ interp, "Lang_DeadMainWindow", 0, FONTS_KEY);
832 Display *dpy = Tk_Display(tkwin);
833 STRLEN na;
834 if (dpy)
835 XSync(dpy,FALSE);
836 if (0 && fonts)
837 {HE *he;
838 hv_iterinit(fonts);
839 while ((he = hv_iternext(fonts)))
840 {
841 SV *val = hv_iterval(fonts,he);
842 Lang_CmdInfo *info = WindowCommand(val,NULL,0);
843 if (info && info->tkfont)
844 {
845 Tk_FreeFont(info->tkfont);
846 info->tkfont = NULL;
847 }
848 }
849 /* Tk_CheckHash((SV *)fonts,NULL); */
850 hv_undef(fonts);
851 }
852 sv_unmagic((SV *) hv, PERL_MAGIC_ext);
853 Tcl_DeleteInterp(interp);
854
855 #ifdef sync_locale
856 /* Restore normal locale handling (see the switch_to_global_locale call
857 * elsewhere in this file) */
858 sync_locale();
859 #endif
860
861 }
862
863 static SV *
struct_sv(ptr,sz)864 struct_sv(ptr,sz)
865 void *ptr;
866 STRLEN sz;
867 {
868 dTHX;
869 SV *sv = (ptr) ? newSVpv((char *) ptr, sz) : newSV(sz);
870 if (ptr)
871 {
872 SvREADONLY_on(sv);
873 }
874 else
875 {
876 Zero(SvPVX(sv),sz+1,char);
877 SvCUR_set(sv,sz);
878 SvPOK_only(sv);
879 }
880 return sv;
881 }
882
883 static int
TkGlue_mgFree(pTHX_ SV * sv,MAGIC * mg)884 TkGlue_mgFree(pTHX_ SV *sv, MAGIC *mg)
885 {
886 STRLEN na;
887 return 0;
888 }
889
890 MGVTBL TkGlue_vtab = {
891 NULL,
892 NULL,
893 NULL,
894 NULL,
895 TkGlue_mgFree
896 };
897
898 static SV *
tilde_magic(hv,sv)899 tilde_magic(hv,sv)
900 SV *hv;
901 SV *sv;
902 {
903 dTHX;
904 MAGIC *mg;
905 sv_magic(hv, sv, PERL_MAGIC_ext, NULL, 0);
906 SvRMAGICAL_off(hv);
907 mg = mg_find(hv, PERL_MAGIC_ext);
908 if (mg->mg_obj != sv)
909 abort();
910 mg->mg_virtual = &TkGlue_vtab;
911 mg_magical(hv);
912 return sv;
913 }
914
915 #define mSVPV(sv,na) (SvOK(sv) ? SvPV(sv,na) : "undef")
916
917 void
LangDumpVec(CONST char * who,int count,SV ** data)918 LangDumpVec(CONST char *who, int count, SV **data)
919 {
920 dTHX;
921 int i;
922 PerlIO_printf(PerlIO_stderr(), "%s (%d):\n", who, count);
923 for (i = 0; i < count; i++)
924 {
925 SV *sv = data[i];
926 if (sv)
927 {
928 PerlIO_printf(PerlIO_stderr(), "%2d ", i);
929 LangPrint(sv);
930 sv_dump(sv);
931 }
932 }
933 if (SvTRUE(get_sv("Tk::_AbortOnLangDump",0)))
934 {
935 abort();
936 }
937 }
938
939 void
DumpStack(CONST char * who)940 DumpStack(CONST char *who)
941 {
942 dTHX;
943 do_watch();
944 LangDumpVec(who, PL_stack_sp - PL_stack_base, PL_stack_base + 1);
945 }
946
947 void
LangSetString(sp,s)948 LangSetString(sp, s)
949 SV **sp;
950 CONST char *s;
951 {
952 dTHX;
953 SV *sv = *sp;
954 do_watch();
955 if (!s)
956 {
957 /* tkOldConfig uses LangSetString when TK_CONFIG_NULL_OK is _NOT_ set
958 we must set something.
959 */
960 s = "";
961 }
962 if (sv)
963 {
964 sv_setpv(sv, s);
965 SvSETMAGIC(sv_maybe_utf8(sv));
966 return;
967 }
968 *sp = Tcl_NewStringObj(s, -1);
969 }
970
971 void
LangSetDefault(sp,s)972 LangSetDefault(sp, s)
973 SV **sp;
974 CONST char *s;
975 {
976 dTHX;
977 SV *sv = *sp;
978 do_watch();
979 if (sv)
980 {
981 if (!s || !*s || SvREADONLY(sv))
982 {
983 Decrement(sv, "LangSetDefault");
984 }
985 else
986 {
987 if (s && *s)
988 {
989 sv_setpv(sv, s);
990 SvSETMAGIC(sv);
991 return;
992 }
993 }
994 }
995 *sp = sv = (s && *s) ? TagIt(newSVpv(s, strlen(s)),"LangSetDefault") : &PL_sv_undef;
996 }
997
998 void
LangSetObj(sp,arg)999 LangSetObj(sp, arg)
1000 SV **sp;
1001 SV *arg;
1002 {
1003 dTHX;
1004 SV *sv = *sp;
1005 do_watch();
1006 if (!arg)
1007 arg = &PL_sv_undef;
1008 if (SvTYPE(arg) == SVt_PVAV)
1009 arg = newRV_noinc(arg);
1010 if (sv && SvMAGICAL(sv))
1011 {
1012 SvSetMagicSV(sv, arg);
1013 SvREFCNT_dec(arg);
1014 }
1015 else
1016 {
1017 *sp = arg;
1018 if (sv)
1019 SvREFCNT_dec(sv);
1020 }
1021 }
1022
1023 static void
Deprecated(char * what,char * file,int line)1024 Deprecated(char *what, char *file, int line)
1025 {
1026 LangDebug("%s:%d: %s is deprecated\n",file,line,what);
1027 }
1028
1029 void
LangOldSetArg(sp,arg,file,line)1030 LangOldSetArg(sp, arg, file, line)
1031 SV **sp;
1032 SV *arg;
1033 char *file;
1034 int line;
1035 {
1036 dTHX;
1037 Deprecated("LangSetArg",file,line);
1038 LangSetObj(sp,(arg) ? SvREFCNT_inc(arg) : arg);
1039 }
1040
1041 /* This replaces LangSetArg(sp,LangVarArg(var)) which leaked RVs */
1042 void
LangSetVar(sp,sv)1043 LangSetVar(sp,sv)
1044 SV **sp;
1045 Var sv;
1046 {
1047 dTHX;
1048 if (sv)
1049 {
1050 SV *rv = newRV(sv);
1051 LangSetObj(sp,rv);
1052 }
1053 else
1054 LangSetObj(sp,NULL);
1055 }
1056
1057 void
LangSetInt(sp,v)1058 LangSetInt(sp, v)
1059 SV **sp;
1060 int v;
1061 {
1062 dTHX;
1063 SV *sv = *sp;
1064 do_watch();
1065 if (sv && sv != &PL_sv_undef)
1066 {
1067 sv_setiv(sv, v);
1068 SvSETMAGIC(sv);
1069 }
1070 else
1071 *sp = sv = newSViv(v);
1072 }
1073
1074 void
LangSetDouble(sp,v)1075 LangSetDouble(sp, v)
1076 SV **sp;
1077 double v;
1078 {
1079 dTHX;
1080 SV *sv = *sp;
1081 do_watch();
1082 if (sv && sv != &PL_sv_undef)
1083 {
1084 sv_setnv(sv, v);
1085 SvSETMAGIC(sv);
1086 }
1087 else
1088 *sp = sv = newSVnv(v);
1089 }
1090
1091 static void
die_with_trace(SV * sv,char * msg)1092 die_with_trace(SV *sv,char *msg)
1093 {
1094 dTHX;
1095 dSP;
1096 if (!sv)
1097 {
1098 sv = newSVpv("Tk",2);
1099 }
1100 ENTER;
1101 SAVETMPS;
1102 PUSHMARK(sp);
1103 XPUSHs(sv);
1104 XPUSHs(sv_2mortal(newSVpv(msg,0)));
1105 PUTBACK;
1106 perl_call_method("die_with_trace",G_VOID);
1107 FREETMPS;
1108 LEAVE;
1109 }
1110
1111 Lang_CmdInfo *
WindowCommand(sv,hv_ptr,need)1112 WindowCommand(sv, hv_ptr, need)
1113 SV *sv;
1114 HV **hv_ptr;
1115 int need;
1116 {
1117 dTHX;
1118 STRLEN na;
1119 char *msg = "not a Tk object";
1120 if (SvROK(sv))
1121 {
1122 HV *hash = (HV *) SvRV(sv);
1123 MAGIC *mg = mg_find((SV *) hash,PERL_MAGIC_ext);
1124 if (hv_ptr)
1125 *hv_ptr = hash;
1126 if (mg)
1127 {
1128 Lang_CmdInfo *info = (Lang_CmdInfo *) SvPV(mg->mg_obj,na);
1129 if (info)
1130 {
1131 if ((need & 1) && !info->interp)
1132 croak("%s is not a Tk object",SvPV(sv,na));
1133 if ((need & 2) && !info->tkwin)
1134 croak("WindowCommand:%s is not a Tk Window",SvPV(sv,na));
1135 if ((need & 4) && !info->image)
1136 croak("%s is not a Tk Image",SvPV(sv,na));
1137 if ((need & 8) && !info->tkfont)
1138 croak("%s is not a Tk Font",SvPV(sv,na));
1139 return info;
1140 }
1141 }
1142 }
1143 else
1144 msg = "not a reference";
1145 if (need) /* Cannot always do this - after() does this a lot ! */
1146 {
1147 die_with_trace(sv,msg);
1148 }
1149 return NULL;
1150 }
1151
1152
1153
1154 Tk_Window
SVtoWindow(sv)1155 SVtoWindow(sv)
1156 SV *sv;
1157 {
1158 Lang_CmdInfo *info = WindowCommand(sv, NULL, 2);
1159 if (info && info->tkwin)
1160 return info->tkwin;
1161 return NULL;
1162 }
1163
1164 HWND
SVtoHWND(sv)1165 SVtoHWND(sv)
1166 SV *sv;
1167 {
1168 Tk_Window tkwin = SVtoWindow(sv);
1169 if (tkwin)
1170 {
1171 #ifdef WIN32
1172 Tk_MakeWindowExist(tkwin);
1173 return Tk_GetHWND(Tk_WindowId(tkwin));
1174 #endif
1175 }
1176 return NULL;
1177 }
1178
1179 void
1180 #ifdef STANDARD_C
Tcl_SprintfResult(Tcl_Interp * interp,char * fmt,...)1181 Tcl_SprintfResult(Tcl_Interp * interp, char *fmt,...)
1182 #else
1183 Tcl_SprintfResult(interp, fmt, va_alist)
1184 Tcl_Interp *interp;
1185 char *fmt;
1186 va_dcl
1187 #endif
1188 {
1189 dTHX;
1190 SV *sv = newSVpv("",0);
1191 va_list ap;
1192 #ifdef I_STDARG
1193 va_start(ap, fmt);
1194 #else
1195 va_start(ap);
1196 #endif
1197 sv_vsetpvfn(sv, fmt, strlen(fmt), &ap, Null(SV**), 0, NULL);
1198 Tcl_SetObjResult(interp, sv);
1199 va_end(ap);
1200 }
1201
1202 #ifdef STANDARD_C
1203 void
Tcl_IntResults(Tcl_Interp * interp,int count,int append,...)1204 Tcl_IntResults
1205 _ANSI_ARGS_((Tcl_Interp * interp, int count, int append,...))
1206 #else
1207 /*VARARGS0 */
1208 void
1209 Tcl_IntResults(interp, count, append, va_alist)
1210 Tcl_Interp *interp;
1211 int count;
1212 int append;
1213 va_dcl
1214 #endif
1215 {
1216 dTHX;
1217 va_list ap;
1218 Tcl_Obj *result;
1219 #ifdef I_STDARG
1220 va_start(ap, append);
1221 #else
1222 va_start(ap);
1223 #endif
1224 if (!append)
1225 {
1226 Tcl_ResetResult(interp);
1227 }
1228 result = Tcl_GetObjResult(interp);
1229 if (count == 1 && !append)
1230 abort();
1231 while (count--)
1232 {
1233 int value = va_arg(ap, int);
1234 Tcl_Obj *vObj = Tcl_NewIntObj(value);
1235 Tcl_ListObjAppendElement(interp,result,vObj);
1236 }
1237 va_end(ap);
1238 }
1239
1240 #ifdef STANDARD_C
1241 void
Tcl_DoubleResults(Tcl_Interp * interp,int count,int append,...)1242 Tcl_DoubleResults
1243 _ANSI_ARGS_((Tcl_Interp * interp, int count, int append,...))
1244 #else
1245 void
1246 Tcl_DoubleResults(interp, count, append, va_alist)
1247 Tcl_Interp *interp;
1248 int count;
1249 int append;
1250 va_dcl
1251 #endif
1252 {
1253 dTHX;
1254 va_list ap;
1255 Tcl_Obj *result;
1256 #ifdef I_STDARG
1257 va_start(ap, append);
1258 #else
1259 va_start(ap);
1260 #endif
1261 if (!append)
1262 Tcl_ResetResult(interp);
1263 result = Tcl_GetObjResult(interp);
1264 if (!count)
1265 {
1266 LangDebug("%s - No Results\n",__FUNCTION__);
1267 abort();
1268 Tcl_Panic("No results");
1269 }
1270 while (count--)
1271 {
1272 double value = va_arg(ap, double);
1273 Tcl_ListObjAppendElement(interp,result,Tcl_NewDoubleObj(value));
1274 }
1275 va_end(ap);
1276 }
1277
1278
1279 #ifdef STANDARD_C
1280 void
Tcl_AppendResult(Tcl_Interp * interp,...)1281 Tcl_AppendResult
1282 _ANSI_ARGS_((Tcl_Interp * interp,...))
1283 #else
1284 void
1285 Tcl_AppendResult(interp, va_alist)
1286 Tcl_Interp *interp;
1287 va_dcl
1288 #endif
1289 {
1290 SV *result = Tcl_GetObjResult(interp);
1291 va_list ap;
1292 char *s;
1293 #ifdef I_STDARG
1294 va_start(ap, interp);
1295 #else
1296 va_start(ap);
1297 #endif
1298 while ((s = va_arg(ap, char *)))
1299 {
1300 Tcl_AppendStringsToObj(result,s, NULL);
1301 }
1302 va_end(ap);
1303 }
1304
1305 SV *
ObjectRef(interp,path)1306 ObjectRef(interp, path)
1307 Tcl_Interp *interp;
1308 char *path;
1309 {
1310 dTHX;
1311 if (path)
1312 {
1313 HV *hv = InterpHv(interp,1);
1314 SV **x = hv_fetch(hv, path, strlen(path), 0);
1315 if (x)
1316 return *x;
1317 }
1318 return &PL_sv_undef;
1319 }
1320
1321 SV *
WidgetRef(interp,path)1322 WidgetRef(interp, path)
1323 Tcl_Interp *interp;
1324 char *path;
1325 {
1326 dTHX;
1327 HV *hv = InterpHv(interp,1);
1328 SV **x = hv_fetch(hv, path, strlen(path), 0);
1329 if (x)
1330 {
1331 SV *w = *x;
1332 if (SvROK(w) && SvTYPE(SvRV(w)) == SVt_PVHV)
1333 return w;
1334 LangDumpVec(path,1,&w);
1335 abort();
1336 }
1337 return &PL_sv_undef;
1338 }
1339
1340 SV *
TkToWidget(tkwin,pinterp)1341 TkToWidget(tkwin,pinterp)
1342 Tk_Window tkwin;
1343 Tcl_Interp **pinterp;
1344 {
1345 dTHX;
1346 Tcl_Interp *junk;
1347 if (!pinterp)
1348 pinterp = &junk;
1349 *pinterp = NULL;
1350 if (tkwin)
1351 {
1352 TkWindow *winPtr = (TkWindow *) tkwin;
1353 TkMainInfo *mainInfo = winPtr->mainPtr;
1354 if (mainInfo)
1355 {
1356 Tcl_Interp *interp = mainInfo->interp;
1357 if (interp)
1358 {
1359 *pinterp = interp;
1360 if (Tk_PathName(tkwin))
1361 return WidgetRef(interp, Tk_PathName(tkwin));
1362 }
1363 }
1364 }
1365 return &PL_sv_undef;
1366 }
1367
1368
1369 Tk_Window
TkToMainWindow(tkwin)1370 TkToMainWindow(tkwin)
1371 Tk_Window tkwin;
1372 {
1373 if (tkwin)
1374 {
1375 TkWindow *winPtr = (TkWindow *) tkwin;
1376 TkMainInfo *mainInfo = winPtr->mainPtr;
1377 if (mainInfo)
1378 {
1379 return (Tk_Window) mainInfo->winPtr;
1380 }
1381 }
1382 return NULL;
1383 }
1384
1385 Tcl_Obj *
LangWidgetObj(interp,tkwin)1386 LangWidgetObj(interp, tkwin)
1387 Tcl_Interp *interp;
1388 Tk_Window tkwin;
1389 {
1390 dTHX;
1391 return SvREFCNT_inc(TkToWidget(tkwin,NULL));
1392 }
1393
1394 Tcl_Obj *
LangObjectObj(interp,name)1395 LangObjectObj(interp, name)
1396 Tcl_Interp *interp;
1397 char *name;
1398 {
1399 dTHX;
1400 return SvREFCNT_inc(ObjectRef(interp, name));
1401 }
1402
1403 Tk_Font
SVtoFont(SV * sv)1404 SVtoFont(SV *sv)
1405 {
1406 dTHX;
1407 if (sv_isobject(sv) && SvPOK(SvRV(sv)))
1408 {
1409 Lang_CmdInfo *info = WindowCommand(sv, (HV **) &sv, 0);
1410 if (info)
1411 {
1412 if (!info->tkfont && info->interp)
1413 {
1414 Tk_Window tkwin = Tk_MainWindow(info->interp);
1415 if (tkwin)
1416 info->tkfont = Tk_GetFontFromObj(tkwin, sv);
1417 }
1418 if (info->tkfont)
1419 {
1420 STRLEN len;
1421 CONST char *s = Tk_NameOfFont(info->tkfont);
1422 if (strcmp(s,SvPV(sv,len)) != 0)
1423 {
1424 croak("Font %p name '%s' string '%s'",info->tkfont,s,SvPV(sv,len));
1425 }
1426 }
1427 return info->tkfont;
1428 }
1429 }
1430 return NULL;
1431 }
1432
1433 Tcl_Obj *
LangFontObj(interp,tkfont,name)1434 LangFontObj(interp, tkfont, name)
1435 Tcl_Interp *interp;
1436 Tk_Font tkfont;
1437 char *name;
1438 {
1439 dTHX;
1440 HV *fonts = FindHv(aTHX_ interp, "LangFontArg", 1, FONTS_KEY);
1441 STRLEN na;
1442 SV *sv;
1443 SV **x;
1444 if (!name)
1445 name = (char *) Tk_NameOfFont(tkfont);
1446 x = hv_fetch(fonts, name, strlen(name), 0);
1447 if (x)
1448 {
1449 sv = *x;
1450 }
1451 else
1452 {
1453 Tk_Window tkwin = Tk_MainWindow(interp);
1454 Lang_CmdInfo info;
1455 SV *isv;
1456 sv = newSVpv(name,0);
1457 memset(&info,0,sizeof(info));
1458 info.interp = interp;
1459 info.tkfont = tkfont;
1460 IncInterp(interp,name);
1461 isv = struct_sv(&info,sizeof(info));
1462 tilde_magic(sv, isv);
1463 sv = Blessed("Tk::Font", MakeReference(sv));
1464 hv_store(fonts, name, strlen(name), sv, 0);
1465 }
1466 return SvREFCNT_inc(sv);
1467 }
1468
1469 void
Font_DESTROY(SV * arg)1470 Font_DESTROY(SV *arg)
1471 {
1472 dTHX;
1473 STRLEN na;
1474 SV *sv;
1475 Lang_CmdInfo *info = WindowCommand(arg,(HV **) &sv,0);
1476 if (info)
1477 {
1478 if (info->interp)
1479 DecInterp(info->interp,SvPV(sv,na));
1480 sv_unmagic(sv,PERL_MAGIC_ext);
1481 }
1482 }
1483
1484 static void
Lang_ClearErrorInfo(interp)1485 Lang_ClearErrorInfo(interp)
1486 Tcl_Interp *interp;
1487 {
1488 dTHX;
1489 AV *av = FindAv(aTHX_ interp, "Lang_ClearErrorInfo", -1, "_ErrorInfo_");
1490 if (av)
1491 {
1492 SvREFCNT_dec((SV *) av);
1493 }
1494 }
1495
1496 void
Tcl_AddErrorInfo(interp,message)1497 Tcl_AddErrorInfo(interp, message)
1498 Tcl_Interp *interp;
1499 CONST char *message;
1500 {
1501 dTHX;
1502 if (InterpHv(interp,0))
1503 {
1504 AV *av = FindAv(aTHX_ interp, "Tcl_AddErrorInfo", 1, "_ErrorInfo_");
1505 SV *sv;
1506 while (isspace(UCHAR(*message)))
1507 message++;
1508 if (*message)
1509 av_push(av,newSVpv((char *)message,0));
1510 }
1511 }
1512
1513 static int
Check_Eval(interp)1514 Check_Eval(interp)
1515 Tcl_Interp *interp;
1516 {
1517 dTHX;
1518 SV *sv = ERRSV;
1519 if (FindSv(aTHX_ interp, "Check_Eval", 0, "_TK_EXIT_"))
1520 return TCL_BREAK;
1521 if (SvTRUE(sv))
1522 {
1523 STRLEN len;
1524 char *s = SvPV(sv, len);
1525 if (!strncmp("_TK_EXIT_(",s,10))
1526 {
1527 Tk_Window tkwin = Tk_MainWindow(interp);
1528 SV *sv = FindSv(aTHX_ interp, "Check_Eval", 1, "_TK_EXIT_");
1529 char *e = strchr(s+=10,')');
1530 sv_setpvn(sv,s,e-s);
1531 if (tkwin)
1532 Tk_DestroyWindow(tkwin);
1533 return TCL_BREAK;
1534 }
1535 else if (!strcmp("_TK_BREAK_\n",s))
1536 {
1537 sv_setpv(sv,"");
1538 return TCL_BREAK;
1539 }
1540 else
1541 {
1542 SV *save = sv_2mortal(newSVsv(sv));
1543 s = SvPV(save, len);
1544 #if 0
1545 LangDebug("%s error:%.*s\n",__FUNCTION__,na,s);
1546 #endif
1547 if (!interp)
1548 croak("%s",s);
1549 Tcl_SetResult(interp, s, TCL_VOLATILE);
1550 sv_setpv(sv,"");
1551 return TCL_ERROR;
1552 }
1553 }
1554 return TCL_OK;
1555 }
1556
1557 static void
Restore_widget(pTHX_ void * arg)1558 Restore_widget(pTHX_ void *arg)
1559 {
1560 SV *widget = (SV *) arg;
1561 SV * sv = GvSV(current_widget);
1562 SvSetMagicSV(sv,widget);
1563 SvREFCNT_dec(widget);
1564 #if 0
1565 LangDumpVec("Restore Tk::widget",1,&sv);
1566 #endif
1567 }
1568
1569 static void
Set_widget(widget)1570 Set_widget(widget)
1571 SV *widget;
1572 {
1573 dTHX;
1574 if (!current_widget)
1575 current_widget = gv_fetchpv("Tk::widget",GV_ADD|GV_ADDWARN, SVt_PV);
1576 if (widget && SvROK(widget))
1577 {
1578 SV * sv = GvSV(current_widget);
1579 /* We used to use save_item() here but that and other
1580 generic perl save routines make assumptions about REFCNT
1581 and magic which we don't obey.
1582 Our REFCNT may be high, and both old an new SVs may have
1583 '~' magic for Tcl_Obj internal stuff.
1584 */
1585 #if 0
1586 LangDumpVec("save Tk::widget",1,&sv);
1587 #endif
1588 save_destructor_x(Restore_widget,LangCopyArg(sv));
1589 SvSetMagicSV(sv,widget);
1590 }
1591 }
1592
1593 static void
Set_event(SV * event)1594 Set_event(SV *event)
1595 {
1596 dTHX;
1597 if (!current_event)
1598 current_event = gv_fetchpv("Tk::event",GV_ADD|GV_ADDWARN, SVt_PV);
1599 if (event && SvROK(event))
1600 {
1601 SV * sv = GvSV(current_event);
1602 save_item(sv);
1603 SvSetMagicSV(sv,event);
1604 }
1605 }
1606
1607 static int
PushObjCallbackArgs(interp,svp,obj)1608 PushObjCallbackArgs(interp, svp ,obj)
1609 Tcl_Interp *interp;
1610 SV **svp;
1611 EventAndKeySym *obj;
1612 {
1613 SV *sv = *svp;
1614 dTHX;
1615 dSP;
1616 STRLEN na;
1617 if (SvTAINTED(sv))
1618 {
1619 croak("Tainted callback %"SVf,sv);
1620 }
1621 if (1 && interp && !sv_isa(sv,"Tk::Callback") && !sv_isa(sv,"Tk::Ev"))
1622 {
1623 return EXPIRE((interp,"Not a Callback '%s'",SvPV(sv,na)));
1624 }
1625 else
1626 {
1627 if (SvROK(sv) && SvTYPE(SvRV(sv)) != SVt_PVCV)
1628 sv = SvRV(sv);
1629 }
1630
1631 PUSHMARK(sp);
1632 if (SvTYPE(sv) == SVt_PVAV)
1633 {
1634 AV *av = (AV *) sv;
1635 int n = av_len(av) + 1;
1636 SV **x = av_fetch(av, 0, 0);
1637 if (n && x)
1638 {
1639 int i = 1;
1640 sv = *x;
1641 if (SvTAINTED(sv))
1642 {
1643 croak("Callback slot 0 tainted %"SVf,sv);
1644 }
1645 /* FIXME:
1646 POE would like window passed to its callback objects
1647 Pending suggestion is:
1648 if ($object->can('_Tk_passWidget') &&
1649 $object->_Tk_passWidget($widget)
1650 {
1651 proceed_as_non_object();
1652 }
1653 */
1654 if (!sv_isobject(sv))
1655 {
1656 if (obj && obj->window) {
1657 XPUSHs(sv_mortalcopy(obj->window));
1658 }
1659 }
1660 for (i = 1; i < n; i++)
1661 {
1662 x = av_fetch(av, i, 0);
1663 if (x)
1664 {SV *arg = *x;
1665 if (SvTAINTED(arg))
1666 {
1667 croak("Callback slot %d tainted %"SVf,i,arg);
1668 }
1669 if (obj && sv_isa(arg,"Tk::Ev"))
1670 {
1671 SV *what = SvRV(arg);
1672 if (SvPOK(what))
1673 {STRLEN len;
1674 char *s = SvPV(what,len);
1675 if (len == 1)
1676 {
1677 PUTBACK;
1678 arg = XEvent_Info(obj, s);
1679 SPAGAIN;
1680 }
1681 else
1682 {char *x;
1683 arg = sv_newmortal();
1684 sv_setpv(arg,"");
1685 while ((x = strchr(s,'%')))
1686 {
1687 if (x > s)
1688 sv_catpvn(arg,s,(unsigned) (x-s));
1689 if (*++x)
1690 {SV *f = XEvent_Info(obj, x++);
1691 STRLEN len;
1692 char *p = SvPV(f,len);
1693 sv_catpvn(arg,p,len);
1694 }
1695 s = x;
1696 }
1697 sv_catpv(arg,s);
1698 }
1699 }
1700 else
1701 {
1702 switch(SvTYPE(what))
1703 {
1704 case SVt_NULL:
1705 arg = &PL_sv_undef;
1706 break;
1707 case SVt_PVAV:
1708 {
1709 int code;
1710 PUTBACK;
1711 if ((code = PushObjCallbackArgs(interp,&arg,obj)) == TCL_OK)
1712 {
1713 int count = LangCallCallback(arg,G_ARRAY|G_EVAL);
1714 if ((code = Check_Eval(interp)) != TCL_OK)
1715 return code;
1716 SPAGAIN;
1717 arg = NULL;
1718 break;
1719 }
1720 else
1721 return code;
1722 }
1723 default:
1724 LangDumpVec("Ev",1,&arg);
1725 LangDumpVec(" ",1,&what);
1726 warn("Unexpected type %d %s",SvTYPE(what),SvPV(arg,na));
1727 arg = sv_mortalcopy(arg);
1728 break;
1729 }
1730 }
1731 if (arg) {
1732 XPUSHs(arg);
1733 }
1734 }
1735 else
1736 XPUSHs(sv_mortalcopy(arg));
1737 }
1738 else
1739 XPUSHs(&PL_sv_undef);
1740 }
1741 }
1742 else
1743 {
1744 if (interp)
1745 {
1746 return EXPIRE((interp,"No 0th element of %s", SvPV(sv, na)));
1747 }
1748 else
1749 sv = &PL_sv_undef;
1750 }
1751 }
1752 else
1753 {
1754 if (obj && obj->window)
1755 XPUSHs(sv_mortalcopy(obj->window));
1756 }
1757 *svp = sv;
1758 PUTBACK;
1759 return TCL_OK;
1760 }
1761
1762 static int
PushCallbackArgs(interp,svp)1763 PushCallbackArgs(interp, svp)
1764 Tcl_Interp *interp;
1765 SV **svp;
1766 {
1767 SV *sv = *svp;
1768 dTHX;
1769 dSP;
1770 if (0 && interp && !sv_isa(sv,"Tk::Callback") && !sv_isa(sv,"Tk::Ev"))
1771 {
1772 return EXPIRE((interp,"Not a Callback '%s'",SvPV_nolen(sv)));
1773 }
1774 LangPushCallbackArgs(svp);
1775 if (interp && (sv = *svp) == &PL_sv_undef)
1776 {
1777 return EXPIRE((interp,"No 0th element of %s", SvPV_nolen(sv)));
1778 }
1779 return TCL_OK;
1780 }
1781
1782 static void
SetTclResult(interp,count)1783 SetTclResult(interp,count)
1784 Tcl_Interp *interp;
1785 int count;
1786 {
1787 dTHX;
1788 dSP;
1789 int offset = count;
1790 Tcl_ResetResult(interp);
1791 if (count)
1792 {
1793 Tcl_Obj *result = Tcl_GetObjResult(interp);
1794 SV **p = sp - count;
1795 if (count > 1)
1796 {
1797 while (count-- > 0)
1798 {
1799 Tcl_ListObjAppendElement(interp, result, newSVsv(*++p));
1800 }
1801 }
1802 else
1803 {
1804 SvSetMagicSV(result,p[1]);
1805 }
1806 }
1807 sp -= offset;
1808 PUTBACK;
1809 }
1810
1811 static void
PushVarArgs(ap,argc)1812 PushVarArgs(ap,argc)
1813 va_list ap;
1814 int argc;
1815 {
1816 dTHX;
1817 dSP;
1818 int i;
1819 char *fmt = va_arg(ap, char *);
1820 char *s = fmt;
1821 unsigned char ch = '\0';
1822 int lng = 0;
1823 for (i = 0; i < argc; i++)
1824 {
1825 s = strchr(s, '%');
1826 if (s)
1827 {
1828 ch = UCHAR(*++s);
1829 lng = 0;
1830 while (isdigit(ch) || ch == '.' || ch == '-' || ch == '+')
1831 ch = *++s;
1832 if (ch == 'l')
1833 {
1834 lng = 1;
1835 ch = *++s;
1836 }
1837 switch (ch)
1838 {
1839 case 'u':
1840 case 'i':
1841 case 'd':
1842 {IV val = (lng) ? va_arg(ap, long) : va_arg(ap, int);
1843 XPUSHs(sv_2mortal(newSViv(val)));
1844 }
1845 break;
1846 case 'g':
1847 case 'e':
1848 case 'f':
1849 XPUSHs(sv_2mortal(newSVnv(va_arg(ap, double))));
1850 break;
1851 case 's':
1852 {
1853 char *x = va_arg(ap, char *);
1854 if (x)
1855 XPUSHs(sv_2mortal(Tcl_NewStringObj(x, -1))); /* for UTF-8-ness */
1856 else
1857 XPUSHs(&PL_sv_undef);
1858 }
1859 break;
1860 case '_':
1861 {
1862 SV *x = va_arg(ap, SV *);
1863 if (x)
1864 XPUSHs(sv_mortalcopy(x));
1865 else
1866 XPUSHs(&PL_sv_undef);
1867 }
1868 break;
1869 case 'L':
1870 {
1871 Tcl_Obj *x = va_arg(ap, Tcl_Obj *);
1872 Tcl_Obj **argv;
1873 int argc;
1874 if (Tcl_ListObjGetElements(NULL,x,&argc,&argv) == TCL_OK)
1875 {
1876 int i;
1877 for (i=0; i < argc; i++)
1878 {
1879 XPUSHs(sv_mortalcopy((SV *) (argv[i])));
1880 }
1881 }
1882 }
1883 break;
1884 default:
1885 croak("Unimplemented format char '%c' in '%s'", ch, fmt);
1886 break;
1887 }
1888 }
1889 else
1890 croak("Not enough %%s (need %d) in '%s'", argc, fmt);
1891 }
1892 if (strchr(s,'%'))
1893 {
1894 croak("Too many %%s (need %d) in '%s'", argc, fmt);
1895 }
1896 PUTBACK;
1897 }
1898
1899
1900
1901 #ifdef STANDARD_C
1902 int
LangDoCallback(Tcl_Interp * interp,LangCallback * sv,int result,int argc,...)1903 LangDoCallback
1904 _ANSI_ARGS_((Tcl_Interp * interp, LangCallback * sv, int result, int argc,...))
1905 #else
1906 int
1907 LangDoCallback(interp, sv, result, argc, va_alist)
1908 Tcl_Interp *interp;
1909 SV *sv;
1910 int result;
1911 int argc;
1912 va_dcl
1913 #endif
1914 {
1915 STRLEN na;
1916 static int flags[3] = { G_DISCARD, G_SCALAR, G_ARRAY };
1917 int count = 0;
1918 int code;
1919 SV *cb = sv;
1920 dTHX;
1921 ENTER;
1922 SAVETMPS;
1923 if (interp)
1924 {
1925 Tcl_ResetResult(interp);
1926 Lang_ClearErrorInfo(interp);
1927 }
1928 code = PushCallbackArgs(interp,&sv);
1929 if (code != TCL_OK)
1930 return code;
1931 if (argc)
1932 {
1933 va_list ap;
1934 #ifdef I_STDARG
1935 va_start(ap, argc);
1936 #else
1937 va_start(ap);
1938 #endif
1939 PushVarArgs(ap,argc);
1940 va_end(ap);
1941 }
1942 count = LangCallCallback(sv, flags[result] | G_EVAL);
1943 if (interp && result)
1944 SetTclResult(interp,count);
1945 FREETMPS;
1946 LEAVE;
1947 count = Check_Eval(interp);
1948 if (count == TCL_ERROR && interp)
1949 {
1950 SV *tmp = newSVpv("", 0);
1951 LangCatArg(tmp,cb,0);
1952 Tcl_AddErrorInfo(interp,SvPV(tmp,na));
1953 SvREFCNT_dec(tmp);
1954 }
1955 return count;
1956 }
1957
1958 static
HandleBgErrors(clientData)1959 void HandleBgErrors(clientData)
1960 ClientData clientData;
1961 {
1962 dTHX;
1963 Tcl_Interp *interp = (Tcl_Interp *) clientData;
1964 AV *pend = FindAv(aTHX_ interp, "HandleBgErrors", 0, "_PendingErrors_");
1965 ENTER;
1966 SAVETMPS;
1967 TAINT_NOT;
1968 if (pend)
1969 {
1970 Set_widget( WidgetRef(interp,"."));
1971 while (av_len(pend) >= 0)
1972 {
1973 SV *sv = av_shift(pend);
1974 if (sv && SvOK(sv))
1975 {
1976 int result = PushCallbackArgs(interp,&sv);
1977 if (result == TCL_OK)
1978 {
1979 LangCallCallback(sv, G_DISCARD | G_EVAL);
1980 result = Check_Eval(interp);
1981 }
1982 if (result == TCL_BREAK)
1983 break;
1984 else if (result == TCL_ERROR)
1985 {
1986 warn("Background Error: %s",Tcl_GetStringResult(interp));
1987 }
1988 }
1989 }
1990 av_clear(pend);
1991 }
1992 FREETMPS;
1993 LEAVE;
1994 Tcl_ResetResult(interp);
1995 DecInterp(interp,"HandleBgErrors");
1996 }
1997
1998 void
Tcl_BackgroundError(interp)1999 Tcl_BackgroundError(interp)
2000 Tcl_Interp *interp;
2001 {
2002 dTHX;
2003 int old_taint = PL_tainted;
2004 TAINT_NOT;
2005 #if 0
2006 warn(__FUNCTION__);
2007 #endif
2008 if (InterpHv(interp,0))
2009 {
2010 AV *pend = FindAv(aTHX_ interp, "Tcl_BackgroundError", 1, "_PendingErrors_");
2011 AV *av = FindAv(aTHX_ interp, "Tcl_BackgroundError", -1, "_ErrorInfo_");
2012 SV *obj = WidgetRef(interp,".");
2013 if (obj && SvROK(obj))
2014 obj = SvREFCNT_inc(obj);
2015 else
2016 obj = newSVpv(BASEEXT,0);
2017 if (!av)
2018 {
2019 av = newAV();
2020 TagIt((SV *) av, "Tcl_BackgroundError");
2021 }
2022 av_unshift(av,3);
2023 av_store(av, 0, newSVpv("Tk::Error",0));
2024 av_store(av, 1, obj);
2025 av_store(av, 2, newSVpv(Tcl_GetStringResult(interp),0));
2026 av_push( pend, LangMakeCallback(MakeReference((SV *) av)));
2027 if (av_len(pend) <= 0)
2028 {
2029 /* 1st one - setup callback */
2030 IncInterp(interp,"Tk_BackgroundError");
2031 Tcl_DoWhenIdle(HandleBgErrors, (ClientData) interp);
2032 }
2033 Tcl_ResetResult(interp);
2034 }
2035 TAINT_IF(old_taint);
2036 }
2037
2038 static void
Lang_MaybeError(interp,code,why)2039 Lang_MaybeError(interp,code,why)
2040 Tcl_Interp *interp;
2041 int code;
2042 char *why;
2043 {
2044 if (code != TCL_OK)
2045 {
2046 Tcl_AddErrorInfo(interp,why);
2047 Tcl_BackgroundError(interp);
2048 }
2049 else
2050 Lang_ClearErrorInfo(interp);
2051 }
2052
2053 void
ClearErrorInfo(win)2054 ClearErrorInfo(win)
2055 SV *win;
2056 {Lang_CmdInfo *info = WindowCommand(win,NULL,1);
2057 Lang_ClearErrorInfo(info->interp);
2058 }
2059
2060
2061 static int
Return_Object(int items,int offset,Tcl_Obj * sv)2062 Return_Object(int items, int offset, Tcl_Obj *sv)
2063 {
2064 dTHX;
2065 int gimme = GIMME_V;
2066 int count = 0;
2067 int i;
2068 SV **objv = NULL;
2069 SV **args = NULL;
2070 /* Get stack as it is now */
2071 dSP;
2072 switch(gimme)
2073 {
2074 case G_VOID :
2075 count = 0;
2076 objv = NULL;
2077 break;
2078 case G_ARRAY:
2079 if (!SvOK(sv))
2080 {
2081 count = 0;
2082 break;
2083 }
2084 else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV &&
2085 !SvMAGICAL(sv) && !sv_isobject(sv))
2086 {
2087 Tcl_ListObjGetElements(NULL,sv,&count,&objv);
2088 break;
2089 }
2090 else
2091 {
2092 /* warn("Special obj in list context"); */
2093 }
2094 default:
2095 count = 1;
2096 objv = &sv;
2097 #if 0
2098 /* Breaks Canvas group members return */
2099 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV && !sv_isobject(sv))
2100 {
2101 if (av_len((AV *)SvRV(sv)) == 0)
2102 {
2103 die_with_trace(NULL,"One element array in scalar context");
2104 objv = av_fetch((AV *)SvRV(sv),0,0);
2105 }
2106 }
2107 #endif
2108 break;
2109 }
2110 SPAGAIN;
2111 if (count > items)
2112 {
2113 EXTEND(sp, (count - items));
2114 }
2115 /* Now move 'args' to 0'th arg position in current stack */
2116 args = sp + offset;
2117 for (i = count-1; i >= 0; i--)
2118 {
2119 args[i] = sv_mortalcopy(objv[i]);
2120 }
2121 /* Copy stack pointer back to global */
2122 PUTBACK;
2123 return count;
2124 }
2125
2126 static int
Return_Results(Tcl_Interp * interp,int items,int offset)2127 Return_Results(Tcl_Interp *interp,int items, int offset)
2128 {
2129 Tcl_Obj *result = Tcl_GetObjResult(interp);
2130 int count = Return_Object(items,offset,result);
2131 Tcl_ResetResult(interp);
2132 return count;
2133 }
2134
2135 static void
Lang_TaintCheck(char * s,int items,SV ** args)2136 Lang_TaintCheck(char *s, int items, SV **args)
2137 {
2138 dTHX;
2139 if (PL_tainting)
2140 {
2141 int i;
2142 for (i=0; i < items; i++)
2143 {
2144 if (SvTAINTED(args[i]))
2145 croak("Tcl_Obj * %d to `%s' (%"SVf") is tainted",i,s,args[i]);
2146 }
2147 }
2148 }
2149
2150 struct pTkCheckChain
2151 {
2152 struct pTkCheckChain *link;
2153 SV *sv;
2154 };
2155
2156 void
Tk_CheckHash(SV * sv,struct pTkCheckChain * tail)2157 Tk_CheckHash(SV *sv,struct pTkCheckChain *tail)
2158 {
2159 dTHX;
2160 struct pTkCheckChain chain;
2161 HE *he;
2162 HV *hv;
2163 SV **svp;
2164 if (SvROK(sv))
2165 sv = SvRV(sv);
2166 chain.link = tail;
2167 chain.sv = sv;
2168 if (SvTYPE(sv) != SVt_PVHV)
2169 return;
2170 hv = (HV *) sv;
2171 hv_iterinit(hv);
2172 while ((he = hv_iternext(hv)))
2173 {
2174 SV *val = hv_iterval(hv,he);
2175 if (val)
2176 {
2177 if (SvREFCNT(val) <= 0)
2178 {I32 len;
2179 char *key = hv_iterkey(he,&len);
2180 LangDebug("%.*s has 0 REFCNT\n",(int) len, key);
2181 sv_dump((SV *)hv);
2182 abort();
2183 }
2184 else
2185 {
2186 if (SvROK(val))
2187 val = SvRV(val);
2188 if (SvTYPE((SV *) val) == SVt_PVHV /* && SvOBJECT(val) */)
2189 {
2190 struct pTkCheckChain *p = &chain;
2191 I32 len;
2192 while (p)
2193 {
2194 if (p->sv == val)
2195 {I32 len;
2196 char *key = hv_iterkey(he,&len);
2197 LangDebug("Check Loop %.*s %p - %p\n",(int) len, key, hv, val);
2198 goto skip;
2199 }
2200 p = p->link;
2201 }
2202 /* LangDebug("Check %p{%s}\n",hv,hv_iterkey(he,&len)); */
2203 Tk_CheckHash(val,&chain);
2204 skip:
2205 /* do nothing */;
2206 }
2207 }
2208 }
2209 }
2210 }
2211
2212 int
Call_Tk(info,items,args)2213 Call_Tk(info, items, args)
2214 Lang_CmdInfo *info;
2215 int items;
2216 SV **args;
2217 {
2218 int count = 1;
2219 STRLEN na;
2220 if (info)
2221 {
2222 dTHX;
2223 dSP;
2224 SV *what = SvREFCNT_inc(args[0]);
2225 SV *exiting;
2226 Tcl_Interp *interp = info->interp;
2227 int old_taint = PL_tainted;
2228 IncInterp(interp,"Call_Tk");
2229 PL_tainted = 0;
2230 do_watch();
2231
2232 Tcl_ResetResult(interp);
2233 if (info->Tk.proc || info->Tk.objProc)
2234 {
2235 int i;
2236 /* Must find offset of 0'th arg now in case
2237 stack moves as a result of the call
2238 */
2239 int offset = args - sp;
2240 int code;
2241 SV **our_sp = sp;
2242
2243 Tcl_ObjCmdProc *proc = info->Tk.objProc;
2244 ClientData cd = info->Tk.objClientData;
2245
2246 if (!proc)
2247 {
2248 proc = (Tcl_ObjCmdProc *) (info->Tk.proc);
2249 cd = info->Tk.clientData;
2250 }
2251 if (PL_tainting)
2252 {
2253 Lang_TaintCheck(Tcl_GetString(args[0]),items, args);
2254 }
2255 for (i=0; i < items; i++)
2256 {
2257 if (SvPOK(args[i]))
2258 Tcl_GetString(args[i]);
2259 }
2260
2261 Tcl_Preserve(interp);
2262
2263 /* BEWARE if Tk code does a callback to perl and perl grows the
2264 stack then args that Tk code has will still point at old stack.
2265 Thus if Tk tests args[i] *after* the callback it will get junk.
2266 (Note it is only vector that is at risk, SVs themselves will stay put.)
2267
2268 So we pre-emptively swap perl stack so any callbacks
2269 which grow their stack don't move our "args"
2270 */
2271 ENTER;
2272 SAVETMPS;
2273 SPAGAIN;
2274 PUSHSTACK;
2275 PUTBACK;
2276
2277 code = (*proc) (cd, interp, items, args);
2278
2279 POPSTACK;
2280 SPAGAIN;
2281 FREETMPS;
2282 LEAVE;
2283
2284 if (sp != our_sp)
2285 abort();
2286
2287 Tcl_Release(interp);
2288
2289 /* info stucture may have been free'ed now ... */
2290 #ifdef WIN32
2291 if (DCcount)
2292 {
2293 warn("DCcount %ld for %s",DCcount, Tcl_GetString(what));
2294 // LangDumpVec("DCcount",items,args);
2295 DCcount = 0;
2296 }
2297 #endif
2298 if ((exiting = FindSv(aTHX_ interp, "Check_Eval", 0, "_TK_EXIT_")))
2299 {
2300 PL_tainted = old_taint;
2301 DecInterp(interp, "Call_Tk");
2302 SvREFCNT_dec(what);
2303 TclpExit(SvIV(exiting));
2304 }
2305 else if (code == TCL_OK)
2306 {
2307 count = Return_Results(interp,items,offset);
2308 }
2309 else if (code == TCL_BREAK)
2310 {
2311 PL_tainted = old_taint;
2312 DecInterp(interp, "Call_Tk");
2313 SvREFCNT_dec(what);
2314 croak("_TK_BREAK_\n");
2315 }
2316 else
2317 {
2318 SV *msg = sv_newmortal();
2319 sv_setpv(msg,"Tk callback for ");
2320 sv_catpv(msg,Tcl_GetString(what));
2321 Tcl_AddErrorInfo(interp, SvPV(msg,na));
2322 sv_setpv(msg,Tcl_GetStringResult(interp));
2323
2324 PL_tainted = old_taint;
2325 DecInterp(interp, "Call_Tk");
2326 SvREFCNT_dec(what);
2327 croak("%s",SvPV(msg,na));
2328 }
2329 }
2330 else
2331 {
2332 /* call after DeleteWidget */
2333 if (info->tkwin)
2334 croak("%s has been deleted",Tk_PathName(info->tkwin));
2335 }
2336 PL_tainted = old_taint;
2337 DecInterp(interp, "Call_Tk");
2338 SvREFCNT_dec(what);
2339 }
2340 else
2341 {
2342 /* Could be an "after" when mainwindow has been destroyed */
2343 }
2344 do_watch();
2345 return count;
2346 }
2347
2348 static void
InitVtabs(void)2349 InitVtabs(void)
2350 {
2351 dTHX;
2352 /* Called by Boot_Glue below, re-called in 5.004_50+ at start of run phase.
2353 * If we have been "Compiled" then module this code is defined in
2354 * will have been re-linked, so the 'static' above will be 0 again
2355 * which will cause us to re-set vtables with addresses where
2356 * we happen to be loaded now, as opposed to where we were loaded
2357 * at compile time.
2358 */
2359 if (!initialized)
2360 {
2361 IMPORT_EVENT;
2362 install_vtab("LangVtab",LangVGet(),sizeof(LangVtab));
2363 install_vtab("TcldeclsVtab",TcldeclsVGet(),sizeof(TcldeclsVtab));
2364 install_vtab("TkVtab",TkVGet(),sizeof(TkVtab));
2365 install_vtab("TkdeclsVtab",TkdeclsVGet(),sizeof(TkdeclsVtab));
2366 install_vtab("TkglueVtab",TkglueVGet(),sizeof(TkglueVtab));
2367 install_vtab("TkintVtab",TkintVGet(),sizeof(TkintVtab));
2368 install_vtab("TkintdeclsVtab",TkintdeclsVGet(),sizeof(TkintdeclsVtab));
2369 install_vtab("TkoptionVtab",TkoptionVGet(),sizeof(TkoptionVtab));
2370 install_vtab("TkimgphotoVtab",TkimgphotoVGet(),sizeof(TkimgphotoVtab));
2371 install_vtab("ImgintVtab",ImgintVGet(),sizeof(ImgintVtab));
2372 #ifdef WIN32
2373 install_vtab("TkintplatdeclsVtab",TkintplatdeclsVGet(),sizeof(TkintplatdeclsVtab));
2374 install_vtab("TkplatdeclsVtab",TkplatdeclsVGet(),sizeof(TkplatdeclsVtab));
2375 install_vtab("TkintxlibdeclsVtab",TkintxlibdeclsVGet(),sizeof(TkintxlibdeclsVtab));
2376 #else
2377 install_vtab("XlibVtab",XlibVGet(),sizeof(XlibVtab));
2378 #endif
2379 Boot_Tix(aTHX);
2380 }
2381 initialized++;
2382 }
2383
XS(XS_Tk__MainWindow_Create)2384 XS(XS_Tk__MainWindow_Create)
2385 {
2386 dXSARGS;
2387 STRLEN na;
2388 Tcl_Interp *interp = Tcl_CreateInterp();
2389 SV **args = &ST(0);
2390 char *appName = items >= 1 ? SvPV(ST(1),na) : "";
2391 int offset = args - sp;
2392 int code;
2393 if (!initialized)
2394 InitVtabs();
2395 code = TkCreateFrame(NULL, interp, items, &ST(0), 1, appName);
2396 if (code != TCL_OK)
2397 {
2398 Tcl_AddErrorInfo(interp, "Tk::MainWindow::Create");
2399 croak("%s",Tcl_GetStringResult(interp));
2400 }
2401 #if !defined(WIN32) && !defined(__PM__) && !(defined(OS2) && defined(__WIN32__))
2402 TkCreateXEventSource();
2403 #endif
2404 TKXSRETURN(Return_Results(interp,items,offset));
2405 }
2406
2407
2408 static int
SelGetProc(clientData,interp,portion,numItems,format,type,tkwin)2409 SelGetProc(clientData,interp,portion,numItems,format,type,tkwin)
2410 ClientData clientData;
2411 Tcl_Interp *interp;
2412 long *portion;
2413 int numItems;
2414 int format;
2415 Atom type;
2416 Tk_Window tkwin;
2417 {
2418 dTHX;
2419 Tcl_Obj *result = (Tcl_Obj *) clientData;
2420 char *p = (char *) portion;
2421 SV *sv = Nullsv;
2422 if (format == 8)
2423 {
2424 TkWindow *winPtr = (TkWindow *) tkwin;
2425 TkDisplay *dispPtr = winPtr->dispPtr;
2426 /* Whole can-of-worms here:
2427 Mozilla has various text/... targets with no charset
2428 data which are in some 16-bit Unicode UCS-2/utf-16 style
2429 for which this would be correct:
2430 format = 16;
2431 numItems /= 2;
2432 (It is a little-endian 16-bit on Linux-x86.)
2433
2434 Note that the is_utf8_string test will _PASS_ for
2435 the 16-bit case with plain ASCII as '\0' is legitimate UTF-8
2436
2437 KDE's Konsole has text/plain;charset=xxxx
2438 charsets are mostly really 8-bit but also has
2439 ISO-10646-UCS-2 which is 16-bit with a leading BOM
2440 For KDE there is no real gain in using one of these
2441 as UTF8_STRING returns same information.
2442 The mozilla targets might be interesting.
2443
2444 Bare is_utf8_string() test may be wrong as well as
2445 we may get partial characters ?
2446 */
2447 if ((dispPtr->utf8Atom != None && type == dispPtr->utf8Atom) ||
2448 is_utf8_string((U8 *) p, numItems))
2449 {
2450 Tcl_AppendToObj(result, p, numItems);
2451 }
2452 else
2453 {
2454 const char *strType = Tk_GetAtomName(tkwin, type);
2455 /* Do NOT use NewStringObj on it that assumes UTF-8-ness
2456 and we have established it isn't
2457 */
2458 sv = newSVpvn(p, numItems);
2459 #if 0
2460 LangDebug("%s %d '%.*s'\n",__FUNCTION__,numItems,numItems,p);
2461 LangDumpVec(strType,1,&sv);
2462 abort();
2463 #endif
2464 Tcl_ListObjAppendElement(interp,result,sv);
2465 }
2466 }
2467 else
2468 {
2469 if (type == Tk_InternAtom(tkwin,"TARGETS"))
2470 type = XA_ATOM;
2471 while (numItems-- > 0)
2472 {
2473 IV value = 0;
2474 sv = Nullsv;
2475 if (8 * sizeof(unsigned char) == format)
2476 {
2477 value = *((unsigned char *) p);
2478 }
2479 else if (8 * sizeof(unsigned short) == format)
2480 {
2481 value = *((unsigned short *) p);
2482 }
2483 else if (8 * sizeof(unsigned int) == format)
2484 {
2485 value = *((unsigned int *) p);
2486 }
2487 else if (8 * sizeof(unsigned long) == format)
2488 {
2489 value = *((unsigned long *) p);
2490 }
2491 else
2492 {
2493 return EXPIRE((interp, "No C type for format %d", format));
2494 }
2495 p += (format / 8);
2496 if (type == XA_ATOM)
2497 {
2498 if (value)
2499 {
2500 sv = newSVpv(Tk_GetAtomName(tkwin,(Atom) value),0);
2501 sv_setiv(sv,value);
2502 SvPOK_on(sv);
2503 }
2504 }
2505 else
2506 sv = newSViv(value);
2507 if (sv)
2508 Tcl_ListObjAppendElement(interp,result,sv);
2509 }
2510 }
2511 return TCL_OK;
2512 }
2513
2514 static int
isSwitch(s)2515 isSwitch(s)
2516 char *s;
2517 {int ch;
2518 if (*s++ != '-')
2519 return 0;
2520 if (!isalpha(UCHAR(*s)))
2521 return 0;
2522 while ((ch = UCHAR(*++s)))
2523 {
2524 if (!isalnum(ch) && ch != '_')
2525 return 0;
2526 }
2527 return 1;
2528 }
2529
XS(XS_Tk__Widget_SelectionGet)2530 XS(XS_Tk__Widget_SelectionGet)
2531 {
2532 dXSARGS;
2533 STRLEN na;
2534 int offset = &ST(0) - sp;
2535 Lang_CmdInfo *info = WindowCommand(ST(0), NULL, 3);
2536 TkWindow *winPtr = (TkWindow *) info->tkwin;
2537 TkDisplay *dispPtr = winPtr->dispPtr;
2538 Atom selection = XA_PRIMARY;
2539 Atom target = None;
2540 int i = 1;
2541 Tcl_Obj *result = NULL;
2542 int retval = TCL_ERROR;
2543 while (i < items)
2544 {STRLEN len;
2545 char *s = SvPV(ST(i),len);
2546 if (len && !isSwitch(s))
2547 {
2548 target = Tk_InternAtom(info->tkwin,s);
2549 i += 1;
2550 }
2551 else if (len >= 2 && !strncmp(s,"-type",len))
2552 {
2553 if (i+1 < items)
2554 target = Tk_InternAtom(info->tkwin,SvPV(ST(i+1),na));
2555 i += 2;
2556 }
2557 else if (len >= 2 && !strncmp(s,"-selection",len))
2558 {
2559 if (i+1 < items)
2560 selection = Tk_InternAtom(info->tkwin,SvPV(ST(i+1),na));
2561 i += 2;
2562 }
2563 else
2564 croak("Bad option '%s'",s);
2565 }
2566 result = Tcl_NewObj();
2567 if (target == None)
2568 {
2569 /* Caller did not specify a target
2570 Try UTF8_STRING and if that fails try STRING
2571
2572 But if they _ask_ for STRING then target will be set
2573 so we don't come here and just go for STRING below.
2574
2575 We could get TARGETS list and then only ask for UTF8_STRING
2576 if owner supports it. But that would still be two requests
2577 and involves either a direct call to XConvertSelection()
2578 which is at best faked on Win32, or poking about in list of
2579 strings returned for the atoms.
2580
2581 The more sophisticated TARGETS approach might start to win if we
2582 want to try TEXT COMPOUND_TEXT text/plain and other legacy
2583 ways of passing non-ASCII. But it seems like most applications
2584 are doing UTF8_STRING these days.
2585
2586 We do UTF8_STRING first as owner may advertise STRING but
2587 fail to return it if selection contains high characters,
2588 or it may return STRING with a lot of '?' or '#' or other
2589 "marker" for non-converted chars. In contrast UTF-8 gives
2590 then no excuses ;-)
2591
2592 */
2593 if (dispPtr->utf8Atom != None)
2594 {
2595 /* Try for UTF8_STRING */
2596 retval = Tk_GetXSelection(info->interp, info->tkwin, selection,
2597 dispPtr->utf8Atom, SelGetProc,
2598 (ClientData) result);
2599 }
2600 target = XA_STRING;
2601 }
2602 if (retval != TCL_OK)
2603 {
2604 retval = Tk_GetXSelection(info->interp, info->tkwin, selection, target,
2605 SelGetProc, (ClientData) result);
2606 }
2607 if (retval != TCL_OK)
2608 {
2609 Tcl_DecrRefCount(result);
2610 croak("%s", Tcl_GetString(Tcl_GetObjResult(info->interp)));
2611 }
2612 retval = Return_Object(items,offset,result);
2613 Tcl_DecrRefCount(result);
2614 XSRETURN(retval);
2615 }
2616
2617 static I32
InsertArg(mark,posn,sv)2618 InsertArg(mark,posn,sv)
2619 SV **mark;
2620 I32 posn;
2621 SV *sv;
2622 {
2623 dTHX;
2624 dSP;
2625 I32 items = sp - mark;
2626 MEXTEND(sp, 1); /* May not be room ? */
2627 while (sp > mark + posn) /* Move all but one args up 1 */
2628 {
2629 sp[1] = sp[0];
2630 sp--;
2631 }
2632 mark[posn+1] = sv;
2633 sp = mark + (++items);
2634 PUTBACK;
2635 return items;
2636 }
2637
XS(XStoWidget)2638 XS(XStoWidget)
2639 {
2640 dXSARGS;
2641 Lang_CmdInfo *info = WindowCommand(ST(0), NULL, 1);
2642 do_watch();
2643 items = InsertArg(mark,1,XSANY.any_ptr);
2644 TKXSRETURN(Call_Tk(info, items, &ST(0)));
2645 }
2646
2647 static SV *
NameFromCv(cv)2648 NameFromCv(cv)
2649 CV *cv;
2650 {
2651 dTHX;
2652 SV *sv = NULL;
2653 if (cv)
2654 {
2655 GV *gv = CvGV(cv);
2656 char *s = GvNAME(gv);
2657 STRLEN l = GvNAMELEN(gv);
2658 sv = sv_newmortal();
2659 sv_setpvn(sv, s, l);
2660 #ifdef DEBUG_GLUE
2661 fprintf(stderr, "Recovered name '%s'\n", Tcl_GetString(sv));
2662 #endif
2663 }
2664 else
2665 croak("No CV passed");
2666 return sv;
2667 }
2668
2669 Tk_Window
Tk_MainWindow(interp)2670 Tk_MainWindow(interp)
2671 Tcl_Interp *interp;
2672 {
2673 dTHX;
2674 HV *hv = InterpHv(interp,0);
2675 if (hv)
2676 {
2677 MAGIC *mg = mg_find((SV *) hv, PERL_MAGIC_ext);
2678 if (mg)
2679 {
2680 return INT2PTR(Tk_Window, SvIV(mg->mg_obj));
2681 }
2682 }
2683 return NULL;
2684 }
2685
2686 static int
InfoFromArgs(info,proc,mwcd,items,args)2687 InfoFromArgs(info,proc,mwcd,items,args)
2688 Lang_CmdInfo *info;
2689 Tcl_ObjCmdProc *proc;
2690 int mwcd;
2691 int items;
2692 SV **args;
2693 {
2694 dTHX;
2695 SV *fallback = NULL;
2696 int i;
2697 memset(info,0,sizeof(*info));
2698 info->Tk.objProc = proc;
2699 for (i=0; i < items; i++)
2700 {
2701 SV *sv = args[i];
2702 if (SvROK(sv) && sv_isobject(sv))
2703 {
2704 Lang_CmdInfo *winfo = WindowCommand(sv,NULL,0);
2705 if (winfo && winfo->interp)
2706 {
2707 if (winfo->interp != info->interp)
2708 info->interp = winfo->interp;
2709 if (mwcd)
2710 {
2711 Tk_Window mw;
2712 if (winfo->tkwin)
2713 mw = TkToMainWindow(winfo->tkwin);
2714 else
2715 mw = Tk_MainWindow(winfo->interp);
2716 if (mw)
2717 {
2718 if ((ClientData) mw != info->Tk.objClientData)
2719 {
2720 if (info->Tk.objClientData)
2721 {
2722 PerlIO_printf(PerlIO_stderr(),"cmd %p/%p using %p/%p\n",
2723 info->Tk.objClientData,info->interp,
2724 mw, winfo->interp);
2725 }
2726 info->Tk.objClientData = (ClientData) mw;
2727 }
2728 }
2729 }
2730 return i;
2731 }
2732 }
2733 }
2734 fallback = perl_get_sv("Tk::_Interp",TRUE);
2735 if (!SvROK(fallback))
2736 {
2737 Tcl_Interp *interp = Tcl_CreateInterp();
2738 SV *sv = sv_2mortal(MakeReference((SV *) interp));
2739 #if 0
2740 Tcl_CallWhenDeleted(interp, TkEventCleanupProc, (ClientData) NULL);
2741 #endif
2742 SvSetMagicSV(fallback,sv);
2743 }
2744 info->interp = (Tcl_Interp *) SvRV(fallback);
2745 return -1;
2746 }
2747
2748 static
XS(XStoSubCmd)2749 XS(XStoSubCmd)
2750 {
2751 dXSARGS;
2752 STRLEN na;
2753 Lang_CmdInfo info;
2754 SV *name = NameFromCv(cv);
2755 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2756 if (posn < 0)
2757 {
2758 #if 0
2759 LangDumpVec(Tcl_GetString(name),items,&ST(0));
2760 #endif
2761 die_with_trace(ST(0),"XStoSubCmd: Not a Tk Window");
2762 }
2763 if (posn == 0)
2764 {
2765 /* Do arg re-ordering to covert grab/wm like calls from
2766 perl method call form to that expected by Tk
2767 0 1 2
2768 have [ win sub ?-opt? .... ]
2769 need [ cv sub ?-opt? win ... ]
2770
2771 */
2772
2773 MEXTEND(sp, 1); /* May not be room ? */
2774 while (sp > mark + 2) /* Move all but two args up 1 */
2775 {
2776 if (SvPOK(*sp) && isSwitch(SvPV(*sp, na)))
2777 break;
2778 sp[1] = sp[0];
2779 sp--;
2780 }
2781 sp[1] = mark[1]; /* Move object = window arg */
2782 sp = mark + (++items); /* move sp past the lot */
2783 PUTBACK; /* and reset the global */
2784 }
2785 ST(0) = name; /* Fill in command name */
2786 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2787 }
2788
2789 static
XS(XStoEvent)2790 XS(XStoEvent)
2791 {
2792 dXSARGS;
2793 STRLEN na;
2794 Lang_CmdInfo info;
2795 SV *name = NameFromCv(cv);
2796 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2797 if (posn < 0)
2798 {
2799 croak("XStoEvent:%s is not a Tk Window",SvPV(ST(0),na));
2800 }
2801 if (posn == 0)
2802 {
2803 if (SvPOK(mark[2]) && strcmp(SvPV(mark[2], na), "generate") == 0)
2804 {
2805 /* Do arg re-ordering to convert calls from
2806 perl method call form to that expected by Tk
2807 0 1 2
2808 have [ win sub ?-opt? .... ]
2809 need [ cv sub win ?-opt? ... ]
2810
2811 */
2812 MEXTEND(sp, 1); /* May not be room ? */
2813 while (sp > mark + 2) /* Move all but two args up 1 */
2814 {
2815 sp[1] = sp[0];
2816 sp--;
2817 }
2818 sp[1] = mark[1]; /* Move object = window arg */
2819 sp = mark + (++items); /* move sp past the lot */
2820 PUTBACK; /* and reset the global */
2821 }
2822 }
2823 ST(0) = name; /* Fill in command name */
2824 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2825 }
2826
2827
2828 static
XS(XStoAfterSub)2829 XS(XStoAfterSub)
2830 {
2831 dXSARGS;
2832 STRLEN na;
2833 Lang_CmdInfo info;
2834 SV *name = NameFromCv(cv);
2835 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2836 if (posn != 0)
2837 {
2838 LangDumpVec(SvPV(name,na),items,&ST(0));
2839 croak("Usage $widget->%s(...)",SvPV(name,na));
2840 }
2841 /* Find a place for the widget arg after a possible subcommands */
2842 posn = 1;
2843 if (posn < items && SvPOK(ST(posn)) && !isSwitch(SvPV(ST(posn),na)))
2844 posn++;
2845 items = InsertArg(mark,posn,ST(0));
2846 ST(0) = name; /* Fill in command name */
2847 Tcl_GetCommandInfo(info.interp,Tcl_GetString(name),&info.Tk);
2848 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2849 }
2850
2851 static
XS(XStoGrid)2852 XS(XStoGrid)
2853 {
2854 dXSARGS;
2855 STRLEN na;
2856 Lang_CmdInfo info;
2857 SV *name = NameFromCv(cv);
2858 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2859 if (posn == 0 && 0)
2860 {
2861 /* Find a place for the widget arg after a possible subcommands */
2862 posn = 1;
2863 if (posn < items && SvPOK(ST(posn)) && !isSwitch(SvPV(ST(posn),na)))
2864 posn++;
2865 items = InsertArg(mark,posn,ST(0));
2866 ST(0) = name; /* Fill in command name */
2867 }
2868 items = InsertArg(mark,0, name);
2869 #if 0
2870 LangDumpVec("grid", items, &ST(0));
2871 #endif
2872 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2873 }
2874
2875
2876 static
XS(XStoDisplayof)2877 XS(XStoDisplayof)
2878 {
2879 dXSARGS;
2880 STRLEN na;
2881 Lang_CmdInfo info;
2882 SV *name = NameFromCv(cv);
2883 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2884 if (posn != 0)
2885 {
2886 LangDumpVec(SvPV(name,na),items,&ST(0));
2887 croak("Usage $widget->%s(...)",SvPV(name,na));
2888 }
2889 posn = 1;
2890 if (posn < items && SvPOK(ST(posn)) && !isSwitch(SvPV(ST(posn),na)))
2891 posn++;
2892 items = InsertArg(mark,posn++,sv_2mortal(newSVpv("-displayof",0)));
2893 SPAGAIN;
2894 mark = sp-items;
2895 items = InsertArg(mark,posn,ST(0));
2896 ST(0) = name; /* Fill in command name */
2897 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2898 }
2899
2900 static
XS(XStoTk)2901 XS(XStoTk)
2902 {
2903 dXSARGS;
2904 STRLEN na;
2905 SV *name = NameFromCv(cv);
2906 Lang_CmdInfo info;
2907 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2908 if (posn < 0)
2909 {
2910 LangDumpVec(SvPV(name,na),items,&ST(0));
2911 croak("Usage $widget->%s(...)",SvPV(name,na));
2912 }
2913 if (items == 0 || !SvPOK(ST(0)) || strcmp(SvPV(ST(0),na),BASEEXT) != 0)
2914 {
2915 items = InsertArg(mark,0,name);
2916 }
2917 ST(0) = name; /* Fill in command name */
2918 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2919 }
2920
2921 static
XS(XStoOption)2922 XS(XStoOption)
2923 {
2924 dXSARGS;
2925 STRLEN na;
2926 SV *name = NameFromCv(cv);
2927 Lang_CmdInfo info;
2928 int posn = InfoFromArgs(&info, LangOptionCommand, 1, items, &ST(0));
2929 if (posn < 0)
2930 {
2931 LangDumpVec(SvPV(name,na),items,&ST(0));
2932 croak("Usage $widget->%s(...)",SvPV(name,na));
2933 }
2934 if (items > 1 && SvPOK(ST(1)) && !strcmp(SvPV(ST(1),na),"get"))
2935 {
2936 items = InsertArg(mark,2,ST(0));
2937 }
2938 ST(0) = name; /* Fill in command name */
2939 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2940 }
2941
2942 static
XS(XStoImage)2943 XS(XStoImage)
2944 {
2945 dXSARGS;
2946 STRLEN na;
2947 SV *name = NameFromCv(cv);
2948 Lang_CmdInfo info;
2949 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2950 if (posn < 0)
2951 {
2952 LangDumpVec(SvPV(name,na),items,&ST(0));
2953 croak("Usage $widget->%s(...)",SvPV(name,na));
2954 }
2955 if (items > 1 && SvPOK(ST(1)))
2956 {
2957 char *opt = SvPV(ST(1),na);
2958 if (strcmp(opt,"create") && strcmp(opt,"names") && strcmp(opt,"types"))
2959 {
2960 items = InsertArg(mark,2,ST(0));
2961 }
2962 }
2963 ST(0) = name; /* Fill in command name */
2964 #if 0
2965 LangDumpVec("Image",items,&ST(0));
2966 #endif
2967 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
2968 }
2969
2970 static
XS(XStoFont)2971 XS(XStoFont)
2972 {
2973 dXSARGS;
2974 STRLEN na;
2975 SV *name = NameFromCv(cv);
2976 Lang_CmdInfo info;
2977 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
2978 if (posn < 0)
2979 {
2980 LangDumpVec(SvPV(name,na),items,&ST(0));
2981 croak("Usage $widget->%s(...)",SvPV(name,na));
2982 }
2983 if (items > 1 && SvPOK(ST(1)))
2984 {
2985 char *opt = SvPV(ST(1),na);
2986 if (strcmp(opt,"create") && strcmp(opt,"names") && strcmp(opt,"families"))
2987 {
2988 /* FIXME: would be better to use hint from info rather than fact that
2989 object is not hash-based */
2990 if (SvROK(ST(0)) && SvTYPE(SvRV(ST(0))) != SVt_PVHV)
2991 {
2992 items = InsertArg(mark,2,ST(0));
2993 }
2994 else if (ST(2) == &PL_sv_undef)
2995 {
2996 #if 0
2997 LangDumpVec("Font undef",items,&ST(0));
2998 #endif
2999 croak("Cannot use undef as font object");
3000 }
3001 }
3002 }
3003
3004 ST(0) = name; /* Fill in command name */
3005 #if 0
3006 LangDumpVec("Font Post",items,&ST(0));
3007 #endif
3008 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
3009 }
3010
3011 int
XSTkCommand(CV * cv,int mwcd,Tcl_ObjCmdProc * proc,int items,SV ** args)3012 XSTkCommand (CV *cv, int mwcd, Tcl_ObjCmdProc *proc, int items, SV **args)
3013 {
3014 dTHX;
3015 STRLEN na;
3016 Lang_CmdInfo info;
3017 SV *name = NameFromCv(cv);
3018 if (InfoFromArgs(&info,proc,mwcd,items,args) != 0)
3019 {
3020 croak("Usage $widget->%s(...)\n%s is not a Tk object",
3021 SvPV_nolen(name),SvPV_nolen(args[0]));
3022 }
3023 /* Having established a widget was passed in ST(0) overwrite
3024 with name of command Tk is expecting
3025 */
3026 args[0] = name; /* Fill in command name */
3027 if (1 || !mwcd)
3028 {
3029 char *s = Tcl_GetString(name);
3030 Tcl_GetCommandInfo(info.interp,s,&info.Tk);
3031 if (!proc && info.Tk.objProc)
3032 {
3033 proc = info.Tk.objProc;
3034 }
3035 CvXSUBANY(cv).any_ptr = proc;
3036 if (!info.Tk.objProc && !info.Tk.proc)
3037 {
3038 info.Tk.objProc = proc;
3039 Tcl_SetCommandInfo(info.interp,s,&info.Tk);
3040 }
3041 }
3042 return Call_Tk(&info, items, args);
3043 }
3044
3045 static
XS(XStoTclCmd)3046 XS(XStoTclCmd)
3047 {
3048 dXSARGS;
3049 TKXSRETURN(XSTkCommand(cv,1,(Tcl_ObjCmdProc *) XSANY.any_ptr, items, &ST(0)));
3050 }
3051
3052 static
XS(XStoTclCmdNull)3053 XS(XStoTclCmdNull)
3054 {
3055 dXSARGS;
3056 TKXSRETURN(XSTkCommand(cv,0,(Tcl_ObjCmdProc *) XSANY.any_ptr, items, &ST(0)));
3057 }
3058
3059 static
XS(XStoNoWindow)3060 XS(XStoNoWindow)
3061 {
3062 dXSARGS;
3063 STRLEN na;
3064 Lang_CmdInfo info;
3065 SV *name = NameFromCv(cv);
3066 HV *cm;
3067 STRLEN sz;
3068 char *cmdName = SvPV(name,sz);
3069 SV **x ;
3070 InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,0,items,&ST(0));
3071 cm = FindHv(aTHX_ info.interp, "XStoNoWindow", 0, CMD_KEY);
3072 Tcl_GetCommandInfo(info.interp,cmdName,&info.Tk);
3073 if (items > 0 && (sv_isobject(ST(0)) || !strcmp(SvPV(ST(0),na),BASEEXT)))
3074 ST(0) = name; /* Fill in command name */
3075 else
3076 items = InsertArg(mark,0,name);
3077 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
3078 }
3079
3080 static CV *
TkXSUB(const char * name,XSptr xs,Tcl_ObjCmdProc * proc)3081 TkXSUB(const char *name,XSptr xs,Tcl_ObjCmdProc *proc)
3082 {
3083 dTHX;
3084 STRLEN na;
3085 SV *sv = newSVpv(BASEEXT,0);
3086 CV *cv;
3087 sv_catpv(sv,"::");
3088 sv_catpv(sv,name);
3089 if (xs && proc)
3090 {
3091 cv = newXS(SvPV(sv,na),xs,__FILE__);
3092 CvXSUBANY(cv).any_ptr = (VOID *) proc;
3093 }
3094 else
3095 {
3096 cv = perl_get_cv(SvPV(sv,na),0);
3097 }
3098 SvREFCNT_dec(sv);
3099 return cv;
3100 }
3101
3102 void
Lang_TkCommand(name,proc)3103 Lang_TkCommand(name,proc)
3104 char *name;
3105 Tcl_ObjCmdProc *proc;
3106 {
3107 TkXSUB(name,XStoTclCmd,proc);
3108 }
3109
3110 void
Lang_TkSubCommand(name,proc)3111 Lang_TkSubCommand(name,proc)
3112 char *name;
3113 Tcl_ObjCmdProc *proc;
3114 {
3115 TkXSUB(name,XStoAfterSub,proc);
3116 }
3117
3118
3119 /*
3120 The bind command is handled specially, it must *always* be called
3121 with a widget object. And only the <> form of sequence is allowed
3122 so that the following forms of call can be spotted:
3123
3124 $widget->bind();
3125 $widget->bind('tag');
3126 $widget->bind('<...>');
3127 $widget->bind('tag','<...>');
3128 $widget->bind('<...>',command);
3129 $widget->bind('tag','<...>',command);
3130
3131 */
3132
3133 static
XS(XStoBind)3134 XS(XStoBind)
3135 {
3136 dXSARGS;
3137 STRLEN na;
3138 Lang_CmdInfo info;
3139 SV *name = NameFromCv(cv);
3140 int posn = InfoFromArgs(&info,(Tcl_ObjCmdProc *) XSANY.any_ptr,1,items,&ST(0));
3141 STRLEN len;
3142 if (posn < 0)
3143 {
3144 LangDumpVec(SvPV(name,na),items,&ST(0));
3145 croak("Usage $widget->%s(...)",SvPV(name,na));
3146 }
3147 if (items < 2 || *SvPV(ST(1),len) == '<')
3148 {
3149 /* Looks like $widget->bind([<..>])
3150 * i.e. bind command to widget itself
3151 * Standard move up of all the args to make room for 'bind'
3152 * as argv[0]
3153 */
3154 items = InsertArg(mark,0,name);
3155 }
3156 else
3157 {
3158 /* Looks like $widget->bind('tag',...)
3159 * simply overwrite 0'th argument with 'bind'
3160 */
3161 ST(0) = name; /* Fill in command name */
3162 #if 0
3163 if (dowarn)
3164 {
3165 if (items == 4)
3166 {
3167 SV *sv = ST(3);
3168 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)
3169 {
3170 LangDumpVec("bind",items,&ST(0));
3171 warn("Subreference for class binding");
3172 }
3173 }
3174 }
3175 #endif
3176 }
3177 TKXSRETURN(Call_Tk(&info, items, &ST(0)));
3178 }
3179
3180
3181 void
LangDeadWindow(interp,tkwin)3182 LangDeadWindow(interp, tkwin)
3183 Tcl_Interp *interp;
3184 Tk_Window tkwin;
3185 {
3186 dTHX;
3187 STRLEN na;
3188 HV *hv = InterpHv(interp,0);
3189 if (hv)
3190 {
3191 /* This is last hook before tkwin disapears
3192 - LangDeleteWidget has happened
3193 - <Destroy> bindings have happened
3194 */
3195 char *cmdName = Tk_PathName(tkwin);
3196 STRLEN cmdLen = strlen(cmdName);
3197 SV *obj = hv_delete(hv, cmdName, cmdLen, G_SCALAR);
3198 if (obj && SvROK(obj) && SvTYPE(SvRV(obj)) == SVt_PVHV)
3199 {
3200 HV *hash = (HV *) SvRV(obj);
3201 MAGIC *mg = mg_find((SV *) hash,PERL_MAGIC_ext);
3202
3203 /* Tk_CheckHash((SV *) hash, NULL); */
3204 if (SvREFCNT(hash) < 1)
3205 {
3206 LangDebug("%s %s has REFCNT=%d\n",__FUNCTION__,cmdName,(int) SvREFCNT(hash));
3207 sv_dump(obj);
3208 }
3209
3210 if (mg)
3211 {
3212 Lang_CmdInfo *info = (Lang_CmdInfo *) SvPV_nolen(mg->mg_obj);
3213 if (info->interp != interp)
3214 Tcl_Panic("%s->interp=%p expected %p", cmdName, info->interp, interp);
3215 DecInterp(info->interp, cmdName);
3216 /* mg->mg_obj is SV holding the Lang_CmdInfo struct
3217 we have now finished with it
3218 */
3219 SvREFCNT_dec(mg->mg_obj);
3220 sv_unmagic((SV *) hash,PERL_MAGIC_ext);
3221 }
3222 }
3223 }
3224 }
3225
3226
3227 int
Tcl_DeleteCommandFromToken(interp,info)3228 Tcl_DeleteCommandFromToken(interp, info)
3229 Tcl_Interp *interp;
3230 Tcl_Command info;
3231 {
3232 if (info)
3233 {
3234 if (info->Tk.deleteProc)
3235 {
3236 (*info->Tk.deleteProc) (info->Tk.deleteData);
3237 info->Tk.deleteProc = NULL;
3238 info->Tk.deleteData = NULL;
3239 }
3240 info->Tk.clientData = NULL;
3241 info->Tk.proc = NULL;
3242 info->Tk.objClientData = NULL;
3243 info->Tk.objProc = NULL;
3244 }
3245 return TCL_OK;
3246 }
3247
3248 void
Lang_DeleteWidget(interp,info)3249 Lang_DeleteWidget(interp, info)
3250 Tcl_Interp *interp;
3251 Tcl_Command info;
3252 {
3253 dTHX;
3254 Tk_Window tkwin = info->tkwin;
3255 char *cmdName = Tk_PathName(tkwin);
3256 SV *win = WidgetRef(interp, cmdName);
3257 /* This is first sign of disapearing widget, <Destroy> bindings
3258 are still to come.
3259 */
3260 LangMethodCall(interp,win,"_Destroyed",0,0);
3261 Tcl_DeleteCommandFromToken(interp,info);
3262 if (win && SvOK(win))
3263 {
3264 HV *hash = NULL;
3265 Lang_CmdInfo *info = WindowCommand(win,&hash,1);
3266 if (info->interp != interp)
3267 Tcl_Panic("%s->interp=%p expected %p", cmdName, info->interp, interp);
3268 if (hash)
3269 hv_delete(hash, XEVENT_KEY, strlen(XEVENT_KEY), G_DISCARD);
3270 /* Tk_CheckHash((SV *) hash, NULL); */
3271 if (SvREFCNT(hash) < 2)
3272 {
3273 LangDebug("%s %s has REFCNT=%d",__FUNCTION__,cmdName,(int) SvREFCNT(hash));
3274 }
3275 SvREFCNT_dec(hash);
3276 }
3277 }
3278
3279 void
Lang_DeleteObject(interp,info)3280 Lang_DeleteObject(interp, info)
3281 Tcl_Interp *interp;
3282 Tcl_Command info;
3283 {
3284 dTHX;
3285 STRLEN na;
3286 char *cmdName = SvPV(info->image,na);
3287 if (info->interp != interp)
3288 Tcl_Panic("%s->interp=%p expected %p", cmdName, info->interp, interp);
3289 Tcl_DeleteCommandFromToken(interp, info);
3290 DecInterp(info->interp,cmdName);
3291 }
3292
3293 void
Lang_NewMainWindow(interp,tkwin)3294 Lang_NewMainWindow(interp,tkwin)
3295 Tcl_Interp *interp;
3296 Tk_Window tkwin;
3297 {
3298 dTHX;
3299 tilde_magic((SV *) InterpHv(interp,1),newSViv(PTR2IV(tkwin)));
3300 }
3301
3302 Tcl_Command
Lang_CreateWidget(interp,tkwin,proc,clientData,deleteProc)3303 Lang_CreateWidget(interp, tkwin, proc, clientData, deleteProc)
3304 Tcl_Interp *interp;
3305 Tk_Window tkwin;
3306 Tcl_ObjCmdProc *proc;
3307 ClientData clientData;
3308 Tcl_CmdDeleteProc *deleteProc;
3309 {
3310 dTHX;
3311 STRLEN na;
3312 HV *hv = InterpHv(interp,1);
3313 char *cmdName = (tkwin) ? Tk_PathName(tkwin) : ".";
3314 STRLEN cmdLen = strlen(cmdName);
3315 HV *hash = newHV();
3316 SV *tmp;
3317 Lang_CmdInfo info;
3318 SV *sv;
3319 do_watch();
3320 memset(&info,0,sizeof(info));
3321 info.Tk.objProc = proc;
3322 info.Tk.deleteProc = deleteProc;
3323 info.Tk.objClientData = info.Tk.deleteData = clientData;
3324 info.interp = interp;
3325 info.tkwin = tkwin;
3326 info.image = NULL;
3327 sv = struct_sv(&info,sizeof(info));
3328
3329 /* Record the object in the main hash */
3330 IncInterp(interp, cmdName);
3331
3332 hv_store(hv, cmdName, cmdLen, newRV((SV *) hash), 0);
3333 /* At this point hash REFCNT should be 2, one for what is stored
3334 in interp and one representing Tk's use
3335 */
3336 tilde_magic((SV *) hash, sv);
3337 return (Lang_CmdInfo *) SvPV(sv,na);
3338 }
3339
3340 Tcl_Command
Lang_CreateObject(interp,cmdName,proc,clientData,deleteProc)3341 Lang_CreateObject(interp, cmdName, proc, clientData, deleteProc)
3342 Tcl_Interp *interp;
3343 char *cmdName;
3344 Tcl_ObjCmdProc *proc;
3345 ClientData clientData;
3346 Tcl_CmdDeleteProc *deleteProc;
3347 {
3348 dTHX;
3349 STRLEN na;
3350 HV *hv = InterpHv(interp,1);
3351 STRLEN cmdLen = strlen(cmdName);
3352 HV *hash = newHV();
3353 SV *sv;
3354 Lang_CmdInfo info;
3355 do_watch();
3356 memset(&info,0,sizeof(info));
3357 info.Tk.objProc = proc;
3358 info.Tk.deleteProc = deleteProc;
3359 info.Tk.objClientData = info.Tk.deleteData = clientData;
3360 info.interp = interp;
3361 info.tkwin = NULL;
3362 info.image = newSVpv(cmdName,cmdLen);
3363 sv = struct_sv(&info,sizeof(info));
3364 /* Record the object in the main hash */
3365 IncInterp(interp, cmdName);
3366 hv_store(hv, cmdName, cmdLen, MakeReference((SV *) hash), 0);
3367 tilde_magic((SV *)hash, sv);
3368 return (Lang_CmdInfo *) SvPV(sv,na);
3369 }
3370
3371 Tcl_Command
Lang_CreateImage(interp,cmdName,proc,clientData,deleteProc,typePtr)3372 Lang_CreateImage(interp, cmdName, proc, clientData, deleteProc, typePtr)
3373 Tcl_Interp *interp;
3374 char *cmdName;
3375 Tcl_ObjCmdProc *proc;
3376 ClientData clientData;
3377 Tcl_CmdDeleteProc *deleteProc;
3378 Tk_ImageType *typePtr;
3379 {
3380 return Lang_CreateObject(interp, cmdName, proc, clientData, deleteProc);
3381 }
3382
3383 Tcl_Command
Tcl_CreateObjCommand(interp,cmdName,proc,clientData,deleteProc)3384 Tcl_CreateObjCommand(interp, cmdName, proc, clientData, deleteProc)
3385 Tcl_Interp *interp;
3386 CONST char *cmdName;
3387 Tcl_ObjCmdProc *proc;
3388 ClientData clientData;
3389 Tcl_CmdDeleteProc *deleteProc;
3390 {
3391 Tk_Window mw = Tk_MainWindow(interp);
3392 if (cmdName[0] == '.')
3393 {
3394 Tk_Window tkwin;
3395 if (cmdName[1] == '\0')
3396 {
3397 tkwin = mw;
3398 }
3399 else
3400 {
3401 tkwin = Tk_NameToWindow(interp, (char *) cmdName, mw);
3402 }
3403 return Lang_CreateWidget(interp, tkwin, proc, clientData, deleteProc);
3404 }
3405 else
3406 {
3407 Tcl_CmdInfo info;
3408 CV *cv;
3409 char *kind = "NULL";
3410 if (clientData)
3411 {
3412 kind = (clientData == (ClientData) mw) ? "mw" : "custom";
3413 }
3414 memset(&info,0,sizeof(info));
3415 info.objProc = proc;
3416 info.objClientData = clientData;
3417 info.deleteProc = deleteProc;
3418 if (!strcmp(cmdName,"menu"))
3419 {
3420 cmdName = "_menu";
3421 }
3422 /* We cannot test sanity of clientData vs XStoXxxxx at this point
3423 as when 1st called XSs are still pointing a B::C friendly re-directors.
3424 Also CVs for "loaded" commands may not exist yet.
3425 */
3426 #if 0
3427 if ((cv = TkXSUB(cmdName,NULL,NULL)))
3428 {
3429 if (clientData)
3430 {
3431 if (clientData == (ClientData) mw)
3432 {
3433 if (CvXSUB(cv) == XStoTclCmdNull)
3434 {
3435 warn("Wrong xsub %s cd=%p (mw)",cmdName, clientData);
3436 CvXSUB(cv) = XStoTclCmd;
3437 }
3438 }
3439 else
3440 {
3441 if (CvXSUB(cv) == XStoTclCmd)
3442 {
3443 warn("Wrong xsub %s cd=%p",cmdName, clientData);
3444 CvXSUB(cv) = XStoTclCmdNull;
3445 }
3446 }
3447 }
3448 else
3449 {
3450 if (CvXSUB(cv) == XStoTclCmd)
3451 {
3452 warn("Wrong xsub %s cd=%p",cmdName, clientData);
3453 CvXSUB(cv) = XStoTclCmdNull;
3454 }
3455 }
3456 }
3457 else
3458 {
3459 warn("No cv for %s",cmdName);
3460 }
3461 #endif
3462 Tcl_SetCommandInfo(interp,cmdName,&info);
3463 if (deleteProc)
3464 {
3465 HV *hv = InterpHv(interp,1);
3466 Tcl_CallWhenDeleted(interp,(Tcl_InterpDeleteProc *)deleteProc,clientData);
3467 }
3468 }
3469 return NULL;
3470 }
3471
3472 int
Tcl_IsSafe(interp)3473 Tcl_IsSafe(interp)
3474 Tcl_Interp *interp;
3475 {
3476 return 0; /* Is this interp in a 'safe' compartment - not yet implemented */
3477 }
3478
3479 int
Tcl_HideCommand(Tcl_Interp * interp,CONST char * cmdName,CONST char * hiddenCmdName)3480 Tcl_HideCommand (Tcl_Interp *interp, CONST char *cmdName, CONST char *hiddenCmdName)
3481 {
3482 CV *cv = TkXSUB(cmdName,NULL,NULL);
3483 warn("Tcl_HideCommand %s => %s called",cmdName,hiddenCmdName);
3484 if (!cv)
3485 {
3486 return EXPIRE((interp,"Cannot find %s", cmdName));
3487 }
3488 return TCL_OK;
3489 }
3490
3491 int
Tcl_SetCommandInfo(interp,cmdName,infoPtr)3492 Tcl_SetCommandInfo(interp,cmdName,infoPtr)
3493 Tcl_Interp *interp;
3494 CONST char *cmdName;
3495 CONST Tcl_CmdInfo *infoPtr;
3496 {
3497 dTHX;
3498 HV *cm = FindHv(aTHX_ interp, "Tcl_SetCommandInfo", 1, CMD_KEY);
3499 hv_store(cm,cmdName,strlen(cmdName),
3500 struct_sv((char *) infoPtr,sizeof(*infoPtr)),0);
3501 return TCL_OK;
3502 }
3503
3504 int
Tcl_GetCommandInfo(Tcl_Interp * interp,CONST char * cmdName,Tcl_CmdInfo * infoPtr)3505 Tcl_GetCommandInfo (Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdInfo *infoPtr)
3506 {
3507 dTHX;
3508 HV *hv = InterpHv(interp,1);
3509 SV **svp = hv_fetch(hv,cmdName,strlen(cmdName),0);
3510 /* Widgets, images and named fonts get put in main hash */
3511 if (svp && *svp)
3512 {
3513 Lang_CmdInfo *info = WindowCommand(*svp,NULL,0);
3514 *infoPtr = info->Tk;
3515 return 1;
3516 }
3517 /* widgets are special cased elsewhere */
3518 else if (*cmdName != '.')
3519 {
3520 HV *cm = FindHv(aTHX_ interp, "Tcl_GetCommandInfo", 1, CMD_KEY);
3521 SV **svp = hv_fetch(cm,cmdName,strlen(cmdName),0);
3522 if (svp && *svp)
3523 {
3524 memcpy(infoPtr,SvPVX(*svp),sizeof(Tcl_CmdInfo));
3525 return 1;
3526 }
3527 else if (0)
3528 {
3529 /* If we didn't find the info but this is supposed to
3530 be a known Tk builtin then something may have gone wrong
3531 but "after" seems to occur regularly
3532 */
3533 CV *cv = TkXSUB(cmdName,NULL,NULL);
3534 if (cv)
3535 {
3536 LangDebug("No Tcl_GetCommandInfo for %s\n",cmdName);
3537 }
3538 }
3539 }
3540 return 0;
3541 }
3542
3543 Tcl_Command
Tcl_CreateCommand(interp,cmdName,proc,clientData,deleteProc)3544 Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
3545 Tcl_Interp *interp;
3546 CONST char *cmdName;
3547 Tcl_CmdProc *proc;
3548 ClientData clientData;
3549 Tcl_CmdDeleteProc *deleteProc;
3550 {
3551 return Tcl_CreateObjCommand(interp, cmdName, (Tcl_ObjCmdProc *) proc, clientData, deleteProc);
3552 }
3553
3554 static SV *LangVar2 _((Tcl_Interp *interp, SV *sv, char *part2, int flags));
3555
3556 static SV *
LangVar2(interp,sv,part2,store)3557 LangVar2(interp, sv, part2, store)
3558 Tcl_Interp *interp;
3559 SV *sv;
3560 char *part2;
3561 int store;
3562 {
3563 if (part2)
3564 {
3565 dTHX;
3566 if (SvTYPE(sv) == SVt_PVHV)
3567 {HV *hv = (HV *) sv;
3568 SV **x = hv_fetch(hv, part2, strlen(part2), store);
3569 if (x)
3570 return *x;
3571 }
3572 else
3573 {
3574 Tcl_Panic("two part %s not implemented", "Tcl_GetVar2");
3575 }
3576 return NULL;
3577 }
3578 else
3579 return sv;
3580 }
3581
3582 Tcl_Obj *
Tcl_ObjGetVar2(interp,sv,part2,flags)3583 Tcl_ObjGetVar2(interp, sv, part2, flags)
3584 Tcl_Interp *interp;
3585 SV *sv;
3586 SV *part2;
3587 int flags;
3588 {
3589 dTHX;
3590 if (sv)
3591 {
3592 if (SvPOK(sv))
3593 {
3594 STRLEN len;
3595 char *s = SvPV(sv,len);
3596 if (len > 6 && !strncmp(s,"::tk::",6))
3597 {
3598 sv = FindTkVarName(s+6,0);
3599 }
3600 }
3601 if (SvROK(sv) && SvTYPE(SvRV(sv)) != SVt_PVAV)
3602 {
3603 sv = SvRV(sv);
3604 }
3605 if (part2)
3606 {
3607 sv = LangVar2(interp, sv, Tcl_GetString(part2), 0);
3608 }
3609 }
3610 else
3611 {
3612 sv = newSV(0);
3613 }
3614 return sv;
3615 }
3616
3617 Tcl_Obj *
Tcl_ObjSetVar2(interp,sv,part2,newValue,flags)3618 Tcl_ObjSetVar2(interp, sv, part2, newValue, flags)
3619 Tcl_Interp *interp;
3620 SV *sv;
3621 SV *part2;
3622 SV *newValue;
3623 int flags;
3624 {
3625 dTHX;
3626 if (SvROK(sv))
3627 sv = SvRV(sv);
3628 if (part2)
3629 sv = LangVar2(interp, sv , Tcl_GetString(part2), 1);
3630 SvSetMagicSV(sv, newValue);
3631 return sv;
3632 }
3633
3634
3635
3636 char *
Tcl_SetVarArg(interp,sv,newValue,flags)3637 Tcl_SetVarArg(interp, sv, newValue, flags)
3638 Tcl_Interp *interp;
3639 SV *sv;
3640 Tcl_Obj * newValue;
3641 int flags;
3642 {
3643 dTHX;
3644 STRLEN na;
3645 if (!newValue)
3646 newValue = &PL_sv_undef;
3647 SvSetMagicSV(sv, newValue);
3648 return SvPV(sv, na);
3649 }
3650
3651 int
LangCmpOpt(opt,arg,len)3652 LangCmpOpt(opt,arg,len)
3653 CONST char *opt;
3654 CONST char *arg;
3655 size_t len;
3656 {
3657 int result = 0;
3658 if (!len)
3659 len = strlen(arg);
3660 if (*opt == '-')
3661 opt++;
3662 if (*arg == '-')
3663 {
3664 arg++;
3665 if (len)
3666 len--;
3667 }
3668 while (len--)
3669 {char ch = *arg++;;
3670 if ((result = *opt++ - ch) || !ch)
3671 break;
3672 }
3673 return result;
3674 }
3675
3676 int
LangCmpArg(a,b)3677 LangCmpArg(a,b)
3678 CONST SV *a;
3679 CONST SV *b;
3680 {
3681 dTHX;
3682 STRLEN na;
3683 char *as;
3684 char *bs;
3685 if (a && SvGMAGICAL(a))
3686 mg_get((SV *) a);
3687 if (b && SvGMAGICAL(b))
3688 mg_get((SV *) b);
3689 as = (a && SvOK(a)) ? SvPV((SV *)a,na) : "";
3690 bs = (b && SvOK(b)) ? SvPV((SV *)b,na) : "";
3691 return strcmp(as,bs);
3692 }
3693
3694 static I32
Perl_Value(pTHX_ IV ix,SV * sv)3695 Perl_Value(pTHX_ IV ix, SV *sv)
3696 {
3697 Tk_TraceInfo *p = INT2PTR(Tk_TraceInfo *, ix);
3698 char *result;
3699
3700 /* We are a "magic" set processor, whether we like it or not
3701 because this is the hook we use to get called.
3702 So we are (I think) supposed to look at "private" flags
3703 and set the public ones if appropriate.
3704 e.g. "chop" sets SvPOKp as a hint but not SvPOK
3705
3706 presumably other operators set other private bits.
3707
3708 Question are successive "magics" called in correct order?
3709
3710 i.e. if we are tracing a tied variable should we call
3711 some magic list or be careful how we insert ourselves in the list?
3712
3713 */
3714 /* This seems also to be wrong in some cases --- see t/sv.t and
3715 RT #121528
3716 */
3717 #if 0
3718 if (!SvPOK(sv) && SvPOKp(sv))
3719 SvPOK_on(sv);
3720
3721 if (!SvNOK(sv) && SvNOKp(sv))
3722 SvNOK_on(sv);
3723
3724 if (!SvIOK(sv) && SvIOKp(sv))
3725 SvIOK_on(sv);
3726 #endif
3727 return 0;
3728 }
3729
3730 static void
TraceExitHandler(ClientData clientData)3731 TraceExitHandler(ClientData clientData)
3732 {
3733 dTHX;
3734 Tk_TraceInfo *p = (Tk_TraceInfo *) clientData;
3735 char *result;
3736 ENTER;
3737 SvREFCNT_inc(p->sv);
3738 save_freesv(p->sv);
3739 result = (*p->proc) (p->clientData, p->interp, p->sv, p->part2, 0);
3740 if (result)
3741 Tcl_Panic("Tcl_VarTraceProc returned '%s'", result);
3742 LEAVE;
3743 }
3744
3745
DECL_MG_UFUNC(Perl_Trace,ix,sv)3746 static DECL_MG_UFUNC(Perl_Trace, ix, sv)
3747 {
3748 Tk_TraceInfo *p = INT2PTR(Tk_TraceInfo *, ix);
3749 char *result;
3750
3751 /* We are a "magic" set processor, whether we like it or not
3752 because this is the hook we use to get called.
3753 So we are (I think) supposed to look at "private" flags
3754 and set the public ones if appropriate.
3755 e.g. "chop" sets SvPOKp as a hint but not SvPOK
3756
3757 presumably other operators set other private bits.
3758
3759 Question are successive "magics" called in correct order?
3760
3761 i.e. if we are tracing a tied variable should we call
3762 some magic list or be careful how we insert ourselves in the list?
3763
3764 */
3765
3766 /* This seems to be wrong in at least one case --- see t/Trace.t and
3767 Message-ID: <3ef348b.0304240510.299e5519@posting.google.com>
3768 */
3769 #if 0
3770 if (!SvPOK(sv) && SvPOKp(sv))
3771 SvPOK_on(sv);
3772
3773 if (!SvNOK(sv) && SvNOKp(sv))
3774 SvNOK_on(sv);
3775
3776 if (!SvIOK(sv) && SvIOKp(sv))
3777 SvIOK_on(sv);
3778 #endif
3779
3780 ENTER;
3781 SvREFCNT_inc(sv);
3782 save_freesv(sv);
3783 result = (*p->proc) (p->clientData, p->interp, sv, p->part2, 0);
3784 if (result)
3785 Tcl_Panic("Tcl_VarTraceProc returned '%s'", result);
3786 LEAVE;
3787 return 0;
3788 }
3789
3790 int
Lang_TraceVar2(interp,sv,part2,flags,tkproc,clientData)3791 Lang_TraceVar2(interp, sv, part2, flags, tkproc, clientData)
3792 Tcl_Interp *interp;
3793 Tcl_Obj * sv;
3794 char *part2;
3795 int flags;
3796 Lang_VarTraceProc *tkproc;
3797 ClientData clientData;
3798 {
3799 dTHX;
3800 Tk_TraceInfo *p;
3801 struct ufuncs *ufp;
3802 MAGIC **mgp;
3803 MAGIC *mg;
3804 MAGIC *mg_list;
3805 SV *exiting;
3806 int mgType = PERL_MAGIC_uvar;
3807
3808 if (SvROK(sv))
3809 sv = SvRV(sv);
3810
3811 if (SvTHINKFIRST(sv))
3812 {
3813 if (SvREADONLY(sv))
3814 {
3815 return EXPIRE((interp, "Cannot trace readonly variable"));
3816 }
3817 }
3818 (void)SvUPGRADE(sv, SVt_PVMG);
3819
3820 if (SvTYPE(sv) == SVt_PVAV)
3821 {
3822 mgType = PERL_MAGIC_ext;
3823 }
3824
3825 /*
3826 * We can't use sv_magic() because it won't add in another magical struct
3827 * of type 'U' if there is already one there. We need multiple 'U'
3828 * magics hanging from one sv or else things like radiobuttons will
3829 * not work. That's because each radiobutton widget group needs to track
3830 * the same sv and update itself as necessary.
3831 */
3832
3833 New(601, p, 1, Tk_TraceInfo);
3834
3835 p->proc = tkproc;
3836 p->clientData = clientData;
3837 p->interp = interp;
3838 p->part2 = part2;
3839 p->sv = sv;
3840
3841 Tcl_CreateExitHandler(TraceExitHandler, (ClientData) p);
3842
3843 /* We want to be last in the chain so that any
3844 other magic has been called first
3845 save the list so that this magic can be moved to the end
3846 */
3847 mg_list = SvMAGIC(sv);
3848 SvMAGIC(sv) = NULL;
3849
3850 /* Add 'U' magic to sv with all NULL args */
3851 sv_magic(sv, 0, mgType, 0, 0);
3852
3853 Newz(666, ufp, 1, struct ufuncs);
3854 ufp->uf_val = Perl_Value;
3855 ufp->uf_set = Perl_Trace;
3856 ufp->uf_index = PTR2IV(p);
3857
3858 mg = SvMAGIC(sv);
3859 mg->mg_ptr = (char *) ufp;
3860 mg->mg_len = sizeof(struct ufuncs);
3861
3862
3863 /* put list back and add mg to end */
3864
3865 SvMAGIC(sv) = mg_list;
3866 mgp = &SvMAGIC(sv);
3867 while ((mg_list = *mgp))
3868 {
3869 mgp = &mg_list->mg_moremagic;
3870 }
3871 *mgp = mg;
3872
3873 if (mgType == PERL_MAGIC_ext)
3874 {
3875 /* We are not doing a real tie to an AV so
3876 we need to set the vtable and re-calc magic flags
3877 */
3878 mg->mg_virtual = &PL_vtbl_uvar;
3879 mg_magical(sv);
3880 }
3881
3882 if (!SvMAGICAL(sv))
3883 abort();
3884
3885 return TCL_OK;
3886 }
3887
3888 SV *
FindTkVarName(varName,flags)3889 FindTkVarName(varName,flags)
3890 CONST char *varName;
3891 int flags;
3892 {
3893 dTHX;
3894 STRLEN na;
3895 SV *name = newSVpv(BASEEXT,strlen(BASEEXT));
3896 SV *sv;
3897 sv_catpv(name,"::");
3898 if (!strncmp(varName,"tk_",3))
3899 varName += 3;
3900 sv_catpv(name,varName);
3901 sv = get_sv(SvPV(name,na),flags);
3902 SvREFCNT_dec(name);
3903 return sv;
3904 }
3905
3906 char *
LangLibraryDir()3907 LangLibraryDir()
3908 {
3909 dTHX;
3910 STRLEN na;
3911 SV *sv = FindTkVarName("library",0);
3912 if (sv && SvPOK(sv))
3913 return SvPV(sv,na);
3914 return NULL;
3915 }
3916
3917 static
DECL_MG_UFUNC(LinkIntSet,ix,sv)3918 DECL_MG_UFUNC(LinkIntSet,ix,sv)
3919 {
3920 int *p = INT2PTR(int *, ix);
3921 (*p) = SvIV(sv);
3922 return 0;
3923 }
3924
3925 static
DECL_MG_UFUNC(LinkDoubleSet,ix,sv)3926 DECL_MG_UFUNC(LinkDoubleSet,ix,sv)
3927 {
3928 double *p = INT2PTR(double *, ix);
3929 (*p) = SvNV(sv);
3930 return 0;
3931 }
3932
3933 static
DECL_MG_UFUNC(LinkCannotSet,ix,sv)3934 DECL_MG_UFUNC(LinkCannotSet,ix,sv)
3935 {
3936 croak("Attempt to set readonly linked variable");
3937 return 0;
3938 }
3939
3940 static
DECL_MG_UFUNC(LinkIntVal,ix,sv)3941 DECL_MG_UFUNC(LinkIntVal,ix,sv)
3942 {
3943 int *p = INT2PTR(int *, ix);
3944 sv_setiv(sv,*p);
3945 return 0;
3946 }
3947
3948 static
DECL_MG_UFUNC(LinkDoubleVal,ix,sv)3949 DECL_MG_UFUNC(LinkDoubleVal,ix,sv)
3950 {
3951 double *p = INT2PTR(double *, ix);
3952 sv_setnv(sv,*p);
3953 return 0;
3954 }
3955
3956 int
Tcl_LinkVar(interp,varName,addr,type)3957 Tcl_LinkVar(interp,varName,addr,type)
3958 Tcl_Interp *interp;
3959 CONST char *varName;
3960 char *addr;
3961 int type;
3962 {
3963 dTHX;
3964 SV *sv = FindTkVarName(varName,0);
3965 if (sv)
3966 {
3967 struct ufuncs uf;
3968 uf.uf_index = PTR2IV(addr);
3969 switch(type & ~TCL_LINK_READ_ONLY)
3970 {
3971 case TCL_LINK_INT:
3972 case TCL_LINK_BOOLEAN:
3973 uf.uf_val = LinkIntVal;
3974 uf.uf_set = LinkIntSet;
3975 *((int *) addr) = SvIV(sv);
3976 break;
3977 case TCL_LINK_DOUBLE:
3978 uf.uf_val = LinkDoubleVal;
3979 uf.uf_set = LinkDoubleSet;
3980 *((double *) addr) = SvNV(sv);
3981 break;
3982 case TCL_LINK_STRING:
3983 default:
3984 return EXPIRE((interp,"Cannot link %s type %d\n",varName,type));
3985 }
3986 if (type & TCL_LINK_READ_ONLY)
3987 {
3988 uf.uf_set = LinkCannotSet;
3989 }
3990 sv_magic(sv,NULL, PERL_MAGIC_uvar, (char *) (&uf), sizeof(uf));
3991 return TCL_OK;
3992 }
3993 else
3994 {
3995 return EXPIRE((interp,"No variable %s\n",varName));
3996 }
3997 }
3998
3999 void
Tcl_UnlinkVar(interp,varName)4000 Tcl_UnlinkVar(interp,varName)
4001 Tcl_Interp *interp;
4002 CONST char *varName;
4003 {
4004 dTHX;
4005 SV *sv = FindTkVarName(varName,0);
4006 if (sv)
4007 {
4008 sv_unmagic(sv,PERL_MAGIC_uvar);
4009 }
4010 }
4011
4012 void
Lang_UntraceVar(interp,sv,flags,tkproc,clientData)4013 Lang_UntraceVar(interp, sv, flags, tkproc, clientData)
4014 Tcl_Interp *interp;
4015 SV *sv;
4016 int flags;
4017 Lang_VarTraceProc *tkproc;
4018 ClientData clientData;
4019 {
4020 int mgType = PERL_MAGIC_uvar;
4021 MAGIC **mgp;
4022 /* it may not be magical i.e. it may never have been traced
4023 This occurs for example when cascade Menu gets untraced
4024 by same code that untraces checkbutton menu items.
4025 If it is not magical just ignore it.
4026 */
4027
4028 if (SvROK(sv))
4029 sv = SvRV(sv);
4030
4031 if (SvTYPE(sv) == SVt_PVAV)
4032 {
4033 mgType = PERL_MAGIC_ext;
4034 }
4035
4036 if (SvMAGICAL(sv) && (mgp = &SvMAGIC(sv)))
4037 {
4038 MAGIC *mg;
4039 for (mg = *mgp; mg; mg = *mgp)
4040 {
4041 /*
4042 * Trawl through the linked list of magic looking
4043 * for the 'U' one which is our proc and ix.
4044 */
4045 if (mg->mg_type == mgType && mg->mg_ptr &&
4046 mg->mg_len == sizeof(struct ufuncs) &&
4047 ((struct ufuncs *) (mg->mg_ptr))->uf_set == Perl_Trace)
4048 {
4049 struct ufuncs *uf = (struct ufuncs *) (mg->mg_ptr);
4050 Tk_TraceInfo *p = INT2PTR(Tk_TraceInfo *, uf->uf_index);
4051 if (p && p->proc == tkproc && p->interp == interp &&
4052 p->clientData == clientData)
4053 {
4054 *mgp = mg->mg_moremagic;
4055 Tcl_DeleteExitHandler(TraceExitHandler, (ClientData) p);
4056 Safefree(p);
4057 uf->uf_index = 0;
4058 Safefree(mg->mg_ptr);
4059 mg->mg_ptr = NULL;
4060 Safefree(mg);
4061 }
4062 else
4063 mgp = &mg->mg_moremagic;
4064 }
4065 else
4066 mgp = &mg->mg_moremagic;
4067 }
4068 if (!SvMAGIC(sv))
4069 {
4070 SvMAGICAL_off(sv);
4071 if ((SvFLAGS(sv) & (SVp_IOK|SVp_NOK)) == (SVp_IOK|SVp_NOK))
4072 {
4073 /* RT #90077: if both SVp_IOK and SVp_NOK are set, then the
4074 * SVf_IOK must not be set, otherwise arithmetic operations
4075 * may use the wrong integer value
4076 */
4077 SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_NOK|SVp_POK)) >> PRIVSHIFT;
4078 }
4079 else
4080 {
4081 SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
4082 }
4083 }
4084 }
4085 }
4086
4087 int
Lang_TraceVar(interp,varName,flags,proc,clientData)4088 Lang_TraceVar(interp, varName, flags, proc, clientData)
4089 Tcl_Interp *interp;
4090 Var varName;
4091 int flags;
4092 Lang_VarTraceProc *proc;
4093 ClientData clientData;
4094 {
4095 return Lang_TraceVar2(interp, varName, NULL, flags, proc, clientData);
4096 }
4097
4098 Tcl_Obj *
LangFindVar(interp,tkwin,name)4099 LangFindVar(interp, tkwin, name)
4100 Tcl_Interp *interp;
4101 Tk_Window tkwin;
4102 CONST char *name;
4103 {
4104 dTHX;
4105 if (tkwin)
4106 {
4107 SV *sv = TkToWidget(tkwin,NULL);
4108 if (name == Tk_Name(tkwin))
4109 name = "Value";
4110 if (sv && SvROK(sv))
4111 {
4112 HV *hv = (HV *) SvRV(sv);
4113 STRLEN l = strlen(name);
4114 SV **x = hv_fetch(hv, name, l, 1);
4115 if (!x)
4116 x = hv_store(hv, name, l, newSVpv("", 0), 0);
4117 if (x)
4118 return SvREFCNT_inc(*x);
4119 }
4120 }
4121 else
4122 {
4123 SV *sv = FindTkVarName(name,1);
4124 if (sv)
4125 return SvREFCNT_inc(sv);
4126 }
4127 return newSVpv("", 0);
4128 }
4129
4130 int
LangStringMatch(string,match)4131 LangStringMatch(string, match)
4132 char *string;
4133 SV *match;
4134 {
4135 dTHX;
4136 STRLEN na;
4137 /* match could be a callback to perl sub to do re match */
4138 return Tcl_StringMatch(string, SvPV(match, na));
4139 }
4140
4141 int
LangSaveVar(interp,sv,vp,type)4142 LangSaveVar(interp,sv,vp,type)
4143 Tcl_Interp *interp;
4144 Tcl_Obj * sv;
4145 Var *vp;
4146 int type;
4147 {
4148 dTHX;
4149 STRLEN na;
4150 int old_taint = PL_tainted;
4151 TAINT_NOT;
4152 *vp = NULL;
4153 if (!sv)
4154 {
4155 return TCL_OK;
4156 }
4157 if (SvGMAGICAL(sv))
4158 mg_get(sv);
4159 if (SvROK(sv))
4160 {
4161 sv = SvRV(sv);
4162 if (sv == &PL_sv_undef)
4163 warn("variable is 'undef'");
4164 switch(type)
4165 {
4166 case TK_CONFIG_HASHVAR:
4167 if (SvTYPE(sv) != SVt_PVHV)
4168 EXPIRE((interp,"%s is not a hash",SvPV(sv,na)));
4169 break;
4170 case TK_CONFIG_ARRAYVAR:
4171 if (SvTYPE(sv) != SVt_PVAV)
4172 EXPIRE((interp,"%s is not an array",SvPV(sv,na)));
4173 break;
4174 default:
4175 case TK_CONFIG_SCALARVAR:
4176 break;
4177 }
4178 *vp = SvREFCNT_inc(sv);
4179 PL_tainted = old_taint;
4180 return TCL_OK;
4181 }
4182 else if (SvPOK(sv))
4183 {
4184 dTHX;
4185 HV *old_stash = CopSTASH(PL_curcop);
4186 char *name;
4187 SV *x = NULL;
4188 int prefix = '?';
4189 name = SvPV(sv,na);
4190 #ifdef CAN_COPSTASH_SET_NULL
4191 CopSTASH_set(PL_curcop, NULL);
4192 #else
4193 # ifdef USE_ITHREADS
4194 CopSTASHPV(PL_curcop) = NULL;
4195 # else
4196 CopSTASH(PL_curcop) = NULL;
4197 # endif
4198 #endif
4199 switch (type)
4200 {
4201 case TK_CONFIG_SCALARVAR:
4202 prefix = '$';
4203 default:
4204 if (!strchr(name,':'))
4205 {
4206 x = FindTkVarName(name,1);
4207 }
4208 else
4209 {
4210 x = perl_get_sv(name,1);
4211 }
4212 break;
4213 case TK_CONFIG_ARRAYVAR:
4214 x = (SV *) perl_get_av(name,TRUE);
4215 prefix = '@';
4216 break;
4217 case TK_CONFIG_HASHVAR:
4218 x = (SV *) perl_get_hv(name,TRUE);
4219 prefix = '%';
4220 break;
4221 }
4222 CopSTASH_set(PL_curcop, old_stash);
4223 if (x)
4224 {
4225 *vp = SvREFCNT_inc(x);
4226 PL_tainted = old_taint;
4227 return TCL_OK;
4228 }
4229 else
4230 Tcl_SprintfResult(interp,"%c%s does not exist",prefix,name);
4231 }
4232 else
4233 {
4234 Tcl_SprintfResult(interp,"Not a reference %s",SvPV(sv,na));
4235 }
4236 PL_tainted = old_taint;
4237 return TCL_ERROR;
4238 }
4239
4240 void
LangFreeVar(sv)4241 LangFreeVar(sv)
4242 Var sv;
4243 {
4244 dTHX;
4245 SvREFCNT_dec(sv);
4246 }
4247
4248 int
LangConfigObj(Tcl_Interp * interp,Tcl_Obj ** save,Tcl_Obj * obj,int type)4249 LangConfigObj(Tcl_Interp *interp, Tcl_Obj **save, Tcl_Obj *obj, int type)
4250 {
4251 dTHX;
4252 *save = Nullsv;
4253 switch (type)
4254 {
4255 case TK_OPTION_OBJ:
4256 if (obj)
4257 *save = LangCopyArg(obj);
4258 return TCL_OK;
4259 case TK_OPTION_CALLBACK:
4260 if (obj)
4261 *save = LangMakeCallback(obj);
4262 return TCL_OK;
4263 case TK_OPTION_SCALARVAR:
4264 return LangSaveVar(interp,obj,save,TK_CONFIG_SCALARVAR);
4265 case TK_OPTION_ARRAYVAR:
4266 return LangSaveVar(interp,obj,save,TK_CONFIG_ARRAYVAR);
4267 case TK_OPTION_HASHVAR:
4268 return LangSaveVar(interp,obj,save,TK_CONFIG_HASHVAR);
4269 default:
4270 Tcl_SprintfResult(interp,"Unexpected type %d for LangConfigObj(%"SVf")",
4271 type,obj);
4272 }
4273 return TCL_ERROR;
4274 }
4275
4276 int
Lang_CallWithArgs(interp,sub,argc,argv)4277 Lang_CallWithArgs(interp, sub, argc, argv)
4278 Tcl_Interp *interp;
4279 char *sub;
4280 int argc;
4281 SV *CONST *argv;
4282 {
4283 dTHX;
4284 dSP;
4285 STRLEN len;
4286 int count;
4287 SV *sv = newSVpv("",0);
4288 if (!strncmp(sub,"tk",2))
4289 {
4290 sv_catpv(sv,"Tk::");
4291 sub += 2;
4292 }
4293 sv_catpv(sv,sub);
4294 sub = SvPV(sv,len);
4295 ENTER;
4296 SAVETMPS;
4297 EXTEND(sp, argc);
4298 PUSHMARK(sp);
4299 while (argc-- > 0)
4300 {
4301 XPUSHs(*argv++);
4302 }
4303 PUTBACK;
4304 count = perl_call_pv(sub, G_EVAL|G_SCALAR);
4305 SetTclResult(interp,count);
4306 SvREFCNT_dec(sv);
4307 FREETMPS;
4308 LEAVE;
4309 return Check_Eval(interp);
4310 }
4311
4312 int
LangMethodCall(Tcl_Interp * interp,Tcl_Obj * sv,char * method,int result,int argc,...)4313 LangMethodCall
4314 #ifdef STANDARD_C
4315 _((Tcl_Interp * interp, Tcl_Obj * sv, char *method, int result, int argc,...))
4316 #else
4317 (interp, sv, method, result, argc, va_alist)
4318 Tcl_Interp *interp;
4319 SV *sv;
4320 char *method;
4321 int result;
4322 int argc;
4323 va_dcl
4324 #endif
4325 {
4326 dTHX;
4327 dSP;
4328 int flags = (result) ? 0 : G_DISCARD;
4329 int count = 0;
4330 int old_taint = PL_tainted;
4331 ENTER;
4332 SAVETMPS;
4333 PUSHMARK(sp);
4334 XPUSHs(sv_mortalcopy(sv));
4335 PUTBACK;
4336 if (argc)
4337 {
4338 va_list ap;
4339 #ifdef I_STDARG
4340 va_start(ap, argc);
4341 #else
4342 va_start(ap);
4343 #endif
4344 PushVarArgs(ap,argc);
4345 va_end(ap);
4346 }
4347 PL_tainted = 0;
4348 sv = sv_newmortal();
4349 sv_setpv(sv,method);
4350 PL_tainted = old_taint;
4351 count = LangCallCallback(sv, flags | G_EVAL);
4352 if (result)
4353 SetTclResult(interp,count);
4354 FREETMPS;
4355 LEAVE;
4356 return Check_Eval(interp);
4357 }
4358
4359 int
Tcl_EvalObjEx(Tcl_Interp * interp,Tcl_Obj * objPtr,int flags)4360 Tcl_EvalObjEx (Tcl_Interp *interp,Tcl_Obj *objPtr, int flags)
4361 {
4362 dTHX;
4363 int code;
4364 SV *cb = LangMakeCallback(objPtr);
4365 SV *sv = cb;
4366 SvREFCNT_inc(interp);
4367 ENTER;
4368 SAVETMPS;
4369 if (PushCallbackArgs(interp,&sv) == TCL_OK)
4370 {
4371 int count = LangCallCallback(sv, G_SCALAR | G_EVAL);
4372 SetTclResult(interp,count);
4373 }
4374 FREETMPS;
4375 LEAVE;
4376 SvREFCNT_dec(cb);
4377 code = Check_Eval(interp);
4378 SvREFCNT_dec(interp);
4379 return code;
4380 }
4381
4382 int
Tcl_EvalObj(Tcl_Interp * interp,Tcl_Obj * objPtr)4383 Tcl_EvalObj(Tcl_Interp *interp,Tcl_Obj *objPtr)
4384 {
4385 return Tcl_EvalObjEx(interp,objPtr,0);
4386 }
4387
4388 /*
4389 * Tcl_EvalObjv is used by tkMenu.c's CloneMenu
4390 * In order to allow Tk::Menu::tkMenuDup to return
4391 * the "object" for the created menu we pass actual
4392 * objects not mortal copies.
4393 * We also avoid the overhead of creating, blessing and destroying
4394 * "Callback" object.
4395 */
4396
4397 int
Tcl_EvalObjv(Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[],int flags)4398 Tcl_EvalObjv(Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[], int flags)
4399 {
4400 SV *sv = objv[0];
4401 int i;
4402 dTHX;
4403 dSP;
4404 ENTER;
4405 SAVETMPS;
4406 PUSHMARK(sp);
4407 for (i=1; i < objc; i++)
4408 {
4409 XPUSHs(objv[i]);
4410 }
4411 PUTBACK;
4412 i = LangCallCallback(sv, G_SCALAR | G_EVAL);
4413 SetTclResult(interp,i);
4414 FREETMPS;
4415 LEAVE;
4416 return Check_Eval(interp);
4417 }
4418
4419 int
Tcl_GlobalEval(Tcl_Interp * interp,CONST char * command)4420 Tcl_GlobalEval(Tcl_Interp *interp, CONST char *command)
4421 {
4422 dTHX;
4423 if (!PL_tainting)
4424 {
4425 warn("Receive from Tk's 'send' ignored (no taint checking)\n");
4426 return EXPIRE((interp,"send to non-secure perl/Tk application rejected\n"));
4427 }
4428 else
4429 {
4430 dSP;
4431 int count = 0;
4432 int old_taint = PL_tainted;
4433 SV *sv;
4434 PL_tainted = 0;
4435 ENTER;
4436 SAVETMPS;
4437 PUSHMARK(sp);
4438 Set_widget(sv = WidgetRef(interp,"."));
4439 XPUSHs(sv_mortalcopy(sv));
4440 PL_tainted = 1;
4441 sv = newSVpv(command,strlen(command));
4442 SvTAINT(sv);
4443 PL_tainted = 0;
4444 XPUSHs(sv_2mortal(sv));
4445 PUTBACK;
4446 Tcl_ResetResult(interp);
4447 Lang_ClearErrorInfo(interp);
4448 sv = sv_2mortal(newSVpv("Receive",0));
4449 PL_tainted = old_taint;
4450 count = LangCallCallback(sv, G_ARRAY | G_EVAL);
4451 SetTclResult(interp,count);
4452 FREETMPS;
4453 LEAVE;
4454 return Check_Eval(interp);
4455 }
4456 }
4457
XS(XS_Tk__Widget_BindClientMessage)4458 XS(XS_Tk__Widget_BindClientMessage)
4459 {
4460 dXSARGS;
4461 if (items >= 1)
4462 {
4463 HV *hv = NULL;
4464 Lang_CmdInfo *info = WindowCommand(ST(0), &hv, 2);
4465 if (info)
4466 {
4467 HV *cm = FindHv(aTHX_ hv, "BindClientMessage", (items > 2), CM_KEY);
4468 if (items >= 2)
4469 {
4470 STRLEN len;
4471 char *key = SvPV(ST(1),len);
4472 if (items > 2)
4473 {
4474 SV *cb = LangMakeCallback(ST(2));
4475 hv_store(cm, key, len, cb ,0);
4476 }
4477 else
4478 {
4479 if (cm)
4480 {
4481 SV **x = hv_fetch(cm, key, len, 0);
4482 if (x)
4483 ST(0) = sv_mortalcopy(*x);
4484 }
4485 }
4486 }
4487 else
4488 {
4489 if (cm)
4490 ST(0) = sv_2mortal(newRV((SV *) cm));
4491 }
4492 }
4493 }
4494 else
4495 croak("Usage: $w->BindClientMessage(atom,callback)");
4496 XSRETURN(1);
4497 }
4498
4499 #ifdef WIN32
4500 int
Lang_WinEvent(tkwin,message,wParam,lParam,resultPtr)4501 Lang_WinEvent(tkwin, message, wParam, lParam, resultPtr)
4502 Tk_Window tkwin;
4503 UINT message;
4504 WPARAM wParam;
4505 LPARAM lParam;
4506 LRESULT *resultPtr;
4507 {
4508 dTHX;
4509 Tcl_Interp *interp = NULL;
4510 SV *w = TkToWidget(tkwin,&interp);
4511 char key[32];
4512 HV *cm = NULL;
4513 STRLEN na;
4514 int code = 0;
4515 if ( !interp || !w || !SvROK(w))
4516 {
4517 return 0;
4518 }
4519 sprintf(key,"%d",message);
4520 if (SvROK(w))
4521 cm = FindHv(aTHX_ (HV *) SvRV(w),"Lang_WinMessage",0,CM_KEY);
4522 if (cm)
4523 {
4524 SV **x = hv_fetch(cm,key,strlen(key),0);
4525 SV *sv;
4526 if (!x)
4527 x = hv_fetch(cm,"0",1,0);
4528 if (x && (sv = *x))
4529 {
4530 dSP;
4531 SV *data = struct_sv(NULL, sizeof(EventAndKeySym));
4532 EventAndKeySym *info = (EventAndKeySym *) SvPVX(data);
4533 int result;
4534 #if 0
4535 LangDebug("%s %d '%s'\n",Tk_PathName(tkwin), message,SvPV(sv,na));
4536 #endif
4537 info->keySym = 0;
4538 info->interp = interp;
4539 info->window = w;
4540 info->tkwin = tkwin;
4541 ENTER;
4542 SAVETMPS;
4543 Tcl_ResetResult(interp);
4544 Lang_ClearErrorInfo(interp);
4545 Set_widget(w);
4546 result = PushObjCallbackArgs(interp,&sv,info);
4547 SPAGAIN;
4548 if (result == TCL_OK)
4549 {
4550 XPUSHs(sv_2mortal(newSViv(message)));
4551 XPUSHs(sv_2mortal(newSViv(wParam)));
4552 XPUSHs(sv_2mortal(newSViv(lParam)));
4553 PUTBACK;
4554 result = LangCallCallback(sv, G_DISCARD | G_EVAL);
4555 if (result)
4556 {
4557 SPAGAIN;
4558 sv = POPs;
4559 PUTBACK;
4560 if (SvIOK(sv))
4561 {
4562 *resultPtr = SvIV(sv);
4563 code = 1;
4564 }
4565 }
4566 }
4567 Lang_MaybeError(interp,Check_Eval(interp),"ClientMessage handler");
4568 FREETMPS;
4569 LEAVE;
4570 }
4571 }
4572 return code;
4573 }
4574 #endif /* WIN32 */
4575
4576 void
LangClientMessage(interp,tkwin,event)4577 LangClientMessage(interp, tkwin, event)
4578 Tcl_Interp *interp;
4579 Tk_Window tkwin;
4580 XEvent *event;
4581 {
4582 dTHX;
4583 SV *w = TkToWidget(tkwin,NULL);
4584 CONST char *key;
4585 HV *cm = NULL;
4586 if (!SvROK(w))
4587 {
4588 Tk_Window mainwin = (Tk_Window)((((TkWindow*)tkwin)->mainPtr)->winPtr);
4589 w = TkToWidget(mainwin,NULL);
4590 }
4591 key = Tk_GetAtomName(tkwin, event->xclient.message_type);
4592 if (SvROK(w))
4593 cm = FindHv(aTHX_ (HV *) SvRV(w),"LangClientMessage",0,CM_KEY);
4594 if (cm)
4595 {
4596 SV **x = hv_fetch(cm,key,strlen(key),0);
4597 SV *sv;
4598 if (!x)
4599 x = hv_fetch(cm,"any",3,0);
4600 if (x && (sv = *x))
4601 {
4602 dSP;
4603 SV *data = struct_sv(NULL, sizeof(EventAndKeySym));
4604 EventAndKeySym *info = (EventAndKeySym *) SvPVX(data);
4605 SV *e = Blessed("XEvent", MakeReference(data));
4606 int result;
4607 info->event = *event;
4608 info->keySym = 0;
4609 info->interp = interp;
4610 info->window = w;
4611 info->tkwin = tkwin;
4612 ENTER;
4613 SAVETMPS;
4614 Tcl_ResetResult(interp);
4615 Lang_ClearErrorInfo(interp);
4616 Set_widget(w);
4617 Set_event(e);
4618 if (SvROK(w))
4619 {
4620 HV *hash = (HV *) SvRV(w);
4621 hv_store(hash, XEVENT_KEY, strlen(XEVENT_KEY), e, 0);
4622 }
4623 else
4624 Decrement(e,"Unused Event");
4625 result = PushObjCallbackArgs(interp,&sv,info);
4626 if (result == TCL_OK)
4627 LangCallCallback(sv, G_DISCARD | G_EVAL);
4628 Lang_MaybeError(interp,Check_Eval(interp),"ClientMessage handler");
4629 if (0 && SvROK(w))
4630 {
4631 HV *hash = (HV *) SvRV(w);
4632 hv_delete(hash, XEVENT_KEY, strlen(XEVENT_KEY), G_DISCARD);
4633 }
4634 FREETMPS;
4635 LEAVE;
4636 }
4637 #if 0
4638 else
4639 {
4640 warn("%s has no handler for '%s'\n",Tk_PathName(tkwin),key);
4641 }
4642 #endif
4643 }
4644 #if 0
4645 else
4646 {
4647 warn("ClientMessage '%s' for %s\n", key, Tk_PathName(tkwin));
4648 }
4649 #endif
4650 }
4651
4652 int
LangEventCallback(cdata,interp,event,tkwin,keySym)4653 LangEventCallback(cdata, interp, event, tkwin, keySym)
4654 ClientData cdata;
4655 Tcl_Interp *interp;
4656 Tk_Window tkwin;
4657 XEvent *event;
4658 KeySym keySym;
4659 {
4660 dTHX;
4661 SV *sv = (SV *) cdata;
4662 int result = TCL_ERROR;
4663 Tk_Window ewin = Tk_EventWindow(event);
4664 #ifdef LEAK_CHECKING
4665 hash_ptr *save = NULL;
4666 long hwm = note_used(&save);
4667 fprintf(stderr, "Event Entry count=%ld hwm=%ld\n", ec = sv_count, hwm);
4668 #endif
4669 Tcl_ResetResult(interp);
4670 Lang_ClearErrorInfo(interp);
4671 if (!SvOK(sv))
4672 {
4673 Tcl_SetResult(interp,"Call of undefined callback",TCL_STATIC);
4674 return TCL_ERROR;
4675 }
4676 if (ewin && tkwin)
4677 {
4678 dSP;
4679 int code;
4680 SV *data = struct_sv(NULL, sizeof(EventAndKeySym));
4681 EventAndKeySym *info = (EventAndKeySym *) SvPVX(data);
4682 SV *e = Blessed("XEvent", MakeReference(data));
4683 SV *w = TkToWidget(tkwin,NULL);
4684 #ifdef DEBUG_GLUE
4685 fprintf(stderr, "%s:%s(%s) = %p\n", "LangEventCallback", SvPV_nolen(sv), Tk_PathName(tkwin), info);
4686 #endif
4687 info->event = *event;
4688 info->keySym = keySym;
4689 info->interp = interp;
4690 info->window = w;
4691 info->tkwin = tkwin;
4692 ENTER;
4693 PUSHSTACKi(PERLSI_MAGIC);
4694 SAVETMPS;
4695 PUTBACK;
4696 Tcl_ResetResult(interp);
4697 Lang_ClearErrorInfo(interp);
4698 Set_widget(w);
4699 Set_event(e);
4700 result = PushObjCallbackArgs(interp,&sv,info);
4701 if (SvROK(w))
4702 {
4703 HV *hash = (HV *) SvRV(w);
4704 hv_store(hash, XEVENT_KEY, strlen(XEVENT_KEY), e, 0);
4705 }
4706 else
4707 Decrement(e,"Unused Event");
4708 if (result == TCL_OK)
4709 {
4710 LangCallCallback(sv, G_DISCARD | G_EVAL);
4711 FREETMPS;
4712 result = Check_Eval(interp);
4713 }
4714 if (0 && SvROK(w))
4715 {
4716 HV *hash = (HV *) SvRV(w);
4717 hv_delete(hash, XEVENT_KEY, strlen(XEVENT_KEY), G_DISCARD);
4718 }
4719 POPSTACK;
4720 LEAVE;
4721 }
4722 else
4723 {
4724 /*
4725 * Event pertains to a window which has been/is being deleted.
4726 * Although we may be able to call perl code we cannot make
4727 * any method calls because the widget hash object has probably vanished.
4728 *
4729 * Quietly return "OK" having done nothing
4730 */
4731 result = TCL_OK;
4732 }
4733 #ifdef LEAK_CHECKING
4734 fprintf(stderr, "sv_count was %ld, now %ld (%ld)\n", ec, sv_count, sv_count - ec);
4735 check_used(&save);
4736 #endif
4737 return result;
4738 }
4739
4740 void
LangFreeArg(sv,freeProc)4741 LangFreeArg(sv, freeProc)
4742 Tcl_Obj * sv;
4743 Tcl_FreeProc *freeProc;
4744 {
4745 dTHX;
4746 Decrement(sv, "LangFreeArg");
4747 }
4748
4749 static int
handle_generic(clientData,eventPtr)4750 handle_generic(clientData, eventPtr)
4751 ClientData clientData;
4752 XEvent *eventPtr;
4753 {
4754 int code = 0;
4755 Tk_Window tkwin = Tk_EventWindow(eventPtr);
4756 if (tkwin)
4757 {
4758 GenericInfo *p = (GenericInfo *) clientData;
4759 Tcl_Interp *interp = p->interp;
4760 SV *sv = p->cb;
4761 dTHX;
4762 dSP;
4763 SV *data = struct_sv(NULL, sizeof(EventAndKeySym));
4764 EventAndKeySym *info = (EventAndKeySym *) SvPVX(data);
4765 SV *e = Blessed("XEvent", MakeReference(data));
4766 SV *w = NULL;
4767 int count = 0;
4768 int result;
4769 info->event = *eventPtr;
4770 info->keySym = None;
4771 info->interp = interp;
4772 info->tkwin = tkwin;
4773 do_watch();
4774 Tcl_ResetResult(interp);
4775 Lang_ClearErrorInfo(interp);
4776 ENTER;
4777 SAVETMPS;
4778 if (tkwin)
4779 w = TkToWidget(tkwin,&info->interp); /* Pending REFCNT */
4780 if (!SvROK(w))
4781 w = Blessed("Window", MakeReference(newSViv((IV) (eventPtr->xany.window))));
4782 else
4783 Set_widget(w);
4784 result = PushObjCallbackArgs(interp, &sv,info);
4785 if (result == TCL_OK)
4786 {
4787 SPAGAIN;
4788 Set_event(e);
4789 XPUSHs(sv_mortalcopy(e));
4790 XPUSHs(sv_mortalcopy(w));
4791 PUTBACK;
4792 count = LangCallCallback(sv, G_EVAL);
4793 result = Check_Eval(interp);
4794 }
4795 if (count)
4796 {
4797 SPAGAIN;
4798 code = TOPi;
4799 sp -= count;
4800 PUTBACK;
4801 }
4802 else
4803 code = 0;
4804 Lang_MaybeError(interp,result,"Generic Event");
4805
4806 FREETMPS;
4807 LEAVE;
4808 }
4809 return code;
4810 }
4811
4812 static void
Perl_GeomRequest(clientData,tkwin)4813 Perl_GeomRequest(clientData,tkwin)
4814 ClientData clientData;
4815 Tk_Window tkwin;
4816 {
4817 Lang_CmdInfo *info = (Lang_CmdInfo *) clientData;
4818 SV *master = TkToWidget(info->tkwin,NULL);
4819 SV *slave = TkToWidget(tkwin,NULL);
4820 dTHX;
4821 dSP;
4822 ENTER;
4823 SAVETMPS;
4824 Set_widget(master);
4825 PUSHMARK(sp);
4826 XPUSHs(sv_mortalcopy(master));
4827 XPUSHs(sv_mortalcopy(slave));
4828 PUTBACK;
4829 LangCallCallback(sv_2mortal(newSVpv("SlaveGeometryRequest",0)),G_DISCARD);
4830 FREETMPS;
4831 LEAVE;
4832 }
4833
4834 static void
Perl_GeomLostSlave(clientData,tkwin)4835 Perl_GeomLostSlave(clientData,tkwin)
4836 ClientData clientData;
4837 Tk_Window tkwin;
4838 {
4839 Lang_CmdInfo *info = (Lang_CmdInfo *) clientData;
4840 SV *master = TkToWidget(info->tkwin,NULL);
4841 SV *slave = TkToWidget(tkwin,NULL);
4842 dTHX;
4843 dSP;
4844 ENTER;
4845 SAVETMPS;
4846 PUSHMARK(sp);
4847 Set_widget(master);
4848 XPUSHs(sv_mortalcopy(master));
4849 XPUSHs(sv_mortalcopy(slave));
4850 PUTBACK;
4851 LangCallCallback(sv_2mortal(newSVpv("LostSlave",0)),G_DISCARD);
4852 FREETMPS;
4853 LEAVE;
4854 }
4855
XS(XS_Tk__Widget_ManageGeometry)4856 XS(XS_Tk__Widget_ManageGeometry)
4857 {
4858 dXSARGS;
4859 STRLEN na;
4860 if (items == 2)
4861 {
4862 HV *hash = NULL;
4863 Lang_CmdInfo *info = WindowCommand(ST(0), &hash, 0);
4864 if (info && info->tkwin)
4865 {
4866 Lang_CmdInfo *slave = WindowCommand(ST(1), NULL, 0);
4867 if (slave && slave->tkwin)
4868 {
4869 SV **x = hv_fetch(hash,GEOMETRY_KEY,strlen(GEOMETRY_KEY),0);
4870 SV *mgr_sv = NULL;
4871 if (!x)
4872 {
4873 Tk_GeomMgr mgr;
4874 mgr.name = Tk_PathName(info->tkwin);
4875 mgr.requestProc = Perl_GeomRequest;
4876 mgr.lostSlaveProc = Perl_GeomLostSlave;
4877 mgr_sv = struct_sv((char *) &mgr,sizeof(mgr));
4878 hv_store(hash,GEOMETRY_KEY,strlen(GEOMETRY_KEY),mgr_sv, 0);
4879 }
4880 else
4881 mgr_sv = *x;
4882 Tk_ManageGeometry(slave->tkwin, (Tk_GeomMgr *) SvPV(mgr_sv,na), (ClientData) info);
4883 }
4884 else
4885 croak("Not a (slave) widget %s",SvPV(ST(1),na));
4886 }
4887 else
4888 croak("Not a (master) widget %s",SvPV(ST(0),na));
4889 }
4890 else
4891 croak("usage $master->ManageGeometry($slave)");
4892 XSRETURN(1);
4893 }
4894
4895 static void
handle_idle(clientData)4896 handle_idle(clientData)
4897 ClientData clientData;
4898 {
4899 dTHX;
4900 GenericInfo *p = (GenericInfo *) clientData;
4901 SV *sv = p->cb;
4902 dSP;
4903 int count = 0;
4904 int code = 0;
4905 ENTER;
4906 SAVETMPS;
4907 Tcl_ResetResult(p->interp);
4908 Lang_ClearErrorInfo(p->interp);
4909 Set_widget(WidgetRef(p->interp,"."));
4910 code = PushCallbackArgs(p->interp,&sv);
4911 if (code == TCL_OK)
4912 {
4913 LangCallCallback(sv, G_DISCARD | G_EVAL);
4914 code = Check_Eval(p->interp);
4915 }
4916 Lang_MaybeError(p->interp,code,"Idle Callback");
4917 FREETMPS;
4918 LEAVE;
4919 LangFreeCallback(p->cb);
4920 DecInterp(p->interp, "handle_idle");
4921 ckfree((char *) p);
4922 }
4923
4924
XS(XS_Tk_DoWhenIdle)4925 XS(XS_Tk_DoWhenIdle)
4926 {
4927 dXSARGS;
4928 STRLEN na;
4929 if (items == 2)
4930 {
4931 Lang_CmdInfo *info = WindowCommand(ST(0), NULL, 0);
4932 if (info && info->interp && (info->tkwin || info->image))
4933 {
4934 /* Try to get result to prove things are "still alive" */
4935 if (Tcl_GetObjResult(info->interp))
4936 {
4937 GenericInfo *p = (GenericInfo *) ckalloc(sizeof(GenericInfo));
4938 IncInterp(info->interp,"Tk_DoWhenIdle");
4939 p->interp = info->interp;
4940 p->cb = LangMakeCallback(ST(1));
4941 Tcl_DoWhenIdle(handle_idle, (ClientData) p);
4942 }
4943 }
4944 else
4945 croak("Not a widget %s",SvPV(ST(0),na));
4946 }
4947 else
4948 croak("Usage $w->DoWhenIdle(callback)");
4949 XSRETURN(1);
4950 }
4951
XS(XS_Tk_CreateGenericHandler)4952 XS(XS_Tk_CreateGenericHandler)
4953 {
4954 dXSARGS;
4955 STRLEN na;
4956 if (items == 2)
4957 {
4958 Lang_CmdInfo *info = WindowCommand(ST(0), NULL, 0);
4959 if (info && info->interp && (info->tkwin || info->image))
4960 {
4961 if (Tcl_GetObjResult(info->interp))
4962 {
4963 GenericInfo *p = (GenericInfo *) ckalloc(sizeof(GenericInfo));
4964 IncInterp(info->interp,"Tk_CreateGenericHandler");
4965 p->interp = info->interp;
4966 p->cb = LangMakeCallback(ST(1));
4967 Tk_CreateGenericHandler(handle_generic, (ClientData) p);
4968 }
4969 }
4970 else
4971 croak("Not a widget %s",SvPV(ST(0),na));
4972 }
4973 else
4974 croak("Usage $w->CreateGenericHandler(callback)");
4975 XSRETURN(1);
4976 }
4977
4978
4979 SV *
XEvent_Info(obj,s)4980 XEvent_Info(obj,s)
4981 EventAndKeySym *obj;
4982 char *s;
4983 {
4984 dTHX;
4985 SV *eventSv = sv_newmortal();
4986 I32 ix = (I32) *s;
4987 char scratch[256];
4988 if (obj)
4989 {
4990 if (ix == '@' || strncmp(s,"xy",2) == 0)
4991 {
4992 char result[80];
4993 strcpy(result, "@");
4994 strcat(result, Tk_EventInfo('x', obj->tkwin, &obj->event, obj->keySym, NULL, NULL, NULL, sizeof(scratch) - 1, scratch));
4995 strcat(result, ",");
4996 strcat(result, Tk_EventInfo('y', obj->tkwin, &obj->event, obj->keySym, NULL, NULL, NULL, sizeof(scratch) - 1, scratch));
4997 sv_setpv(eventSv, result);
4998 }
4999 else
5000 {
5001 int isNum = 0;
5002 int number = 0;
5003 int type = TK_EVENTTYPE_NONE;
5004 char *result = Tk_EventInfo(ix, obj->tkwin, &obj->event, obj->keySym, &number, &isNum, &type, sizeof(scratch) - 1, scratch);
5005 switch (type)
5006 {
5007 case TK_EVENTTYPE_WINDOW:
5008 {
5009 SV *w = &PL_sv_undef;
5010 if (result && result[0] == '.')
5011 w = WidgetRef(obj->interp, result);
5012 if (SvROK(w))
5013 SvSetMagicSV(eventSv, w);
5014 else
5015 {
5016 if (number)
5017 sv_setref_iv(eventSv, "Window", number);
5018 }
5019 }
5020 break;
5021
5022 case TK_EVENTTYPE_DISPLAY:
5023 sv_setref_pv(eventSv, "DisplayPtr", (void *) number);
5024 break;
5025
5026 case TK_EVENTTYPE_DATA:
5027 sv_setpvn(eventSv, result, (unsigned) number);
5028 break;
5029
5030 default:
5031 if (result) {
5032 sv_setpv(eventSv, result);
5033 }
5034 if (isNum)
5035 {
5036 sv_setiv(eventSv, number);
5037 if (result)
5038 SvPOK_on(eventSv);
5039 }
5040 break;
5041 }
5042 }
5043 }
5044 return sv_maybe_utf8(eventSv);
5045 }
5046
5047 EventAndKeySym *
SVtoEventAndKeySym(SV * arg)5048 SVtoEventAndKeySym(SV *arg)
5049 {
5050 dTHX;
5051 SV *sv;
5052 if (sv_isobject(arg) && (sv = SvRV(arg)) &&
5053 SvPOK(sv) && SvCUR(sv) == sizeof(EventAndKeySym))
5054 {
5055 return (EventAndKeySym *) SvPVX(sv);
5056 }
5057 else
5058 croak("obj is not an XEvent");
5059 return NULL;
5060 }
5061
XS(XS_Tk__Widget_PassEvent)5062 XS(XS_Tk__Widget_PassEvent)
5063 {
5064 dXSARGS;
5065 Tk_Window tkwin = NULL;
5066 EventAndKeySym *obj = NULL;
5067 if (items == 2
5068 && (tkwin = (Tk_Window) SVtoWindow(ST(0)))
5069 && (obj = SVtoEventAndKeySym(ST(1)))
5070 )
5071 {
5072 if (Tk_WindowId(tkwin) == None)
5073 Tk_MakeWindowExist(tkwin);
5074 TkBindEventProc((TkWindow *)tkwin, &obj->event);
5075 }
5076 else
5077 croak("Usage: $widget->PassEvent($event)");
5078 ST(0) = &PL_sv_undef;
5079 XSRETURN(1);
5080 }
5081
5082
5083 void
Tk_ChangeScreen(interp,dispName,screenIndex)5084 Tk_ChangeScreen(interp, dispName, screenIndex)
5085 Tcl_Interp *interp;
5086 char *dispName;
5087 int screenIndex;
5088 {
5089
5090 }
5091
5092
5093 /* These are for file name handling which needs further abstraction */
5094
5095 char *
Tcl_TranslateFileName(interp,name,bufferPtr)5096 Tcl_TranslateFileName(interp, name, bufferPtr)
5097 Tcl_Interp *interp;
5098 CONST char *name;
5099 Tcl_DString *bufferPtr;
5100 {
5101 dTHX;
5102 dSP;
5103 IV count;
5104 ENTER;
5105 SAVETMPS;
5106 PUSHMARK(sp);
5107 XPUSHs(sv_2mortal(newSVpv((char *) name,0)));
5108 PUTBACK;
5109 perl_call_pv("Tk::TranslateFileName",G_EVAL|G_SCALAR);
5110 SPAGAIN;
5111 *bufferPtr = POPs;
5112 PUTBACK;
5113 SvREFCNT_inc(*bufferPtr);
5114 FREETMPS;
5115 LEAVE;
5116 return Tcl_DStringValue(bufferPtr);
5117 }
5118
5119 CONST char *
Tcl_PosixError(interp)5120 Tcl_PosixError(interp)
5121 Tcl_Interp *interp;
5122 {
5123 dTHX;
5124 return Strerror(errno);
5125 }
5126
5127 #ifdef STANDARD_C
5128 void
EnterWidgetMethods(char * package,...)5129 EnterWidgetMethods(char *package,...)
5130 #else
5131 /*VARARGS0 */
5132 void
5133 EnterWidgetMethods(package, va_alist)
5134 char *package;
5135 va_dcl
5136 #endif
5137 {
5138 dTHX;
5139 va_list ap;
5140 char buf[80];
5141 char *method;
5142 #ifdef I_STDARG
5143 va_start(ap, package);
5144 #else
5145 va_start(ap);
5146 #endif
5147 while ((method = va_arg(ap, char *)))
5148 {
5149 CV *cv;
5150 if (strcmp(method, "configure") && strcmp(method, "cget"))
5151 {
5152 sprintf(buf, "Tk::%s::%s", package, method);
5153 cv = newXS(buf, XStoWidget, __FILE__);
5154 CvXSUBANY(cv).any_ptr = newSVpv(method, 0);
5155 }
5156 }
5157 }
5158
5159 void
Lang_SetErrorCode(interp,code)5160 Lang_SetErrorCode(interp, code)
5161 Tcl_Interp *interp;
5162 char *code;
5163 {
5164
5165 }
5166
5167 void
Tcl_SetObjErrorCode(Tcl_Interp * interp,Tcl_Obj * errorObjPtr)5168 Tcl_SetObjErrorCode (Tcl_Interp * interp,Tcl_Obj * errorObjPtr)
5169 {
5170
5171 }
5172
5173 char *
Lang_GetErrorCode(interp)5174 Lang_GetErrorCode(interp)
5175 Tcl_Interp *interp;
5176 {
5177 warn("Lang_GetErrorCode not implemented");
5178 return "";
5179 }
5180
5181 char *
Lang_GetErrorInfo(interp)5182 Lang_GetErrorInfo(interp)
5183 Tcl_Interp *interp;
5184 {
5185 warn("Lang_GetErrorInfo not implemented");
5186 return "";
5187 }
5188
5189 void
LangBadFile(fd)5190 LangBadFile(fd)
5191 int fd;
5192 {
5193 warn("File (%d) closed without deleting handler",fd);
5194 }
5195
5196 int
LangEventHook(flags)5197 LangEventHook(flags)
5198 int flags;
5199 /* Used by Tcl_Async stuff for signal handling */
5200 {
5201 #if 0
5202 #if defined(WNOHANG) && (defined(HAS_WAITPID) || defined(HAS_WAIT4))
5203 int status = -1;
5204 I32 pid = wait4pid(-1,&status,WNOHANG);
5205 if (pid > 0)
5206 {
5207 pidgone(pid, status);
5208 warn("Child process %d status=%d",pid,status);
5209 return 1;
5210 }
5211 #endif
5212 #endif
5213 return 0;
5214 }
5215
5216 /* Tcl caches compiled regexps so does not free them */
5217
5218 struct WrappedRegExp
5219 {
5220 #if HAS_PMOP_EXTRA_FLAGS
5221 PMOP op;
5222 #else
5223 U32 flags;
5224 #endif
5225 #if USE_REGEXP_511
5226 REGEXP *pat;
5227 #else
5228 regexp *pat;
5229 #endif
5230 SV *source;
5231 };
5232
5233 void
Lang_FreeRegExp(re)5234 Lang_FreeRegExp(re)
5235 Tcl_RegExp re;
5236 {
5237 dTHX;
5238 if (re->pat)
5239 ReREFCNT_dec(re->pat);
5240 if (re->source)
5241 SvREFCNT_dec(re->source);
5242 Safefree(re);
5243 }
5244
5245 /* An "XS" routine to call with G_EVAL set */
5246 static void
do_comp(pTHX_ CV * cv)5247 do_comp(pTHX_ CV *cv)
5248 {
5249 dMARK;
5250 dAX;
5251 struct WrappedRegExp *p = (struct WrappedRegExp *) CvXSUBANY(cv).any_ptr;
5252 #if USE_PREGCOMP_31027
5253 p->pat = pregcomp(p->source,p->flags);
5254 #else /* USE_PREGCOMP_31027 */
5255 int len = 0;
5256 char *string = Tcl_GetStringFromObj(p->source,&len);
5257
5258 #if HAS_PMOP_EXTRA_FLAGS
5259 p->op.op_pmdynflags |= PMdf_DYN_UTF8;
5260 p->pat = pregcomp(string,string+len,&p->op);
5261 #else
5262 p->pat = pregcomp(string,string+len,p->flags);
5263 #endif
5264 #if 0
5265 LangDebug("/%.*s/ => %p\n",len,string,p->pat);
5266 #endif
5267 #endif /* USE_PREGCOMP_31027 */
5268 XSRETURN(0);
5269 }
5270
5271 I32
Lang_catch(pTHX_ XSUBADDR_t subaddr,void * any,I32 flags,char * filename)5272 Lang_catch(pTHX_ XSUBADDR_t subaddr, void *any, I32 flags,char *filename)
5273 {
5274 dSP;
5275 CV *cv = (CV *) sv_newmortal();
5276 int count;
5277 SV **oldSP = sp;
5278 sv_upgrade((SV *)cv, SVt_PVCV);
5279 CvFILE(cv) = filename;
5280 CvXSUB(cv) = subaddr;
5281 CvXSUBANY(cv).any_ptr = any;
5282 #ifdef CvISXSUB_on
5283 CvISXSUB_on(cv); /* this is needed for perl5.9@27244 */
5284 #endif
5285 count = call_sv((SV *)cv,flags|G_EVAL);
5286 SPAGAIN;
5287 if (sp != oldSP)
5288 {
5289 LangDebug("Stack moved %p => %p\n",oldSP,sp);
5290 }
5291 return count;
5292 }
5293
5294 Tcl_RegExp
Tcl_GetRegExpFromObj(Tcl_Interp * interp,Tcl_Obj * obj,int flags)5295 Tcl_GetRegExpFromObj(Tcl_Interp *interp, Tcl_Obj *obj, int flags)
5296 {
5297 dTHX;
5298 Tcl_RegExp re;
5299 MAGIC *mg = Null(MAGIC*);
5300
5301 Newz('R', re, 1, struct WrappedRegExp);
5302
5303 re->source = Tcl_DuplicateObj(obj);
5304
5305 /* If source is a reference and thing refrered to has right
5306 magic we can use regexp from the qr//
5307 */
5308 if (SvROK(re->source)) {
5309 SV *sv = SvRV(re->source);
5310 if(SvMAGICAL(sv))
5311 mg = mg_find(sv, PERL_MAGIC_qr);
5312 }
5313
5314 #if HAS_PMOP_EXTRA_FLAGS
5315 /* Could do more conversions here
5316 Not sure how/if to override case-ness of qr// pattern
5317 */
5318 if (flags & TCL_REG_NOCASE) {
5319 re->op.op_pmflags |= PMf_FOLD;
5320 }
5321 #else
5322 #if USE_REGEXP_511
5323 re->flags = (flags & TCL_REG_NOCASE ? RXf_PMf_FOLD : 0);
5324 #else
5325 re->flags = RXf_UTF8 | (flags & TCL_REG_NOCASE ? RXf_PMf_FOLD : 0);
5326 #endif
5327 #endif
5328
5329 if (mg)
5330 {
5331 #if USE_REGEXP_511
5332 re->pat = (REGEXP *)mg->mg_obj;
5333 #else
5334 re->pat = (regexp *)mg->mg_obj;
5335 #endif
5336 /* Guess wildly ... */
5337 ReREFCNT_inc(re->pat);
5338 }
5339 else
5340 {
5341 dSP;
5342 SV *err;
5343 ENTER;
5344 SAVETMPS;
5345 PUSHMARK(sp);
5346 Lang_catch(aTHX_ do_comp, re, G_VOID, __FILE__);
5347 FREETMPS;
5348 LEAVE;
5349 err = ERRSV;
5350 if (SvTRUE(err))
5351 {
5352 Lang_FreeRegExp(re);
5353 Tcl_SetResult(interp,SvPV_nolen(err),TCL_VOLATILE);
5354 return NULL;
5355 }
5356 }
5357 return re;
5358 }
5359
5360 int
Tcl_RegExpExec(interp,re,cstring,cstart)5361 Tcl_RegExpExec(interp, re, cstring, cstart)
5362 Tcl_Interp *interp;
5363 Tcl_RegExp re;
5364 CONST char *cstring;
5365 CONST char *cstart;
5366 {
5367 dTHX;
5368 SV *tmp = sv_newmortal();
5369 int code;
5370 sv_upgrade(tmp,SVt_PV);
5371 SvCUR_set(tmp,strlen(cstring));
5372 SvPVX(tmp) = (char *) cstring;
5373 SvLEN(tmp) = 0;
5374 SvREADONLY_on(tmp);
5375 SvPOK_on(tmp);
5376 /* From Tk all strings are UTF-8 */
5377 SvUTF8_on(tmp);
5378 #ifdef ROPT_MATCH_UTF8
5379 RX_MATCH_UTF8_on(re->pat);
5380 #else
5381 /* eeek what do we do now ... */
5382 #endif
5383 code = pregexec(re->pat,SvPVX(tmp),SvEND(tmp),(char *) cstart,0,
5384 tmp,REXEC_COPY_STR);
5385 #if 0
5386 LangDebug("%d '%.*s'\n",code,SvCUR(tmp),SvPVX(tmp));
5387 sv_dump(tmp);
5388 regdump(re->pat);
5389 #endif
5390 return code;
5391 }
5392
5393 void
Tcl_RegExpRange(wrap,index,startPtr,endPtr)5394 Tcl_RegExpRange(wrap, index, startPtr, endPtr)
5395 Tcl_RegExp wrap;
5396 int index;
5397 CONST84 char **startPtr;
5398 CONST84 char **endPtr;
5399 {
5400 #if USE_REGEXP_511
5401 REGEXP *rx = wrap->pat;
5402 regexp *const re = (struct regexp *)SvANY(rx);
5403 #else
5404 regexp *re = wrap->pat;
5405 #endif
5406 #if USE_NEWSTYLE_REGEXP_STRUCT
5407 if (re->offs[index].start != -1 && re->offs[index].end != -1)
5408 {
5409 *startPtr = re->subbeg+re->offs[index].start;
5410 *endPtr = re->subbeg+re->offs[index].end;
5411 }
5412 #else
5413 if (re->startp[index] != -1 && re->endp[index] != -1)
5414 {
5415 *startPtr = re->subbeg+re->startp[index];
5416 *endPtr = re->subbeg+re->endp[index];
5417 }
5418 #endif
5419 else
5420 {
5421 *startPtr = NULL;
5422 *endPtr = NULL;
5423 }
5424 }
5425
5426 void
Lang_BuildInImages()5427 Lang_BuildInImages()
5428 {
5429 #if 0
5430 Tk_CreateImageType(&tkBitmapImageType);
5431 Tk_CreateImageType(&tkPixmapImageType);
5432 Tk_CreateImageType(&tkPhotoImageType);
5433
5434 /*
5435 * Create built-in photo image formats.
5436 */
5437
5438 Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
5439 #endif
5440 }
5441
5442
5443 ClientData
Tcl_GetAssocData(interp,name,procPtr)5444 Tcl_GetAssocData(interp,name,procPtr)
5445 Tcl_Interp *interp;
5446 CONST char *name;
5447 Tcl_InterpDeleteProc **procPtr;
5448 {
5449 dTHX;
5450 HV *cm = FindHv(aTHX_ interp, "Tcl_GetAssocData", 0, ASSOC_KEY);
5451 SV **x = hv_fetch(cm, name, strlen(name), 0);
5452 if (x)
5453 {
5454 STRLEN sz;
5455 Assoc_t *info = (Assoc_t *) SvPV(*x,sz);
5456 if (sz != sizeof(*info))
5457 croak("%s corrupted",ASSOC_KEY);
5458 if (procPtr)
5459 *procPtr = info->proc;
5460 return info->clientData;
5461 }
5462 return NULL;
5463 }
5464
5465 void
Tcl_SetAssocData(interp,name,proc,clientData)5466 Tcl_SetAssocData(interp,name,proc,clientData)
5467 Tcl_Interp *interp;
5468 CONST char *name;
5469 Tcl_InterpDeleteProc *proc;
5470 ClientData clientData;
5471 {
5472 dTHX;
5473 HV *cm = FindHv(aTHX_ interp, "Tcl_SetAssocData", 1, ASSOC_KEY);
5474 Assoc_t info;
5475 SV *d;
5476 info.proc = proc;
5477 info.clientData = clientData;
5478 d = struct_sv((char *) &info,sizeof(info));
5479 hv_store(cm,name,strlen(name),d,0);
5480 }
5481
5482 #define MkXSUB(str,name,xs,proc) \
5483 extern XSdec(name); \
5484 XS(name) \
5485 { \
5486 CvXSUB(cv) = xs; \
5487 CvXSUBANY(cv).any_ptr = (VOID *) proc; \
5488 xs(aTHX_ cv); \
5489 }
5490 #include "TkXSUB.def"
5491 #undef MkXSUB
5492
5493
5494 void
install_vtab(name,table,size)5495 install_vtab(name, table, size)
5496 char *name;
5497 void *table;
5498 size_t size;
5499 {
5500 dTHX;
5501 if (table)
5502 {
5503 typedef unsigned (*fptr)_((void));
5504 fptr *q = table;
5505 unsigned i;
5506 if ((*q[0])() != size)
5507 {
5508 croak("%s table is %u not %u",name,(*q[0])(),(unsigned) size);
5509 }
5510 sv_setiv(FindTkVarName(name,GV_ADD|GV_ADDMULTI),PTR2IV(table));
5511 if (size % sizeof(fptr))
5512 {
5513 warn("%s is strange size %d",name,size);
5514 }
5515 size /= sizeof(void *);
5516 for (i=0; i < size; i++)
5517 {
5518 if (!q[i])
5519 warn("%s slot %d is NULL",name,i);
5520 }
5521 }
5522 else
5523 {
5524 croak("%s pointer is NULL",name);
5525 }
5526 }
5527
5528
5529
XS(XS_Tk_INIT)5530 XS(XS_Tk_INIT)
5531 {
5532 dXSARGS;
5533 InitVtabs();
5534 XSRETURN_EMPTY;
5535 }
5536
5537 void
Boot_Glue(pTHX)5538 Boot_Glue
5539 _((pTHX))
5540 {
5541 dSP;
5542 /* A wonder how you call $e-># ? */
5543 char *XEventMethods = "abcdfhkmopstvwxyABDEKNRSTWXY#";
5544 char buf[128];
5545 CV *cv;
5546 #if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 9)
5547 #define COP_WARNINGS_TYPE STRLEN*
5548 #else
5549 #define COP_WARNINGS_TYPE SV*
5550 #endif
5551 #ifdef pWARN_NONE
5552 COP_WARNINGS_TYPE old_warn = PL_curcop->cop_warnings;
5553 PL_curcop->cop_warnings = pWARN_NONE;
5554 #endif
5555
5556 /* Arrange to call initialization code - an XSUB called INIT */
5557 cv = newXS("Tk::INIT", XS_Tk_INIT, __FILE__);
5558
5559 #ifdef pWARN_NONE
5560 PL_curcop->cop_warnings = old_warn;
5561 #endif
5562
5563 initialized = 0;
5564 InitVtabs();
5565
5566 #ifdef VERSION
5567 sprintf(buf, "%s::VERSION", BASEEXT);
5568 sv_setpv(perl_get_sv(buf,1),VERSION);
5569 #endif
5570
5571 sprintf(buf, "%s::Widget::%s", BASEEXT, "BindClientMessage");
5572 cv = newXS(buf, XS_Tk__Widget_BindClientMessage, __FILE__);
5573
5574 sprintf(buf, "%s::Widget::%s", BASEEXT, "PassEvent");
5575 cv = newXS(buf, XS_Tk__Widget_PassEvent, __FILE__);
5576
5577 sprintf(buf, "%s::Widget::%s", BASEEXT, "SelectionGet");
5578 cv = newXS(buf, XS_Tk__Widget_SelectionGet, __FILE__);
5579
5580 cv = newXS("Tk::MainWindow::Create", XS_Tk__MainWindow_Create, __FILE__);
5581
5582
5583 newXS("Tk::DoWhenIdle", XS_Tk_DoWhenIdle, __FILE__);
5584 newXS("Tk::CreateGenericHandler", XS_Tk_CreateGenericHandler, __FILE__);
5585
5586
5587 sprintf(buf, "%s::Widget::%s", BASEEXT, "ManageGeometry");
5588 cv = newXS(buf, XS_Tk__Widget_ManageGeometry, __FILE__);
5589
5590 cv = newXS("Tk::Interp::DESTROY", XS_Tk__Interp_DESTROY, __FILE__);
5591
5592 #define MkXSUB(str,name,xs,proc) \
5593 newXS(str, name, __FILE__);
5594 #include "TkXSUB.def"
5595 #undef MkXSUB
5596
5597 Tk_CreateImageType(&tkPhotoImageType);
5598 Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
5599 #if 0
5600 Tk_CreatePhotoImageFormat(&imgFmtGIF);
5601 #else
5602 Tk_CreatePhotoImageFormat(&tkImgFmtGIF);
5603 #endif
5604 Tk_CreatePhotoImageFormat(&imgFmtXBM);
5605 Tk_CreatePhotoImageFormat(&imgFmtXPM);
5606 Tk_CreatePhotoImageFormat(&imgFmtBMP);
5607 }
5608
5609 void
Tcl_AllowExceptions(Tcl_Interp * interp)5610 Tcl_AllowExceptions (Tcl_Interp *interp)
5611 {
5612 /* FIXME: What should this do ? */
5613 }
5614
5615
5616 static HV *uidHV;
5617
5618 Tk_Uid
Tk_GetUid(key)5619 Tk_GetUid(key)
5620 CONST char *key; /* String to convert. */
5621 {
5622 dTHX;
5623 STRLEN klen;
5624 SV *svkey = newSVpv((char *)key,strlen(key));
5625 HE *he;
5626 if (!uidHV)
5627 uidHV = newHV();
5628 he = hv_fetch_ent(uidHV,svkey,0,0); /* added by SRT: prevents leak of auto-created SVs */
5629 if (!he)
5630 he = hv_store_ent(uidHV,svkey,Nullsv,0); /* ... */
5631 SvREFCNT_dec(svkey);
5632 return (Tk_Uid) HePV(he,klen);
5633 }
5634
5635
5636 Tcl_Obj*
Tcl_FSGetCwd(interp)5637 Tcl_FSGetCwd(interp)
5638 Tcl_Interp *interp;
5639 {
5640 dTHX;
5641 dSP;
5642 SV *ret = Nullsv;
5643 ENTER;
5644 SAVETMPS;
5645 PUSHMARK(sp);
5646 PUTBACK;
5647 if (call_pv("Cwd::getcwd",G_SCALAR) == 1)
5648 {
5649 SPAGAIN;
5650 ret = POPs;
5651 PUTBACK;
5652 SvREFCNT_inc(ret);
5653 }
5654 else
5655 {
5656 SPAGAIN;
5657 }
5658 FREETMPS;
5659 LEAVE;
5660 return ret;
5661 }
5662
5663
5664 char *
Tcl_GetCwd(interp,cwdPtr)5665 Tcl_GetCwd(interp, cwdPtr)
5666 Tcl_Interp *interp;
5667 Tcl_DString *cwdPtr;
5668 {
5669 Tcl_Obj *cwd;
5670 cwd = Tcl_FSGetCwd(interp);
5671 if (cwd == NULL) {
5672 return NULL;
5673 } else {
5674 Tcl_DStringInit(cwdPtr);
5675 Tcl_DStringAppend(cwdPtr, Tcl_GetString(cwd), -1);
5676 Tcl_DecrRefCount(cwd);
5677 return Tcl_DStringValue(cwdPtr);
5678 }
5679 }
5680
5681 void
LangSelectHook(CONST char * what,Tk_Window tkwin,Atom selection,Atom target,Atom type)5682 LangSelectHook(CONST char *what,Tk_Window tkwin,
5683 Atom selection, Atom target, Atom type)
5684 {
5685 #if 0
5686 /* There is still something not-quite-right about Selection
5687 but we don't want all this noise in the release
5688 */
5689 TkWindow *winPtr = (TkWindow *)tkwin;
5690 char *name = (tkwin == winPtr->dispPtr->clipWindow)
5691 ? "ClipWindow" : Tk_PathName(tkwin);
5692 LangDebug("%s sel=%s target=%s type=%s win=%p '%s'\n", what,
5693 Tk_GetAtomName(tkwin, selection),
5694 Tk_GetAtomName(tkwin, target),
5695 (type == None) ? "None" : Tk_GetAtomName(tkwin, type),
5696 tkwin, name);
5697 #endif
5698 }
5699
5700
5701