1pTk(3)                User Contributed Perl Documentation               pTk(3)
2
3
4

NAME

6       Tk2portableTk - how to make your Tk source portable to other inter‐
7       preted languages.
8

Author

10       Ilya Zakharevich <ilya@math.ohio-state.edu>  has contributed most of
11       this document. Many thanks.
12

DESCRIPTION

14       PortableTk is an attempt to make Tk useful from other languages. Cur‐
15       rently tk4.0 runs under Perl using this approach. Below, Lang is the
16       notation for an external language to which PortableTk glues Tk code.
17
18       The main problem with using the code developed for TCL with different
19       languages is the absence of data types: almost anything is "char*". It
20       makes automatic translation hopeless. However, if you "typedef" several
21       new symbols to be "char*", you can still use your code in TCL, and it
22       will make the automatic translation possible.
23
24       Another problem with the approach that "everything is a string" is
25       impossibility to have a result that says "NotApplicable" without set‐
26       ting an error. Thus different Tk command return different string values
27       that mean "error happened", like "", " " or "??". Other languages can
28       be more flexible, so in portableTk you should inform the compiler that
29       what you want to return means "error" (see "Setting variables").
30
31       Currently PortableTk uses several different approachs to simplify
32       translation: several TCL functions that are especially dangerous to use
33       are undefined, so you can easily find places that need to be updated to
34       use Language-independent functions based on compiler warnings.  Eventu‐
35       ally a way to use these Language-independent functions under proper TCL
36       will be also provided.  The end of this document provides a starting
37       point for such a project.
38

Structure of pTk, porting your code

40       pTk, that is a port of Tk, is very special with respect to porting of
41       other code to portableTk. The problem is that currently there is very
42       little hope to merge the modifications back into Tk, so a special
43       strategy is needed to maintain this port. Do not use this strategy to
44       port your own code.
45
46       pTk is produced from Tk via a two-step process: first, some manual
47       editing (the result is in the subdirectory "mTk"), and second, auto‐
48       matic conversion by the "munge" script (written in Perl). Thus the sub‐
49       directory "pTk/mTk" contains code with minimal possible difference from
50       the virgin Tk code, so it is easier to merge(1) the differences between
51       Tk versions into modified code.
52
53       It looks like the strategy for a portable code should be exactly oppo‐
54       site: starting from TCL-based code, apply "munge", and then hand-edit
55       the resulting code. Probably it is also possible to target your code to
56       portableTk from scratch, since this will make it possible to run it
57       under a lot of Languages.
58
59       The only reason anyone would like to look into contents of "pTk/mTk"
60       directory is to find out which constructs are not supported by "munge".
61       On the other hand, "pTk" directory contains code that is conformant to
62       portableTk, so you can look there to find example code.
63
64       "munge" is the script that converts most common Tk constructs to their
65       "portableTk" equivalent. For your code to qualify, you should follow Tk
66       conventions on indentation and names of variables, in particular, the
67       array of arguments for the "...CmdProc" should be called "argv".
68
69       For details on what "munge" can do, see "Translation of some TCL func‐
70       tions".
71

PortableTk API

