File: pTk.pod

package info (click to toggle)
perl-tk 1%3A804.033-2
  • links: PTS
  • area: main
  • in suites: buster
  • size: 34,724 kB
  • ctags: 37,174
  • sloc: ansic: 349,541; perl: 52,192; sh: 17,904; makefile: 5,732; asm: 3,565; ada: 1,681; pascal: 1,089; cpp: 1,006; yacc: 883; cs: 879
file content (550 lines) | stat: -rw-r--r-- 17,210 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
=head1 NAME

Tk2portableTk - how to make your B<Tk> source portable to other
interpreted languages.

=for category  C Programming

=head1 Author

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

=head1 DESCRIPTION

B<PortableTk> is an attempt to make B<Tk> useful from other
languages. Currently tk4.0 runs under Perl using this
approach. Below, I<Lang> is the notation for an external language to
which B<PortableTk> glues B<Tk> code.

The main problem with using the code developed for B<TCL> with
different languages is the absence of data types: almost anything is
C<char*>. It makes automatic translation hopeless. However, if you
C<typedef> several new symbols to be C<char*>, you can still use your
code in B<TCL>, I<and> it will make the automatic translation
possible.

Another problem with the approach that "everything is a string" is
impossibility to have a result that says "NotApplicable" without
setting an error. Thus different B<Tk> command return different string
values that mean "error happened", like C<"">, C<" "> or
C<"??">. Other languages can be more flexible, so in B<portableTk> you
should inform the compiler that what you want to return means "error"
(see L<Setting variables>).

Currently B<PortableTk> uses several different approachs
to simplify translation: several B<TCL> functions that are especially
dangerous to use are undefined, so you can easily find places that
need to be updated to use Language-independent functions based on
compiler warnings.  Eventually a way to use these Language-independent
functions under proper B<TCL> will be also provided.  The end of this
document provides a starting point for such a project.

=head1 Structure of B<pTk>, porting your code

B<pTk>, that is a port of B<Tk>, is very special with respect to porting
of other code to B<portableTk>. The problem is that currently there is
very little hope to merge the modifications back into B<Tk>, so a
special strategy is needed to maintain this port. Do not use this
strategy to port your own code.

B<pTk> is produced from B<Tk> via a two-step process: first, some
manual editing (the result is in the subdirectory C<mTk>), and second,
automatic conversion by the C<munge> script (written in Perl). Thus the
subdirectory C<pTk/mTk> contains code with minimal possible difference
from the virgin B<Tk> code, so it is easier to merge(1) the
differences between B<Tk> versions into modified code.

It looks like the strategy for a portable code should be exactly
opposite: starting from B<TCL>-based code, apply C<munge>, and then
hand-edit the resulting code. Probably it is also possible to target
your code to B<portableTk> from scratch, since this will make it
possible to run it under a lot of I<Lang>uages.

The only reason anyone would like to look into contents of C<pTk/mTk>
directory is to find out which constructs are not supported by
C<munge>. On the other hand, C<pTk> directory contains code that is
conformant to B<portableTk>, so you can look there to find example code.

C<munge> is the script that converts most common B<Tk> constructs to
their C<portableTk> equivalent. For your code to qualify, you should
follow B<Tk> conventions on indentation and names of variables, in
particular, the array of arguments for the C<...CmdProc> should be
called C<argv>.

For details on what C<munge> can do, see
L<Translation of some TCL functions>.

=head1 B<PortableTk> API

=head2 Checking what you are running under

B<PortableTk> provides a symbol C<????>. If this symbol is defined,
your source is compiled with it.

=head2 New types of configuration options

B<PortableTk> defines several new types of configuration options:

 TK_CONFIG_CALLBACK
 TK_CONFIG_LANGARG
 TK_CONFIG_SCALARVAR
 TK_CONFIG_HASHVAR
 TK_CONFIG_ARRAYVAR
 TK_CONFIG_IMAGE

You should use them instead of TK_CONFIG_STRING whenever
appropriate. This allows your application to receive a direct
representation of the corresponding resource instead of the string
representation, if this is possible under given language.

???? It looks like C<TK_CONFIG_IMAGE> and C<TK_CONFIG_SCALARVAR> set
variables of type C<char*>.

=head2 Language data

The following data types are defined:

=over 4

=item C<Tcl_Obj *>

is the main datatype of the language.  This is a type that your C
function gets pointers to for arguments when the corresponding I<Lang>
function is called.  The corresponding config type is
C<TK_CONFIG_LANGARG>.

This is also a type that keeps information about contents of I<Lang>
variable.

=item C<Var>

Is a substitute for a C<char *> that contains name of variable. In
I<Lang> it is an object that contains reference to another I<Lang>
variable.

=item C<LangResultSave>

????

