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

NAME

6       Tk2portableTk - how to make your Tk source portable to other
7       interpreted 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.
15       Currently 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
26       setting an error. Thus different Tk command return different string
27       values that mean "error happened", like "", " " or "??". Other
28       languages can be more flexible, so in portableTk you should inform the
29       compiler that what you want to return means "error" (see "Setting
30       variables").
31
32       Currently PortableTk uses several different approachs to simplify
33       translation: several TCL functions that are especially dangerous to use
34       are undefined, so you can easily find places that need to be updated to
35       use Language-independent functions based on compiler warnings.
36       Eventually a way to use these Language-independent functions under
37       proper TCL will be also provided.  The end of this document provides a
38       starting point for such a project.
39

Structure of pTk, porting your code

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

PortableTk API

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

Translation back to TCL

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

Checking for trouble

363       If you start with working TCL code, you can start conversion using the
364       above hints. Good indication that you are doing is OK is absence of
365       "sprintf" and "sscanf" in your code (at least in the part that is
366       working with interpreter).
367

Additional API

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