73       Checking what you are running under
74
75       PortableTk provides a symbol "????". If this symbol is defined, your
76       source is compiled with it.
77
78       New types of configuration options
79
80       PortableTk defines several new types of configuration options:
81
82        TK_CONFIG_CALLBACK
83        TK_CONFIG_LANGARG
84        TK_CONFIG_SCALARVAR
85        TK_CONFIG_HASHVAR
86        TK_CONFIG_ARRAYVAR
87        TK_CONFIG_IMAGE
88
89       You should use them instead of TK_CONFIG_STRING whenever appropriate.
90       This allows your application to receive a direct representation of the
91       corresponding resource instead of the string representation, if this is
92       possible under given language.
93
94       ???? It looks like "TK_CONFIG_IMAGE" and "TK_CONFIG_SCALARVAR" set
95       variables of type "char*".
96
97       Language data
98
99       The following data types are defined:
100
101       "Tcl_Obj *"
102           is the main datatype of the language.  This is a type that your C
103           function gets pointers to for arguments when the corresponding Lang
104           function is called.  The corresponding config type is "TK_CON‐
105           FIG_LANGARG".
106
107           This is also a type that keeps information about contents of Lang
108           variable.
109
110       "Var"
111           Is a substitute for a "char *" that contains name of variable. In
112           Lang it is an object that contains reference to another Lang vari‐
113           able.
114
115       "LangResultSave"
116           ????
117
118       "LangCallback"
119           "LangCallback*" a substitute for a "char *" that contains command
120           to call. The corresponding config type is "TK_CONFIG_CALLBACK".
121
122       "LangFreeProc"
123           It is the type that the "Lang_SplitList" sets. Before you call it,
124           declare
125
126               Args *args;
127               LangFreeProc *freeProc = NULL;
128               ...
129               code = Lang_SplitList(interp, value,
130                   &argc, &args, &freeProc);
131
132           After you use the split values, call
133
134               if (args != NULL && freeProc) (*freeProc)(argc,args);
135
136           It is not guaranteed that the "args" can survive deletion of
137           "value".
138
139       Conversion
140
141       The following macros and functions are used for conversion between
142       strings and the additional types:
143
144        LangCallback * LangMakeCallback(Tcl_Obj *)
145        Tcl_Obj * LangCallbackArg(LangCallback *)
146        char * LangString(Tcl_Obj *)
147
148       After you use the result of LangCallbackArg(), you should free it with
149       "freeProc" "LANG_DYNAMIC" (it is not guaranteed that any change of
150       "Tcl_Obj *" will not be reflected in <LangCallback>, so you cannot do
151       LangSet...() in between, and you should reset it to "NULL" if you want
152       to do any further assignments to this "Tcl_Obj *").
153
154       The following function returns the "Tcl_Obj *" that is a reference to
155       "Var":
156
157        Tcl_Obj * LangVarArg(Var)
158
159       ???? It is very anti-intuitive, I hope the name is changed.
160
161        int LangCmpCallback(LangCallback *a,Tcl_Obj * b)
162
163       (currently only a stub), and, at last,
164
165        LangCallback * LangCopyCallback(LangCallback *)
166
167       Callbacks
168
169       Above we have seen the new datatype "LangCallback" and the correspond‐
170       ing Config option  "TK_CONFIG_CALLBACK". The following functions are
171       provided for manipulation of "LangCallback"s:
172
173        void LangFreeCallback(LangCallback *)
174        int LangDoCallback(Tcl_Interp *,LangCallback *,
175               int result,int argc, char *format,...)
176
177       The argument "format" of "LangDoCallback" should contain a string that
178       is suitable for "sprintf" with optional arguments of "LangDoCallback".
179       "result" should be false if result of callback is not needed.
180
181        int LangMethodCall(Tcl_Interp *,Tcl_Obj *,char *method,
182               int result,int argc,...)
183
184       ????
185
186       Conceptually, "LangCallback*" is a substitute for ubiquitous "char *"
187       in TCL. So you should use "LangFreeCallback" instead of "ckfree" or
188       "free" if appropriate.
189
190       Setting variables
191
192        void LangFreeArg (Tcl_Obj *, Tcl_FreeProc *freeProc)
193        Tcl_Obj *  LangCopyArg (Tcl_Obj *);
194        void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)
195        void LangSetString(Tcl_Obj * *, char *s)
196        void LangSetDefault(Tcl_Obj * *, char *s)
197
198       These two are equivalent unless s is an empty string. In this case
199       "LangSetDefault" behaves like "LangSetString" with "s==NULL", i.e., it
200       sets the current value of the Lang variable to be false.
201
202        void LangSetInt(Tcl_Obj * *,int)
203        void LangSetDouble(Tcl_Obj * *,double)
204
205       The Lang functions separate uninitialized and initialized data compar‐
206       ing data with "NULL". So the declaration for an "Tcl_Obj *" should look
207       like
208
209        Tcl_Obj * arg = NULL;
210
211       if you want to use this "arg" with the above functions. After you are
212       done, you should use "LangFreeArg" with "TCL_DYNAMIC" as "freeProc".
213
214       Language functions
215
216       Use
217
218       "int  LangNull(Tcl_Obj *)"
219           to check that an object is false;
220
221       "int  LangStringMatch(char *string, Tcl_Obj * match)"
222           ????
223
224       "void LangExit(int)"
225           to make a proper shutdown;
226
227       "int LangEval(Tcl_Interp *interp, char *cmd, int global)"
228           to call Lang "eval";
229
230       "void Lang_SetErrorCode(Tcl_Interp *interp,char *code)"
231       "char *Lang_GetErrorCode(Tcl_Interp *interp)"
232       "char *Lang_GetErrorInfo(Tcl_Interp *interp)"
233       "void LangCloseHandler(Tcl_Interp *interp,Tcl_Obj * arg,FILE
234       *f,Lang_FileCloseProc *proc)"
235           currently stubs only;
236
237       "int LangSaveVar(Tcl_Interp *,Tcl_Obj * arg,Var *varPtr,int type)"
238           to save the structure "arg" into Lang variable *varPtr;
239
240       "void LangFreeVar(Var var)"
241           to free the result;
242
243       "int LangEventCallback(Tcl_Interp *,LangCallback *,XEvent *,KeySym)"
244           ????
245
246       "int LangEventHook(int flags)"
247       "void LangBadFile(int fd)"
248       "int LangCmpConfig(char *spec, char *arg, size_t length)"
249           unsupported????;
250
251       "void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)"
252
253       Another useful construction is
254
255        Tcl_Obj * variable = LangFindVar(interp, Tk_Window tkwin, char *name);
256
257       After using the above function, you should call
258
259        LangFreeVar(Var variable);
260
261       ???? Note discrepancy in types!
262
263       If you want to find the value of a variable (of type "Tcl_Obj *") given
264       the variable name, use "Tcl_GetVar(interp, varName, flags)". If you are
265       interested in the string value of this variable, use
266       "LangString(Tcl_GetVar(...))".
267
268       To get a C array of "Tcl_Obj *" of length "n", use
269
270           Tcl_Obj * *args = LangAllocVec(n);
271           ...
272           LangFreeVec(n,args);
273
274       You can set the values of the "Tcl_Obj *"s using "LangSet..." func‐
275       tions, and get string value using "LangString".
276
277       If you want to merge an array of "Tcl_Obj *"s into one "Tcl_Obj *"
278       (that will be an array variable), use
279
280           result = Tcl_Merge(listLength, list);
281
282       Translation of some TCL functions
283
284       We mark items that can be dealt with by "munge" by Autoconverted.
285
286       "Tcl_AppendResult"
287           does not take "(char*)NULL", but "NULL" as delimiter. Autocon‐
288           verted.
289
290       "Tcl_CreateCommand", "Tcl_DeleteCommand"
291           "Tk_CreateWidget", "Tk_DeleteWidget", the second argument is the
292           window itself, not the pathname. Autoconverted.
293
294       "sprintf(interp->result, "%d %d %d %d",...)"
295           "Tcl_IntResults(interp,4,0,...)". Autoconverted.
296
297       "interp->result = "1";"
298           "Tcl_SetResult(interp,"1", TCL_STATIC)". Autoconverted.
299
300       Reading "interp->result"
301           "Tcl_GetResult(interp)". Autoconverted.
302
303       "interp->result = Tk_PathName(textPtr->tkwin);"
304           "Tk_WidgetResult(interp,textPtr->tkwin)". Autoconverted.
305
306       Sequence "Tcl_PrintDouble, Tcl_PrintDouble, ..., Tcl_AppendResult"
307           Use a single command
308
309            void Tcl_DoubleResults(Tcl_Interp *interp, int append,
310                   int argc,...);
311
312           "append" governs whether it is required to clear the result first.
313
314           A similar command for "int" arguments is "Tcl_IntResults".
315
316       "Tcl_SplitList"
317           Use "Lang_SplitList" (see the description above).
318