=item C<LangCallback>

C<LangCallback*> a substitute for a C<char *> that contains command to
call. The corresponding config type is C<TK_CONFIG_CALLBACK>.

=item C<LangFreeProc>

It is the type that the C<Lang_SplitList> sets. Before you call it,
declare

    Args *args;
    LangFreeProc *freeProc = NULL;
    ...
    code = Lang_SplitList(interp, value,
	&argc, &args, &freeProc);

After you use the split values, call

    if (args != NULL && freeProc) (*freeProc)(argc,args);

It is not guaranteed that the C<args> can survive deletion of C<value>.

=back

=head2 Conversion

The following macros and functions are used for conversion between
strings and the additional types:

 LangCallback * LangMakeCallback(Tcl_Obj *)
 Tcl_Obj * LangCallbackArg(LangCallback *)
 char * LangString(Tcl_Obj *)

After you use the result of LangCallbackArg(), you should free it with
C<freeProc> C<LANG_DYNAMIC> (it is not guaranteed that any change of
C<Tcl_Obj *> will not be reflected in <LangCallback>, so you cannot do
LangSet...() in between, and you should reset it to C<NULL> if you
want to do any further assignments to this C<Tcl_Obj *>).

The following function returns the C<Tcl_Obj *> that is a reference to C<Var>:

 Tcl_Obj * LangVarArg(Var)

???? It is very anti-intuitive, I hope the name is changed.

 int LangCmpCallback(LangCallback *a,Tcl_Obj * b)

(currently only a stub), and, at last,

 LangCallback * LangCopyCallback(LangCallback *)

=head2 Callbacks

Above we have seen the new datatype C<LangCallback> and the
corresponding I<Config option>  C<TK_CONFIG_CALLBACK>. The following
functions are provided for manipulation of C<LangCallback>s:

 void LangFreeCallback(LangCallback *)
 int LangDoCallback(Tcl_Interp *,LangCallback *,
	int result,int argc, char *format,...)

The argument C<format> of C<LangDoCallback> should contain a string that is
suitable for C<sprintf> with optional arguments of C<LangDoCallback>.
C<result> should be false if result of callback is not needed.

 int LangMethodCall(Tcl_Interp *,Tcl_Obj *,char *method,
	int result,int argc,...)

????

Conceptually, C<LangCallback*> is a substitute for ubiquitous C<char *>
in B<TCL>. So you should use C<LangFreeCallback> instead of C<ckfree>
or C<free> if appropriate.

=head2 Setting variables

 void LangFreeArg (Tcl_Obj *, Tcl_FreeProc *freeProc)
 Tcl_Obj *  LangCopyArg (Tcl_Obj *);
 void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)
 void LangSetString(Tcl_Obj * *, char *s)
 void LangSetDefault(Tcl_Obj * *, char *s)

These two are equivalent unless s is an empty string. In this case
C<LangSetDefault> behaves like C<LangSetString> with C<s==NULL>, i.e.,
it sets the current value of the I<Lang> variable to be false.

 void LangSetInt(Tcl_Obj * *,int)
 void LangSetDouble(Tcl_Obj * *,double)

The I<Lang> functions separate uninitialized and initialized data
comparing data with C<NULL>. So the declaration for an C<Tcl_Obj *> should
look like

 Tcl_Obj * arg = NULL;

if you want to use this C<arg> with the above functions. After you are
done, you should use C<LangFreeArg> with C<TCL_DYNAMIC> as C<freeProc>.

=head2 Language functions

Use

=over 4

=item C<int  LangNull(Tcl_Obj *)>

to check that an object is false;

=item C<int  LangStringMatch(char *string, Tcl_Obj * match)>

????

=item C<void LangExit(int)>

to make a proper shutdown;

=item C<int LangEval(Tcl_Interp *interp, char *cmd, int global)>

to call I<Lang> C<eval>;

=item C<void Lang_SetErrorCode(Tcl_Interp *interp,char *code)>

=item C<char *Lang_GetErrorCode(Tcl_Interp *interp)>

=item C<char *Lang_GetErrorInfo(Tcl_Interp *interp)>

=item C<void LangCloseHandler(Tcl_Interp *interp,Tcl_Obj * arg,FILE *f,Lang_FileCloseProc *proc)>

currently stubs only;

=item C<int LangSaveVar(Tcl_Interp *,Tcl_Obj * arg,Var *varPtr,int type)>

to save the structure C<arg> into I<Lang> variable C<*varPtr>;

=item C<void LangFreeVar(Var var)>

to free the result;

=item C<int LangEventCallback(Tcl_Interp *,LangCallback *,XEvent *,KeySym)>

????

=item C<int LangEventHook(int flags)>

=item C<void LangBadFile(int fd)>