Translation back to TCL

320       To use your portableTk program with TCL, put
321
322        #include "ptcl.h"
323
324       before inclusion of "tk.h", and link the resulting code with
325       "ptclGlue.c".
326
327       These files currently implement the following:
328
329       Additional config types:
330            TK_CONFIG_CALLBACK
331            TK_CONFIG_LANGARG
332            TK_CONFIG_SCALARVAR
333            TK_CONFIG_HASHVAR
334            TK_CONFIG_ARRAYVAR
335            TK_CONFIG_IMAGE
336
337       Types:
338            Var, Tcl_Obj *, LangCallback, LangFreeProc.
339
340       Functions and macros:
341            Lang_SplitList, LangString, LangSetString, LangSetDefault,
342            LangSetInt, LangSetDouble Tcl_ArgResult, LangCallbackArg,
343            LangSaveVar, LangFreeVar,
344            LangFreeSplitProc, LangFreeArg, Tcl_DoubleResults, Tcl_IntResults,
345            LangDoCallback, Tk_WidgetResult, Tcl_CreateCommand,
346            Tcl_DeleteCommand, Tcl_GetResult.
347
348       Current implementation contains enough to make it possible to compile
349       "mTk/tkText*.[ch]" with the virgin Tk.
350
351       New types of events ????
352
353       PortableTk defines following new types of events:
354
355        TK_EVENTTYPE_NONE
356        TK_EVENTTYPE_STRING
357        TK_EVENTTYPE_NUMBER
358        TK_EVENTTYPE_WINDOW
359        TK_EVENTTYPE_ATOM
360        TK_EVENTTYPE_DISPLAY
361        TK_EVENTTYPE_DATA
362
363       and a function
364
365        char * Tk_EventInfo(int letter,
366                   Tk_Window tkwin, XEvent *eventPtr,
367                   KeySym keySym, int *numPtr, int *isNum, int *type,
368                   int num_size, char *numStorage)
369