=item C<int LangCmpConfig(char *spec, char *arg, size_t length)>

unsupported????;

=item  C<void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)>

=back

Another useful construction is

 Tcl_Obj * variable = LangFindVar(interp, Tk_Window tkwin, char *name);

After using the above function, you should call

 LangFreeVar(Var variable);

???? Note discrepancy in types!

If you want to find the value of a variable (of type C<Tcl_Obj *>) given the
variable name, use C<Tcl_GetVar(interp, varName, flags)>. If you are
interested in the string value of this variable, use
C<LangString(Tcl_GetVar(...))>.

To get a B<C> array of C<Tcl_Obj *> of length C<n>, use

    Tcl_Obj * *args = LangAllocVec(n);
    ...
    LangFreeVec(n,args);

You can set the values of the C<Tcl_Obj *>s using C<LangSet...> functions,
and get string value using C<LangString>.

If you want to merge an array of C<Tcl_Obj *>s into one C<Tcl_Obj *> (that will
be an array variable), use

    result = Tcl_Merge(listLength, list);

=head2 Translation of some TCL functions

We mark items that can be dealt with by C<munge> by I<Autoconverted>.

=over 4

=item C<Tcl_AppendResult>

does not take C<(char*)NULL>, but C<NULL> as delimiter. I<Autoconverted>.

=item C<Tcl_CreateCommand>, C<Tcl_DeleteCommand>

C<Tk_CreateWidget>, C<Tk_DeleteWidget>, the second argument is the
window itself, not the pathname. I<Autoconverted>.

=item C<sprintf(interp-E<gt>result, "%d %d %d %d",...)>

C<Tcl_IntResults(interp,4,0,...)>. I<Autoconverted>.

=item C<interp-E<gt>result = "1";>

C<Tcl_SetResult(interp,"1", TCL_STATIC)>. I<Autoconverted>.

=item Reading C<interp-E<gt>result>

C<Tcl_GetResult(interp)>. I<Autoconverted>.

=item C<interp-E<gt>result = Tk_PathName(textPtr-E<gt>tkwin);>

C<Tk_WidgetResult(interp,textPtr-E<gt>tkwin)>. I<Autoconverted>.

=item Sequence C<Tcl_PrintDouble, Tcl_PrintDouble, ..., Tcl_AppendResult>

Use a single command

 void Tcl_DoubleResults(Tcl_Interp *interp, int append,
	int argc,...);

C<append> governs whether it is required to clear the result first.

A similar command for C<int> arguments is C<Tcl_IntResults>.

=item C<Tcl_SplitList>

Use C<Lang_SplitList> (see the description above).

=back

=head1 Translation back to TCL

To use your B<portableTk> program with B<TCL>, put

 #include "ptcl.h"

I<before> inclusion of C<tk.h>, and link the resulting code with
C<ptclGlue.c>.

These files currently implement the following:

=over 4

=item Additional config types:

 TK_CONFIG_CALLBACK
 TK_CONFIG_LANGARG
 TK_CONFIG_SCALARVAR
 TK_CONFIG_HASHVAR
 TK_CONFIG_ARRAYVAR
 TK_CONFIG_IMAGE

=item Types:

 Var, Tcl_Obj *, LangCallback, LangFreeProc.

=item Functions and macros:

 Lang_SplitList, LangString, LangSetString, LangSetDefault,
 LangSetInt, LangSetDouble Tcl_ArgResult, LangCallbackArg,
 LangSaveVar, LangFreeVar,
 LangFreeSplitProc, LangFreeArg, Tcl_DoubleResults, Tcl_IntResults,
 LangDoCallback, Tk_WidgetResult, Tcl_CreateCommand,
 Tcl_DeleteCommand, Tcl_GetResult.

=back

Current implementation contains enough to make it possible to compile
C<mTk/tkText*.[ch]> with the virgin B<Tk>.

=head2 New types of events ????

PortableTk defines following new types of events:

 TK_EVENTTYPE_NONE
 TK_EVENTTYPE_STRING
 TK_EVENTTYPE_NUMBER
 TK_EVENTTYPE_WINDOW
 TK_EVENTTYPE_ATOM
 TK_EVENTTYPE_DISPLAY
 TK_EVENTTYPE_DATA

and a function

 char *	Tk_EventInfo(int letter,
	    Tk_Window tkwin, XEvent *eventPtr,
 	    KeySym keySym, int *numPtr, int *isNum, int *type,
            int num_size, char *numStorage)

=head1 Checking for trouble

If you start with working TCL code, you can start convertion using
the above hints. Good indication that you are doing is OK is absence
of C<sprintf> and C<sscanf> in your code (at least in the part that is
working with interpreter).

=head1 Additional API

What is described here is not included into base B<portableTk>
distribution. Currently it is coded in B<TCL> and as Perl macros (core
is coded as functions, so theoretically you can use the same object
files with different interpreted languages).

=head2 C<ListFactory>

Dynamic arrays in B<TCL> are used for two different purposes: to
construct strings, and to construct lists. These two usages will have
separate interfaces in other languages (since list is a different type
from a string), so you should use a different interface in your code.

The type for construction of dynamic lists is C<ListFactory>. The API
below is a counterpart of the API for construction of dynamic lists
in B<TCL>:

 void ListFactoryInit(ListFactory *)
 void ListFactoryFinish(ListFactory *)
 void ListFactoryFree(ListFactory *)
 Tcl_Obj * * ListFactoryArg(ListFactory *)
 void ListFactoryAppend(ListFactory *, Tcl_Obj * *arg)
 void ListFactoryAppendCopy(ListFactory *, Tcl_Obj * *arg)
 ListFactory * ListFactoryNewLevel(ListFactory *)
 ListFactory * ListFactoryEndLevel(ListFactory *)
 void ListFactoryResult(Tcl_Interp *, ListFactory *)

The difference is that a call to C<ListFactoryFinish> should precede the
actual usage of the value of C<ListFactory>, and there are two
different ways to append an C<Tcl_Obj *> to a C<ListFactory>:
ListFactoryAppendCopy() guarantees that the value of C<arg> is copied
to the list, but ListFactoryAppend() may append to the list a
reference to the current value of C<arg>. If you are not going to change
the value of C<arg> after appending, the call to ListFactoryAppend may
be quicker.

As in B<TCL>, the call to ListFactoryFree() does not free the
C<ListFactory>, only the objects it references.

The functions ListFactoryNewLevel() and ListFactoryEndLevel() return a
pointer to a C<ListFactory> to fill. The argument of
ListFactoryEndLevel() cannot be used after a call to this function.

=head2 DStrings

Production of strings are still supported in B<portableTk>.

=head2 Accessing C<Tcl_Obj *>s

The following functions for getting a value of an C<Tcl_Obj *> I<may> be
provided:

 double LangDouble(Tcl_Obj *)
 int LangInt(Tcl_Obj *)
 long LangLong(Tcl_Obj *)
 int LangIsList(Tcl_Obj * arg)

The function LangIsList() is supported only partially under B<TCL>,
since there is no data types. It checks whether there is a space
inside the string C<arg>.

=head2 Assigning numbers to C<Tcl_Obj *>s

While LangSetDouble() and LangSetInt() are supported ways to assign
numbers to assign an integer value to a variable, for the sake of
efficiency under B<TCL> it is supposed that the destination of these
commands was massaged before the call so it contains a long enough
string to sprintf() the numbers inside it. If you are going to
immediately use the resulting C<Tcl_Obj *>, the best way to do this is to
declare a buffer in the beginning of a block by

   dArgBuffer;

and assign this buffer to the C<Tcl_Obj *> by

   void LangSetDefaultBuffer(Tcl_Obj * *)

You can also create the buffer(s) manually and assign them using

   void LangSetBuffer(Tcl_Obj * *, char *)

This is the only choice if you need to assign numeric values to
several C<Tcl_Obj *>s simultaneously. The advantage of the first approach is
that the above declarations can be made C<nop>s in different languages.

Note that if you apply C<LangSetDefaultBuffer> to an C<Tcl_Obj *> that
contains some value, you can create a leak if you do not free that
C<Tcl_Obj *> first. This is a non-problem in real languages, but can be a
trouble in C<TCL>, unless you use only the above API.

=head2 Creating new C<Tcl_Obj *>s

The API for creating a new C<Tcl_Obj *> is

 void LangNewArg(Tcl_Obj * *, LangFreeProc *)

The API for creating a new C<Tcl_Obj *> is absent. Just initialize C<Tcl_Obj *> to
be C<NULL>, and apply one of C<LangSet...> methods.

After you use this C<Tcl_Obj *>, it should be freed thusly:

C<LangFreeArg(arg, freeProc)>.

=head2 Evaluating a list

Use

 int LangArgEval(Tcl_Interp *, Tcl_Obj * arg)

Here C<arg> should be a list to evaluate, in particular, the first
element should be a C<LangCallback> massaged to be an C<Tcl_Obj *>. The
arguments can be send to the subroutine by reference or by value in
different languages.

=head2 Getting result as C<Tcl_Obj *>

Use C<Tcl_ArgResult>. It is not guaranteed that result survives this
operation, so the C<Tcl_Obj *> you get should be the only mean to access the
data from this moment on. After you use this C<Tcl_Obj *>, you should free
it with C<freeProc> C<LANG_DYNAMIC> (you can do LangSet...() in between).

=cut