Checking for trouble

371       If you start with working TCL code, you can start convertion using the
372       above hints. Good indication that you are doing is OK is absence of
373       "sprintf" and "sscanf" in your code (at least in the part that is work‐
374       ing with interpreter).
375

Additional API

377       What is described here is not included into base portableTk distribu‐
378       tion. Currently it is coded in TCL and as Perl macros (core is coded as
379       functions, so theoretically you can use the same object files with dif‐
380       ferent interpreted languages).
381
382       "ListFactory"
383
384       Dynamic arrays in TCL are used for two different purposes: to construct
385       strings, and to construct lists. These two usages will have separate
386       interfaces in other languages (since list is a different type from a
387       string), so you should use a different interface in your code.
388
389       The type for construction of dynamic lists is "ListFactory". The API
390       below is a counterpart of the API for construction of dynamic lists in
391       TCL:
392
393        void ListFactoryInit(ListFactory *)
394        void ListFactoryFinish(ListFactory *)
395        void ListFactoryFree(ListFactory *)
396        Tcl_Obj * * ListFactoryArg(ListFactory *)
397        void ListFactoryAppend(ListFactory *, Tcl_Obj * *arg)
398        void ListFactoryAppendCopy(ListFactory *, Tcl_Obj * *arg)
399        ListFactory * ListFactoryNewLevel(ListFactory *)
400        ListFactory * ListFactoryEndLevel(ListFactory *)
401        void ListFactoryResult(Tcl_Interp *, ListFactory *)
402
403       The difference is that a call to "ListFactoryFinish" should precede the
404       actual usage of the value of "ListFactory", and there are two different
405       ways to append an "Tcl_Obj *" to a "ListFactory": ListFactoryAppend‐
406       Copy() guarantees that the value of "arg" is copied to the list, but
407       ListFactoryAppend() may append to the list a reference to the current
408       value of "arg". If you are not going to change the value of "arg" after
409       appending, the call to ListFactoryAppend may be quicker.
410
411       As in TCL, the call to ListFactoryFree() does not free the "ListFac‐
412       tory", only the objects it references.
413
414       The functions ListFactoryNewLevel() and ListFactoryEndLevel() return a
415       pointer to a "ListFactory" to fill. The argument of ListFacto‐
416       ryEndLevel() cannot be used after a call to this function.
417
418       DStrings
419
420       Production of strings are still supported in portableTk.
421
422       Accessing "Tcl_Obj *"s
423
424       The following functions for getting a value of an "Tcl_Obj *" may be
425       provided:
426
427        double LangDouble(Tcl_Obj *)
428        int LangInt(Tcl_Obj *)
429        long LangLong(Tcl_Obj *)
430        int LangIsList(Tcl_Obj * arg)
431
432       The function LangIsList() is supported only partially under TCL, since
433       there is no data types. It checks whether there is a space inside the
434       string "arg".
435
436       Assigning numbers to "Tcl_Obj *"s
437
438       While LangSetDouble() and LangSetInt() are supported ways to assign
439       numbers to assign an integer value to a variable, for the sake of effi‐
440       ciency under TCL it is supposed that the destination of these commands
441       was massaged before the call so it contains a long enough string to
442       sprintf() the numbers inside it. If you are going to immediately use
443       the resulting "Tcl_Obj *", the best way to do this is to declare a buf‐
444       fer in the beginning of a block by
445
446          dArgBuffer;
447
448       and assign this buffer to the "Tcl_Obj *" by
449
450          void LangSetDefaultBuffer(Tcl_Obj * *)
451
452       You can also create the buffer(s) manually and assign them using
453
454          void LangSetBuffer(Tcl_Obj * *, char *)
455
456       This is the only choice if you need to assign numeric values to several
457       "Tcl_Obj *"s simultaneously. The advantage of the first approach is
458       that the above declarations can be made "nop"s in different languages.
459
460       Note that if you apply "LangSetDefaultBuffer" to an "Tcl_Obj *" that
461       contains some value, you can create a leak if you do not free that
462       "Tcl_Obj *" first. This is a non-problem in real languages, but can be
463       a trouble in "TCL", unless you use only the above API.
464
465       Creating new "Tcl_Obj *"s
466
467       The API for creating a new "Tcl_Obj *" is
468
469        void LangNewArg(Tcl_Obj * *, LangFreeProc *)
470
471       The API for creating a new "Tcl_Obj *" is absent. Just initialize
472       "Tcl_Obj *" to be "NULL", and apply one of "LangSet..." methods.
473
474       After you use this "Tcl_Obj *", it should be freed thusly:
475
476       "LangFreeArg(arg, freeProc)".
477
478       Evaluating a list
479
480       Use
481
482        int LangArgEval(Tcl_Interp *, Tcl_Obj * arg)
483
484       Here "arg" should be a list to evaluate, in particular, the first ele‐
485       ment should be a "LangCallback" massaged to be an "Tcl_Obj *". The
486       arguments can be send to the subroutine by reference or by value in
487       different languages.
488
489       Getting result as "Tcl_Obj *"
490
491       Use "Tcl_ArgResult". It is not guaranteed that result survives this
492       operation, so the "Tcl_Obj *" you get should be the only mean to access
493       the data from this moment on. After you use this "Tcl_Obj *", you
494       should free it with "freeProc" "LANG_DYNAMIC" (you can do LangSet...()
495       in between).
496
497
498
499perl v5.8.8                       2008-02-05                            pTk(3)
Impressum