line
stmt
bran
cond
sub
pod
time
code
1
package Tcl::pTk;
2
3
our ($VERSION) = ('0.90');
4
5
121
121
292322
use strict;
121
206
121
4646
6
121
121
151133
use Tcl;
0
0
7
use Exporter ('import');
8
use Scalar::Util (qw /blessed/); # Used only for it's blessed function
9
use AutoLoader; # Used for autoloading the Error routine
10
use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS $platform @cleanup_refs $cleanup_queue_maxsize $cleanupPending);
11
12
# Wait till we have 100 things to delete before we do cleanup
13
$cleanup_queue_maxsize = 50;
14
15
# Set the platform global variable, based on the OS we are running under
16
BEGIN{
17
if($^O eq 'cygwin')
18
{
19
$platform = 'MSWin32'
20
}
21
else
22
{
23
$platform = ($^O eq 'MSWin32') ? $^O : 'unix';
24
}
25
};
26
27
28
use Tcl::pTk::Widget;
29
use Tcl::pTk::MainWindow;
30
use Tcl::pTk::DialogBox;
31
use Tcl::pTk::Dialog;
32
use Tcl::pTk::LabEntry;
33
use Tcl::pTk::ROText;
34
use Tcl::pTk::Listbox;
35
use Tcl::pTk::Balloon;
36
use Tcl::pTk::Menu;
37
use Tcl::pTk::Menubutton;
38
use Tcl::pTk::Optionmenu;
39
use Tcl::pTk::Canvas;
40
use Tcl::pTk::Font;
41
42
43
# Tcl::pTk::libary variable: Translation from perl/tk Tk.pm
44
{($Tcl::pTk::library) = __FILE__ =~ /^(.*)\.pm$/;}
45
$Tcl::pTk::library = Tk->findINC('.') unless (defined($Tcl::pTk::library) && -d $Tcl::pTk::library);
46
47
48
# Global vars used by this package
49
50
our ( %W, $Wint, $Wpath, $Wdata, $DEBUG, $inMainLoop );
51
52
53
# For debugging, we use Sub::Name to name anonymous subs, this makes tracing the program
54
# much easier (using perl -d:DProf or other tools)
55
$DEBUG =0 unless defined($DEBUG);
56
if($DEBUG){
57
require Sub::Name;
58
import Sub::Name;
59
}
60
61
62
@Tcl::pTk::ISA = qw(Tcl);
63
64
65
sub WIDGET_CLEANUP() {1}
66
67
$Tcl::pTk::DEBUG ||= 0;
68
69
sub _DEBUG {
70
# Allow for optional debug level and message to be passed in.
71
# If level is passed in, return true only if debugging is at
72
# that level.
73
# If message is passed in, output that message if the level
74
# is appropriate (with any extra args passed to output).
75
my $lvl = shift;
76
return $Tcl::pTk::DEBUG unless defined $lvl;
77
my $msg = shift;
78
if (defined($msg) && ($Tcl::pTk::DEBUG >= $lvl)) { print STDERR $msg, @_; }
79
return ($Tcl::pTk::DEBUG >= $lvl);
80
}
81
82
83
=head1 NAME
84
85
Tcl::pTk - Interface to Tcl/Tk with Perl/Tk compatible sytax
86
87
=head1 SYNOPSIS
88
89
B
90
91
use Tcl::pTk;
92
93
my $mw = MainWindow->new();
94
my $lab = $mw->Label(-text => "Hello world")->pack;
95
my $btn = $mw->Button(-text => "test", -command => sub {
96
$lab->configure(-text=>"[". $lab->cget('-text')."]");
97
})->pack;
98
MainLoop;
99
100
Or B
101
102
use Tcl::pTk;
103
my $int = new Tcl::pTk;
104
$int->Eval(<<'EOS');
105
# pure-tcl code to create widgets (e.g. generated by some GUI builder)
106
entry .e
107
button .inc -text {increment by Perl}
108
pack .e .inc
109
EOS
110
my $btn = $int->widget('.inc'); # get .inc button into play
111
my $e = $int->widget('.e'); # get .e entry into play
112
$e->configure(-textvariable=>\(my $var='aaa'));
113
$btn->configure(-command=>sub{$var++});
114
$int->MainLoop;
115
116
=head1 DESCRIPTION
117
118
C interfaces perl to an existing Tcl/Tk
119
installation on your computer. It has fully perl/tk (See L) compatible syntax for running existing
120
perl/tk scripts, as well as direct-tcl syntax for using any other Tcl/Tk features.
121
122
Using this module an interpreter object is created, which
123
then provides access to all the installed Tcl libraries (Tk, Tix,
124
BWidgets, BLT, etc) and existing features (for example native-looking
125
widgets using the C package).
126
127
B
128
129
=over
130
131
=item *
132
133
Perl/Tk compatible syntax.
134
135
=item *
136
137
Pure perl megawidgets work just like in perl/tk. See the test case t/slideMegaWidget.t in the source distribution
138
for a simple example.
139
140
=item *
141
142
All the perl/tk widget demos work with minimal changes. Typically the only changes needed are just changing the "Use Tk;"
143
to "Use Tcl::pTk" at the top of the file. See the I demo script included in the source distribution to run the demos.
144
145
=item *
146
147
Built-in local drag-drop support, compatible with perl/tk drag-drop coding syntax.
148
149
=item *
150
151
L package supplied which enables Tcl::pTk to be used with existing Tk Scripts.
152
153
=item *
154
155
Similar interface approach to Tcl/Tk that other dynamic languages use (e.g. ruby, python). Because of this approach,
156
upgrades to Tcl/Tk shouldn't require much coding changes (if any) in L.
157
158
=item *
159
160
L package supplied, which provides a quick way of using the new better-looking Tile/ttk widgets in existing code.
161
162
=item *
163
164
TableMatrix (spreadsheet/grid Tktable widget, built to emulate the perl/tk L interface ) built into the package
165
(as long as you have the Tktable Tcl/Tk extension installed).
166
167
=item *
168
169
Extensive test suite.
170
171
=item *
172
173
Compatible with Tcl/Tk 8.4+
174
175
=back
176
177
=head2 Examples
178
179
There are many examples in the I script (This is very simlar to the I demo installed with
180
perl/tk). After installing the L package, type I on the command line to run.
181
182
The test cases in the I directory of the source distribution also is a good source of code examples.
183
184
=head1 Relation to the L Package
185
186
This package (L) is similar (and much of the code is derived from) the L package,
187
maintained by Vadim Konovalov. However it differs from the L package in some important ways:
188
189
=over 1
190
191
=item * L
192
193
Emphasis is on 100% compatibility with existing perl/tk syntax.
194
195
For developers with a perl/Tk background and an existing perl/Tk codebase to support.
196
For perl/Tk developers looking to take
197
advantage of the look/feel updates in Tcl/Tk 8.5 and above.
198
199
=item * L
200
201
Emphasis is on a lightweight interface to Tcl/Tk with syntax similar to (but not exactly like) perl/tk.
202
203
For developers with some perl/Tk background, writing new code,
204
but no existing perl/Tk codebase to support.
205
206
=back
207
208
=head1 Basic Usage/Operation
209
210
=head2 Creating a Tcl interpreter for Tk
211
212
Before you start using widgets, an interpreter (at least one) should be
213
created, which will manage all things in Tcl. Creating an interpreter is created automatically
214
my the call to the C (or C) methods, but can also be created explicitly.
215
216
B
217
For perl/tk syntax, the interpreter is created for you when you create the mainwindow.
218
219
use Tcl::pTk;
220
221
my $mw = MainWindow->new(); # Create Tcl::pTk interpreter and returns mainwindow widget
222
my $int = $mw->interp; # Get the intepreter that was created in the MainWindow call
223
224
B
225
226
use Tcl::pTk;
227
228
my $int = new Tcl::pTk;
229
230
Optionally a DISPLAY argument can be specified: C.
231
This creates a Tcl interpreter object $int, and creates a main toplevel
232
window. The window is created on display DISPLAY (defaulting to the display
233
named in the DISPLAY environment variable)
234
235
=head2 Entering the main event loop
236
237
B
238
239
MainLoop; # Exact same syntax used as perl/Tk
240
241
B
242
243
$inst->MainLoop;
244
245
=head2 Creating and using widgets
246
247
Two different approaches are used to manipulate widgets (or to manipulate any Tcl objects that
248
act similarly to widgets).
249
250
=over
251
252
=item *
253
254
Perl/Tk compatible-syntax approach. i.e. C<< $widget->method >> syntax.
255
256
=item *
257
258
Direct access using Eval-ed Tcl code. (e.g. using the C<< Eval >> Tcl::pTk method)
259
260
=back
261
262
The first way to manipulate widgets is identical to the perl/Tk calling conventions,
263
the second one uses Tcl syntax. Both ways are interchangeable in that a widget
264
created with one way can be used the another way. This interchangability enables
265
use of Tcl-code created elsewhere (e.g. by some WYSIWYG IDE).
266
267
Usually Perl programs operate with Tcl::pTk via perl/Tk syntax, so users have no
268
need to deal with the Tcl language directly. Only some basic understanding of
269
Tcl/Tk widgets is needed.
270
271
272
=head3 Tcl/Tk syntax
273
274
In order to get better understanding on usage of Tcl/Tk widgets from within
275
Perl, a bit of Tcl/Tk knowledge is needed, so we'll start from 2nd approach,
276
with Tcl's Eval (C<< $int->Eval('...') >>) and then smoothly move to first
277
approach with perl/Tk syntax.
278
279
=over
280
281
=item * The Tcl Interpreter
282
283
The Tcl interpreter is used to process Tcl/Tk widgets; within C you
284
create it with C, and given any widget object, you can retreive it by the
285
C<< $widget->interp >> method. ( Within pure Tcl/Tk the interpreter already exists,
286
you don't need to create it explicitly. )
287
288
=item * The Widget Path
289
290
The Widget path is a string starting with a dot and consisting of several
291
names separated by dots. These names are individual widget-names that comprise
292
a widget's hierarchy. As an example, if there exists a frame with a path
293
C<.fram>, and you want to create a button on it and name it C, then
294
you should specify name C<.fram.butt>. Widget paths are also refered in
295
other miscellaneous widget operations, like geometry management.
296
297
At any time a widget's path can be retreived with C<< $widget->path; >>
298
within C.
299
300
=item * The Widget Path as a Tcl/Tk command
301
302
When a widget is created in Tcl/Tk, a special command is created that is the name of the
303
widget's path. For example, a button created in a frame has a path and command-name C<.fr.b>. This
304
command also has subcommands which manipulate the widget. That is why
305
C<< $int->Eval('.fr.b configure -text {new text}'); >> makes sense.
306
Note that using perl/tk syntax C<< $button->configure(-text=>'new text'); >> does exactly the same thing,
307
if C<$button> corresponds to C<.fr.b> widget.
308
309
310
=back
311
312
313
The C statement not only creates the C package, but also creates the
314
C package, which is responsible for widgets. Each widget ( an object
315
blessed to C, or any of its subclasses )
316
behaves in such a way that its method will result in calling it's path on the
317
interpreter.
318
319
=head3 Perl/Tk syntax
320
321
C fully supports perl/Tk widget syntax of the L package, which has been used for many years. This means that any C widget
322
has a number of methods like C, C , C, C and so
323
on, and invoking those methods will create an appropriate child widget.
324
C will generate an unique path-name for a newly created widget.
325
326
To demonstrate this concept, the perl/Tk syntax:
327
328
my $label = $frame->Label(-text => "Hello world");
329
330
executes the command
331
332
$int->call("label", ".l", "-text", "Hello world");
333
334
and this command similar to
335
336
$int->Eval("label .l -text {Hello world}");
337
338
This way Tcl::pTk widget commands are translated to Tcl syntax and directed to
339
the Tcl interpreter. This translation that occurs from perl/Tk syntax to Tcl calls is why the two approaches for
340
dealing with widgets are interchangeable.
341
342
The newly created widget C<$label> will be blessed to package C
343
which is isa-C (i.e. C is a subclass of C).
344
345
346
=head1 Categories of Tcl::pTk Widgets
347
348
C Widgets fall into the following basic categories, based on how they are implemented in the C package.
349
350
=over 1
351
352
=item Direct auto-wrapped widgets
353
354
These types of widgets (for example the Entry, Button, Scrollbar, and Label widgets) have no special code written for them
355
in C. Their creation and method calls (e.g. C<$button->configure(-text => 'ButtonText')> ) are handled
356
by the wrapping code in the base Tcl::pTk::Widget package.
357
358
=item Auto-wrapped widgets, with compatibility code
359
360
These types of widgets are similar to the Direct auto-wraped widgets, but have additional code written to be completely
361
compatibile with the perl/Tk syntax. Examples of this type of widget are the Text, Frame, Menu, and Menubutton widgets.
362
363
=item Megawidgets
364
365
These are widgets that are composed of one-or-more other base widget types. Pure-perl megawidgets are supported in Tcl::pTk,
366
just like they are in perl/Tk. Examples of these types of widgets are ProgressBar, LabEntry, BrowseEntry, and SlideSwitch (one of the test cases in the source distribution).
367
368
=item Derived Widgets
369
370
Derived widgets are sub-classes of existing widgets that provide some additional functions. Derived widgets are created in
371
Tcl::pTk using very similar syntax to perl/Tk (i.e. using the Tcl::pTk::Derived package, similar to the Tk::Derived package).
372
Examples of these types of widgets are Tree, TextEdit, TextUndo, ROText, and DirTree.
373
374
=back
375
376
=head1 A behind-the-scenes look at auto-wrapped widgets
377
378
All widgets in C are objects, and have an inheritance hierarchy that derives from the C
379
parent class. Megawidgets and derived widgets are handled very similar (if not exactly) the same as in perl/tk.
380
381
Auto-wrapped widgets (like the Entry, Button, Scrollbar, etc.) are handled differently.
382
The object system for these types of widgets is dynamic. Classes and/or methods are created when they are
383
first used or needed.
384
385
The following describes how methods are called for the two different categories of auto-wrapped widgets
386
387
=over 1
388
389
=item Direct auto-wrapped widget example
390
391
Here is an example of a Entry widget, a direct auto-wrapped widget:
392
393
my $entry = $mw->Entry->pack; # Create an entry widget and pack it
394
$entry->insert('end', -text=>'text'); # Insert some text into the Entry
395
my $entryText = $entry->get(); # Get the entry's text
396
397
Internally, the following mechanics come into play:
398
The I method creates an I widget (known as C in the Tcl/Tk environment).
399
When this creation method is invoked the first time, a package
400
C is created, which sets up the class hierarchy for any
401
further Entry widgets. The newly-created C class is be
402
a direct subclass of C.
403
404
The second code line above calls the C method of the C<$entry> object.
405
When invoked first time, a method (i.e. subref) C is
406
created in package C, which will end-up calling
407
calling the C method on the Tcl/Tk interpreter (i.e.
408
C<$entry->interp()->invoke($entry, 'insert', -text, 'text')
409
410
The first time C is called, the C method does not exist, so AUTOLOAD
411
comes into play and creates the method. The second time C is called, the already-created
412
method is called directly (i.e. not created again), thus saving execution time.
413
414
=item Auto-wrapped widgets, with compatibility code
415
416
Here is an example of a Text widget, which is an auto-wrapped widget with extra
417
code added for compatibility with the perl/tk Text widget.
418
419
my $text = $mw->Text->pack; # Create an text widget and pack it
420
$text->insert('end', -text=>'text'); # Insert some text into the Text
421
@names = $text->markNames; # Get a list of the marks set in the
422
# Text widget
423
424
Internally, following mechanics come into play:
425
The I method creates an I widget (known as C in Tcl/Tk environment).
426
Because a C package already exists, a new package is not created
427
at runtime like the case above.
428
429
The second code line above calls the C of the C<$text> object of type
430
C. This C method is already defined in the C package,
431
so it is called directly.
432
433
The third code line above calls the C method on the C<$text> object. This method
434
is not defined in the C package, so the first time when C is called,
435
AUTOLOAD in the L package comes into play and creates the method.
436
The second time C is called, the already-created
437
method is called directly (i.e. not created again), thus saving execution time.
438
439
=back
440
441
=head2 Description of an auto-wrapped method call
442
443
Suppose C<$widget> isa C, its path is C<.path>, and method
444
C invoked on it with a list of parameters, C<@parameters>:
445
446
$widget->method(@parameters);
447
448
In this case all C<@parameters> will be preprocessed by performing the following actions:
449
450
=over
451
452
=item 1.
453
454
For each variable reference, a Tcl variable will be created and tied to it, so changes in the perl variable
455
will be reflected in the Tcl variable, and changes in the Tcl variable will show up in the perl variable.
456
457
=item 2.
458
459
For each perl code-reference, a Tcl command will be created that calls this perl code-ref.
460
461
=item 3.
462
463
Each array reference will considered a callback, and proper actions will be taken.
464
465
=back
466
467
After processing of C<@parameters>, the Tcl/Tk interpreter will be requested to
468
perform following operation:
469
470
=over
471
472
=item if C<$method> is all lowercase (e.g. C), C
473
474
C<.path method parameter1 parameter2> I<....>
475
476
=item if C<$method> contains exactly one capital letter inside the method name (e.g. C), C
477
478
C<.path method submethod parameter1 parameter2> I<....>
479
480
=item if C<$method> contains several capital letter inside the method name, C
481
482
C<.path method submeth subsubmeth parameter1 parameter2> I<....>
483
484
=back
485
486
=head2 Fast method invocation for auto-wrapped widgets
487
488
If you are sure that preprocessing of C<@parameters> in a method call aren't required
489
(i.e. no parameters are Perl references to scalars, subroutines or arrays), then
490
the preprocessing step described above can be skipped by calling the method with
491
an underscore C<_> prepended to the name. (e.g call C<$text->_markNames()>, instead of
492
C<$text->markNames()>). Calling the method this way means you are using an internal
493
method that executes faster, but normally you should use a "public" (i.e. non-underscore) method, which includes all preprocessing.
494
495
Example:
496
497
# Can't use the faster method-call here, because \$var must be
498
# preprocessed for Tcl/Tk:
499
$button->configure(-textvariable=>\$var);
500
501
# Faster version of insert method for the "Text" widget
502
$text->_insert('end','text to insert','tag');
503
504
# This line does exactly same thing as previous line:
505
$text->_insertEnd('text to insert','tag');
506
507
When doing many inserts to a text widget, the faster version can help speed things up.
508
509
510
=head1 Using any Tcl/Tk feature from Tcl::pTk
511
512
In addition to the standard widgets (e.g. Entry, Button, Menu, etc), the C module
513
lets you use any other widget from the Tcl/Tk widget library. This can be done with either
514
Tcl syntax (via the C method), or with regular perl/tk syntax.
515
516
To interface to a new Tcl/Tk widget using perl/tk syntax, a C method call
517
is made on an already-created widget, or on the C interpreter object itself.
518
519
Syntax is
520
521
# Calling Declare on a widget object:
522
$widget->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
523
@options);
524
525
or, exactly the same,
526
527
# Calling Declare on a the Tcl::pTk Interpreter object:
528
$interp->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
529
@options);
530
531
Options are:
532
533
-require => 'tcl-package-name'
534
-prefix => 'some-prefix'
535
536
The I<-require> option specifies the new Tcl/Tk widget requires a Tcl package to be loaded with a name
537
of 'tcl-package-name';
538
539
The I<-prefix> option used to specify the prefix of the autogenerated widget path-name. This option is
540
normally used when the Tcl/Tk widget name contains non-alphabetic characters (e.g. ':'). If not specified, the
541
prefix will be generated from the package-name.
542
543
A typical example of using the C method:
544
545
$mw->Declare('BLTNoteBook','blt::tabnotebook',-require=>'BLT',-prefix=>'bltnbook');
546
547
After this call, C will create a widget creation method for this new package to make it an
548
auto-wrapped widget (See the definition of auto-wrapped widgets above).
549
550
This means
551
552
my $tab = $mw->BLTNoteBook;
553
554
will create blt::tabnotebook widget. Effectively, this is equavalent to the following
555
Tcl/Tk code:
556
557
package require BLT # but invoked only once
558
blt::tabnotebook .bltnbook1
559
560
After the above example code, the variable C<$tab> is a B that behaves in
561
the usual way, for example:
562
563
$tab->insert('end', -text=>'text');
564
$tab->tabConfigure(0, -window=>$tab->Label(-text=>'text of label'));
565
566
These two lines are the Tcl/Tk equivalent of:
567
568
.bltnbook1 insert end -text {text}
569
.bltnbook1 tab configure 0 -window [label .bltnbook1.lab1 -text {text of label}]
570
571
You can also intermix the perl/tk and Tcl/Tk syntax like this:
572
573
$interp->Eval('package require BLT;blt::tabnotebook .bltnbook1');
574
$tab = $interp->widget('.bltnbook1');
575
$tab->tabConfigure(0, -window=>$tab->Label(-text=>'text of label'));
576
577
=head1 How to read Tcl/Tk widget docs when using in C
578
579
For the documentation of standard perl/tk widgets (like Button, Entry, Menu, etc), you can refer
580
to the the perl/tk docs L (We may move a copy of the perl/tk docs to Tcl::pTk in the future). For non-standard
581
widgets (like the BLTNotebook widget example above) you have to use the Tcl docs on the widget for the widget documentation. (Most Tcl/Tk
582
docs can be found at http://www.tcl.tk/ )
583
584
When reading Tcl/Tk widget documentation about widgets, you can apply the following guidelines to determine how
585
to use the widget in C using perl/tk syntax.
586
587
Suppose the Tcl/Tk docs say:
588
589
pathName method-name optional-parameters
590
(some description)
591
592
This means the widget has a has method C and you can
593
invoke it in C like
594
595
$widget->method-name(optional-parameters);
596
597
The C<$widget> variable in C is like the I in the Tcl/Tk docs.
598
599
Sometimes the Tcl/Tk method-name consists of two words (verb1 verb2). In this
600
case there are two equivalent ways to invoke it, C< $widget->verb1('verb2',...); > or
601
C< $widget->verb1Verb2(...)>;
602
603
Widget options are used just like they are shown in the Tcl/Tk docs. There is no special translation needed
604
for the widget options described in the Tcl/Tk docs for use in C.
605
606
=head1 Miscellaneous methods
607
608
=head2 C<< $int->widget( path, widget-type ) >>
609
610
When widgets are created in C they are stored internally and can and can be retreived
611
by the C method, which takes widget path as first parameter, and optionally
612
the widget type (such as Button, or Text etc.). For Example:
613
614
# this will retrieve widget, and then call configure on it
615
widget(".fram.butt")->configure(-text=>"new text");
616
617
# this will retrieve widget as Button (Tcl::pTk::Button object)
618
my $button = widget(".fram.butt", 'Button');
619
620
# same but retrieved widget considered as general widget, without
621
# specifying its type. This will make it a generic Tcl::pTk::Widget object
622
my $button = widget(".fram.butt");
623
624
Please note that this method will return to you a widget object even if it was
625
not created within C. A check is not performed to see if a
626
widget with given path name exists. This enables the use of widgets created elsewhere
627
in Tcl/Tk to be treated like C widgets.
628
629
=head2 C
630
631
If you need to associate any data with particular widget, you can do this with
632
C method of either interpreter or widget object itself. This method
633
returns same anonymous hash and it should be used to hold any keys/values pairs.
634
635
Examples:
636
637
$interp->widget_data('.fram1.label2')->{var} = 'value';
638
$label->widget_data()->{var} = 'value';
639
640
B
641
642
Use of this method has largely been superceded by the perl/tk-compatible C widget method.
643
644
645
646
=head2 C<< $widget->tooltip("text") >>
647
648
Any widget accepts the C method, accepting any text as parameter, which
649
will be used as floating help text explaining the widget. The widget itself
650
is returned, so to provide convenient way of chaining:
651
652
$mw->Button(-text=>"button 1")->tooltip("This is a button, m-kay")->pack;
653
$mw->Entry(-textvariable=>\my $e)->tooltip("enter the text here, m-kay")->pack;
654
655
The C method uses the C package, which is a part of C within
656
Tcl/Tk, so be sure you have that Tcl/Tk package installed.
657
658
Note: The perl/tk-compatible B widget is also available for installing tool-tips on widgets
659
and widget-elements.
660
661
662
=head1 Terminology
663
664
In the documentation and comments for this package, I, I, I, I, and I are used. These terms have the
665
following meanings in the context of this package.
666
667
=over 1
668
669
=item perl/Tk
670
671
The traditional perl interface to the Tk GUI libraries. i.e the perl package occupying the L namespace on CPAN.
672
673
=item Tcl/Tk
674
675
The Tcl/Tk package with tcl-code and associated libraries (e.g. Tcl.so or Tcl.dll and associated tcl-code). See http://www.tcl.tk/
676
677
=item Tcl::pTk
678
679
This package, which provides a perl interface into the Tcl/Tk GUI libraries.
680
681
=item Tcl.pm
682
683
The L perl package, which provides a simple interface from perl to Tcl/Tk. L interpreter objects are subclassed
684
from the L package.
685
686
=item Tcl
687
688
The I programming language.
689
690
=back
691
692
693
=head1 BUGS
694
695
Currently work is in progress, and some features could change in future
696
versions.
697
698
=head1 AUTHORS
699
700
=over
701
702
=item Malcolm Beattie.
703
704
=item Vadim Konovalov, vadim_tcltk@vkonovalov.ru 19 May 2003.
705
706
=item Jeff Hobbs, jeffh _a_ activestate com, February 2004.
707
708
=item Gisle Aas, gisle _a_ activestate . com, 14 Apr 2004.
709
710
=item John Cerney, john.cerney _a_ gmail . com, 29 Sep 2009.
711
712
=back
713
714
=head1 COPYRIGHT
715
716
This program is free software; you can redistribute it and/or modify it
717
under the same terms as Perl itself.
718
719
See http://www.perl.com/perl/misc/Artistic.html
720
721
=cut
722
723
my @misc = qw( after destroy focus grab lower option place raise
724
image font
725
selection tk grid tkwait update winfo wm);
726
my @perlTk = qw( MainWindow MainLoop DoOneEvent tkinit update Ev Exists);
727
728
# Flags for supplying to DoOneEvent
729
my @eventFlags = qw(DONT_WAIT WINDOW_EVENTS FILE_EVENTS
730
TIMER_EVENTS IDLE_EVENTS ALL_EVENTS);
731
732
@EXPORT = (@perlTk, @eventFlags);
733
@EXPORT_OK = (@misc );
734
%EXPORT_TAGS = (widgets => [], misc => \@misc, perlTk => \@perlTk,
735
eventtypes => [@eventFlags],
736
);
737
738
## TODO -- module's private $tkinterp should go away!
739
my $tkinterp = undef; # this gets defined when "new" is done
740
741
# Hash to keep track of all created widgets and related instance data
742
# Tcl::pTk will maintain PATH (Tk widget pathname) and INT (Tcl interp)
743
# and the user can create other info.
744
%W = (
745
INT => {}, # Hash of mainwindowID or pathname => Tcl::pTk Interpreter Reference
746
PATH => {}, # Hash of pathname => pathname (or mainwindow id)
747
RPATH => {}, # Hash of pathname => widget reference
748
DATA => {}, # Hash of widget data (used by the widget_data methods)
749
);
750
# few shortcuts for %W to be faster
751
$Wint = $W{INT};
752
$Wpath = $W{PATH};
753
$Wdata = $W{DATA};
754
755
756
757
# hash to keep track on preloaded Tcl/Tk modules, such as Tix, BWidget
758
my %preloaded_tk; # (interpreter independent thing. is this right?)
759
760
#
761
sub new {
762
my ($class, $display) = @_;
763
Carp::croak 'Usage: $interp = new Tcl::pTk([$display])'
764
if @_ > 1;
765
my @argv;
766
if (defined($display)) {
767
push(@argv, -display => $display);
768
} else {
769
$display = $ENV{DISPLAY} || '';
770
}
771
my $i = new Tcl;
772
bless $i, $class;
773
$i->SetVar2("env", "DISPLAY", $display, Tcl::GLOBAL_ONLY);
774
$i->SetVar("argv", [@argv], Tcl::GLOBAL_ONLY);
775
$i->SetVar("tcl_interactive", 0, Tcl::GLOBAL_ONLY);
776
$i->SUPER::Init();
777
$i->pkg_require('Tk', $i->GetVar('tcl_version'));
778
779
my $mwid = $i->invoke('winfo','id','.');
780
$W{PATH}->{$mwid} = '.';
781
$W{INT}->{$mwid} = $i;
782
$W{mainwindow}->{"$i"} = bless({ winID => $mwid }, 'Tcl::pTk::MainWindow');
783
784
# When mainwindow goes away, delete entry from the $W{mainwindow} global hash:
785
$i->call('trace', 'add', 'command', '.', 'delete',
786
sub { delete $W{mainwindow}{"$i"} }
787
);
788
$i->ResetResult();
789
790
$Tcl::pTk::TK_VERSION = $i->GetVar("tk_version");
791
# Only do this for DEBUG() ?
792
$Tk::VERSION = $Tcl::pTk::TK_VERSION;
793
$Tk::VERSION =~ s/^(\d)\.(\d)/${1}0$2/;
794
unless (defined $tkinterp) {
795
# first call, create command-helper in TCL to trace widget destruction
796
$i->CreateCommand("::perl::w_del", \&widget_deletion_watcher);
797
798
# Create command-helper in TCL to perform the actual widget cleanup
799
# (deferred in a afterIdle call )
800
$i->CreateCommand("::perl::w_cleanup", \&widget_cleanup);
801
}
802
$tkinterp = $i;
803
804
# Create background error handling method that is similar to the way perltk does it
805
$tkinterp->CreateCommand('bgerror', \&Tcl::pTk::bgerror);
806
807
return $i;
808
}
809
810
sub mainwindow {
811
# this is a window with path '.'
812
my $interp = shift;
813
814
815
return $W{mainwindow}->{"$interp"};
816
}
817
sub tkinit {
818
my $interp = Tcl::pTk->new(@_);
819
$interp->mainwindow;
820
}
821
822
sub MainWindow {
823
my $interp = Tcl::pTk->new(@_);
824
825
# Load Tile Widgets, if the tcl version is > 8.5
826
my $patchlevel = $interp->icall('info', 'patchlevel');
827
my (@patchElems) = split('\.', $patchlevel);
828
my $versionNumber = $patchElems[0] + $patchElems[1]/1000 + $patchElems[2]/100e3; # convert version to number
829
if( $versionNumber >= 8.005 ){
830
require Tcl::pTk::Tile;
831
Tcl::pTk::Tile::_declareTileWidgets($interp);
832
}
833
834
# Load palette commands, so $interp->invoke can be used with them later, for speed.
835
$interp->call('auto_load', 'tk_setPalette');
836
837
838
# Declare auto-widgets, so subclasses of auto-created widgets will work correctly.
839
Tcl::pTk::Widget::declareAutoWidget($interp);
840
841
842
$interp->mainwindow;
843
}
844
845
846
## Front-End for fileevent that can be called using Tcl::pTk->fileevent, instead of the normal
847
# $widget->filevent syntax. This is provided for compatibility with perl/tk
848
#
849
sub fileevent{
850
my $firstArg = shift;
851
my $int = ( ref($firstArg) ? $firstArg : $tkinterp ); # Get default interp, unless supplied
852
my $mw = $int->mainwindow(); # Get the mainwindow for this interpreter
853
854
# Call the normal fileevent
855
$mw->fileevent(@_);
856
}
857
858
sub MainLoop {
859
# This perl-based mainloop differs from Tk_MainLoop in that it
860
# relies on the traced deletion of '.' instead of using the
861
# Tk_GetNumMainWindows C API.
862
# This could optionally be implemented with 'vwait' on a specially
863
# named variable that gets set when '.' is destroyed.
864
unless ($inMainLoop){ # Don't recursivly enter into a mainloop
865
local $inMainLoop = 1;
866
my $int = (ref $_[0]?shift:$tkinterp);
867
my $mainwindow = $W{mainwindow};
868
while ( %$mainwindow ) { # Keep calling DoOneEvent until all mainwindows go away
869
$int->DoOneEvent(0);
870
}
871
}
872
}
873
874
# timeofday function for compatibility with Tk::timeofday
875
sub timeofday {
876
# This perl-based mainloop differs from Tk_MainLoop in that it
877
# relies on the traced deletion of '.' instead of using the
878
# Tk_GetNumMainWindows C API.
879
# This could optionally be implemented with 'vwait' on a specially
880
# named variable that gets set when '.' is destroyed.
881
my $int = (ref $_[0]?shift:$tkinterp);
882
my $t = $int->invoke("clock", "microseconds");
883
$t = $t/1e6;
884
}
885
886
887
# DoOneEvent for compatibility with perl/tk
888
sub DoOneEvent{
889
my $int = (ref $_[0]?shift:$tkinterp);
890
my $flags = shift;
891
$int->Tcl::DoOneEvent($flags);
892
}
893
894
# After wrapper for compatibility with perl/tk (So that Tcl::pTk->after(delay) calls work
895
sub after{
896
my $int = shift;
897
$int = (ref($int) ? $int : $tkinterp ); # if interpreter not supplied use $tkinterp
898
my $ms = shift;
899
my $callback = shift;
900
901
$ms = int($ms) if( $ms =~ /\d/ ); # Make into an integer to keep tk from complaining
902
903
if( defined($callback)){
904
# Turn into callback, if not one already
905
unless( blessed($callback) and $callback->isa('Tcl::pTk::Callback')){
906
$callback = Tcl::pTk::Callback->new($callback);
907
}
908
909
my $sub = sub{ $callback->Call()};
910
#print "Tcl::pTk::after: setting after on $sub\n";
911
my $ret = $int->call('after', $ms, $sub );
912
return $int->declare_widget($ret);
913
}
914
else{ # No Callback defined, just do a sleep
915
return $int->call('after', $ms );
916
}
917
918
return($int->call('after', $ms));
919
}
920
921
922
# create_widget Method
923
# This is used as a front-end to the declare_widget method, so that -command and -variable configuration
924
# options supplied at widget-creation will be properly stored as Tcl::pTk::Callback objects (for perltk
925
# compatibility).
926
# This is done by issuing the -command or -variable type option after widget creation, where the callback object can be
927
# stored with the widget
928
sub create_widget{
929
my $int = shift; # Interperter
930
my $parent = shift; # Parent widget
931
my $id = shift; # unique id for the new widget
932
my $ttktype = shift; # Name of widget, in tcl/tk
933
my $widget_class = shift || 'Tcl::pTk::Widget';
934
935
my @args = @_;
936
937
my @filteredArgs; # args, filtered of any -command type options
938
my @commandOptions; # any command options needed to be issued after widget creation.
939
940
# Go thru each arg and look for callback (i.e -command ) args
941
my $lastArg;
942
foreach my $arg(@args){
943
944
if( defined($lastArg) && !ref($lastArg) && ( $lastArg =~ /^-\w+/ ) ){
945
if( $lastArg =~ /command|cmd$/ && defined($arg) ) { # Check for last arg something like -command
946
947
#print "Found command arg $lastArg => $arg\n";
948
949
# Save this option for issuing after widget creation
950
push @commandOptions, $lastArg, $arg;
951
952
# Remove the lastArg from the current arg queue, since we will be handling
953
# it using @commandOptions
954
pop @filteredArgs;
955
956
$lastArg = undef;
957
next;
958
}
959
if( $lastArg =~ /variable$/ ){ # Check for last arg something like -textvariable
960
# Save this option for issuing after widget creation
961
push @commandOptions, $lastArg, $arg;
962
963
# Remove the lastArg from the current arg queue, since we will be handling
964
# it using @commandOptions
965
pop @filteredArgs;
966
967
$lastArg = undef;
968
next;
969
}
970
971
}
972
973
$lastArg = $arg;
974
975
push @filteredArgs, $arg;
976
}
977
978
# Make the normal declare_widget call
979
my $widget = $int->declare_widget($parent->call($ttktype, $id, @filteredArgs), $widget_class);
980
981
# Make configure call for any left-over commands
982
$widget->configure(@commandOptions) if(@commandOptions);
983
984
return $widget;
985
}
986
987
988
#
989
# declare_widget, method of interpreter object
990
# args:
991
# - a path of existing Tcl/Tk widget to declare its existance in Tcl::pTk
992
# - (optionally) package name where this widget will be declared, default
993
# is 'Tcl::pTk::Widget', but could be 'Tcl::pTk::somewidget'
994
sub declare_widget {
995
my $int = shift;
996
my $path = shift;
997
my $widget_class = shift || 'Tcl::pTk::Widget';
998
# JH: This is all SOOO wrong, but works for the simple case.
999
# Issues that need to be addressed:
1000
# 1. You can create multiple interpreters, each containing identical
1001
# pathnames. This var should be better scoped.
1002
# VK: mostly resolved, such interpreters with pathnames allowed now
1003
# 2. There is NO cleanup going on. We should somehow detect widget
1004
# destruction (trace add command delete ... in 8.4) and interp
1005
# destruction to clean up package variables.
1006
#my $id = $path=~/^\./ ? $int->invoke('winfo','id',$path) : $path;
1007
$int->invoke('trace', 'add', 'command', $path, 'delete', "::perl::w_del $path")
1008
if ( WIDGET_CLEANUP && $path !~ /\#/); # don't trace for widgets like 'after#0'
1009
my $id = $path;
1010
my $w = bless({ winID => $id}, $widget_class);
1011
Carp::confess("id is not found\n") if( !defined($id));
1012
$Wpath->{$id} = $path; # widget pathname
1013
$Wint->{$id} = $int; # Tcl interpreter
1014
$W{RPATH}->{$path} = $w;
1015
1016
1017
return $w;
1018
}
1019
1020
sub widget_deletion_watcher {
1021
my (undef,$int,undef,$path) = @_;
1022
#print STDERR "[D:$path]\n";
1023
1024
# Call the _OnDestroy method on the widget to perform cleanup on it
1025
my $w = $W{RPATH}->{$path};
1026
#print STDERR "Calling _Destroyed on $w, Ind = ".$Idelete++."\n";
1027
$w->_Destroyed();
1028
1029
$int->delete_widget_refs($path);
1030
1031
delete $W{RPATH}->{$path};
1032
}
1033
1034
###############################################
1035
# Overriden delet_ref
1036
# Instead of immediately deleting a scalar or code ref in Tcl-land,
1037
# queue the ref to be deleted in an after-idle call.
1038
# This is done, rather than deleting immediately, because an immediate delete
1039
# before a widget is completely destroyed can causes Tcl-crashes.
1040
sub delete_ref {
1041
my $interp = shift;
1042
my $rname = shift;
1043
my $ref = $interp->return_ref($rname);
1044
push @cleanup_refs, $rname;
1045
1046
# Create an after-idle call to delete refs, if the cleanup queue is bigger
1047
# than the threshold
1048
if( !$cleanupPending and scalar(@cleanup_refs) > $cleanup_queue_maxsize ){
1049
#print STDERR "Calling after idle cleanup on ".join(", ", @cleanup_refs)."\n";
1050
$cleanupPending = 1; # Setup flag so we don't call the after idle multiple times
1051
$interp->call('after', 'idle', "::perl::w_cleanup");
1052
}
1053
return $ref;
1054
}
1055
1056
1057
# Sub to cleanup any que-ed commands and variables in
1058
# @cleanup_refs. This usually called from an after-idle procedure
1059
sub widget_cleanup {
1060
my (undef,$int,undef,$path) = @_;
1061
1062
my @deleteList = @cleanup_refs;
1063
1064
# Go thru each list and delete
1065
foreach my $rname(@deleteList){
1066
#print "Widget_Cleanup deleting $rname\n";
1067
1068
$int->SUPER::delete_ref($rname);
1069
}
1070
1071
# Zero-out cleanup_refs
1072
@cleanup_refs = ();
1073
$cleanupPending = 0; # Reset cleanup flag for next time
1074
1075
}
1076
1077
# widget_data return anonymous hash that could be used to hold any
1078
# user-specific data
1079
sub widget_data {
1080
my $int = shift;
1081
my $path = shift;
1082
$Wdata->{$path} ||= {};
1083
return $Wdata->{$path};
1084
}
1085
1086
# subroutine awidget used to create [a]ny [widget]. Nothing complicated here,
1087
# mainly needed for keeping track of this new widget and blessing it to right
1088
# package
1089
sub awidget {
1090
my $int = (ref $_[0]?shift:$tkinterp);
1091
my $wclass = shift;
1092
# Following is a suboptimal way of autoloading, there should exist a way
1093
# to Improve it.
1094
my $sub = sub {
1095
my $int = (ref $_[0]?shift:$tkinterp);
1096
my ($path) = $int->call($wclass, @_);
1097
return $int->declare_widget($path);
1098
};
1099
unless ($wclass=~/^\w+$/) {
1100
die "widget name '$wclass' contains not allowed characters";
1101
}
1102
# create appropriate method ...
1103
no strict 'refs';
1104
*{"Tcl::pTk::$wclass"} = $sub;
1105
# ... and call it (if required)
1106
if ($#_>-1) {
1107
return $sub->($int,@_);
1108
}
1109
}
1110
sub widget($@) {
1111
my $int = (ref $_[0]?shift:$tkinterp);
1112
my $wpath = shift;
1113
my $wtype = shift || 'Tcl::pTk::Widget';
1114
if (exists $W{RPATH}->{$wpath}) {
1115
return $W{RPATH}->{$wpath};
1116
}
1117
unless ($wtype=~/^(?:Tcl::pTk)/) {
1118
Tcl::pTk::Widget::create_widget_package($wtype);
1119
$wtype = "Tcl::pTk::$wtype";
1120
}
1121
#if ($wtype eq 'Tcl::pTk::Widget') {
1122
# require Carp;
1123
# Carp::cluck("using \"widget\" without widget type is strongly discouraged");
1124
#}
1125
# We could ask Tcl about it by invoking
1126
# my @res = $int->Eval("winfo exists $wpath");
1127
# but we don't do it, as long as we allow any widget paths to
1128
# be used by user.
1129
my $w = $int->declare_widget($wpath,$wtype);
1130
return $w;
1131
}
1132
1133
sub Exists {
1134
my $wid = shift;
1135
return 0 unless defined($wid);
1136
if (blessed($wid) && $wid->isa('Tcl::pTk::Widget') ) {
1137
my $wp = $wid->path;
1138
my $interp = $wid->interp;
1139
return 0 unless( defined $interp); # Takes care of some issues during global destruction
1140
return $interp->icall('winfo','exists',$wp);
1141
}
1142
return eval{$tkinterp->icall('winfo','exists',$wid)};
1143
}
1144
1145
sub widgets {
1146
\%W;
1147
}
1148
1149
sub pkg_require {
1150
# Do Tcl package require with optional version, cache result.
1151
my $int = shift;
1152
my $pkg = shift;
1153
my $ver = shift;
1154
1155
my $id = "$int$pkg"; # to made interpreter-wise, do stringification of $int
1156
1157
return $preloaded_tk{$id} if $preloaded_tk{$id};
1158
1159
my @args = ("package", "require", $pkg);
1160
push(@args, $ver) if defined($ver);
1161
eval { $preloaded_tk{$id} = $int->icall(@args); };
1162
if ($@) {
1163
# Don't cache failures, as the package may become available by
1164
# changing auto_path and such.
1165
return;
1166
}
1167
return $preloaded_tk{$id};
1168
}
1169
1170
sub need_tk {
1171
# DEPRECATED: Use pkg_require and call instead.
1172
my $int = shift;
1173
my $pkg = shift;
1174
my $cmd = shift || '';
1175
warn "DEPRECATED CALL: need_tk($pkg, $cmd), use pkg_require\n";
1176
if ($pkg eq 'ptk-Table') {
1177
require Tcl::pTk::Table;
1178
}
1179
else {
1180
# Only require the actual package once
1181
my $ver = $int->pkg_require($pkg);
1182
return 0 if !defined($ver);
1183
$int->Eval($cmd) if $cmd;
1184
}
1185
return 1;
1186
}
1187
1188
1189
1190
# subroutine findINC copied from perlTk/Tk.pm
1191
sub findINC {
1192
my $file = join('/',@_); # Normal location
1193
my $fileImage = join('/', $_[0], 'images', $_[1]); # alternate location in the 'images' directory
1194
my $dir;
1195
$file =~ s,::,/,g;
1196
$fileImage =~ s,::,/,g;
1197
foreach $dir (@INC) {
1198
my $path;
1199
1200
# check for normal location and 'images' location of the file
1201
return $path if (-e ($path = "$dir/$file") );
1202
return $path if (-e ($path = "$dir/$fileImage") );
1203
1204
}
1205
return undef;
1206
}
1207
1208
1209
1210
# sub Declare is just a dispatcher into Tcl::pTk::Widget method
1211
sub Declare {
1212
Tcl::pTk::Widget::Declare(undef,@_[1..$#_]);
1213
}
1214
1215
1216
#
1217
# AUTOLOAD method for Tcl::pTk interpreter object, which will bring into
1218
# existance interpreter methods
1219
sub AUTOLOAD {
1220
my $int = shift;
1221
my ($method,$package) = $Tcl::pTk::AUTOLOAD;
1222
1223
# If this is the Tcl::pTk::Error routine,
1224
# Call the standard Autoloader::AUTOLOAD to
1225
# load our Error routine that has been autosplit to a separate file
1226
# (i.e. appears after the _END_).
1227
# Autoloading the Error routine keeps from getting subroutine redefined warnings
1228
# when the user supplies their own Error routine or Tcl::pTk::ErrorDialog is used.
1229
if( $method =~ /Tcl::pTk::Error/ ){
1230
if( defined( $Tcl::pTk::TkHijack::translateList ) ){
1231
#print "TkHijack is loaded\n";
1232
# If TkHijack is loaded and the user has define their own
1233
# Tk::Error, call that:
1234
if( defined(&Tk::Error)){
1235
#print "Tk::Error has been defined\n";
1236
*Tcl::pTk::Error = \&Tk::Error;
1237
return $int->Tcl::pTk::Error(@_);
1238
1239
}
1240
}
1241
$AutoLoader::AUTOLOAD = $method;
1242
unshift @_, $int; # Put arg back on stack like AUTOLOAD expects it
1243
goto &AutoLoader::AUTOLOAD;
1244
}
1245
1246
# Normal handling follows
1247
my $method0;
1248
for ($method) {
1249
s/^(Tcl::pTk::)//
1250
or Carp::confess "weird inheritance ($method)";
1251
$package = $1;
1252
$method0 = $method;
1253
s/(?
1254
s/(?
1255
}
1256
1257
# if someone calls $interp->_method(...) then it is considered as faster
1258
# version of method, similar to calling $interp->method(...) but via
1259
# 'invoke' instead of 'call', thus faster
1260
my $fast = '';
1261
$method =~ s/^_// and do {
1262
$fast='_';
1263
if (exists $::Tcl::pTk::{$method}) {
1264
no strict 'refs';
1265
*{"::Tcl::pTk::_$method"} = *{"::Tcl::pTk::$method"};
1266
return $int->$method(@_);
1267
}
1268
};
1269
1270
# search for right corresponding Tcl/Tk method, and create it afterwards
1271
# (so no consequent AUTOLOAD will happen)
1272
1273
# Check to see if it is a camelCase method. If so, split it apart.
1274
# code below will always create subroutine that calls a method.
1275
# This could be changed to create only known methods and generate error
1276
# if method is, for example, misspelled.
1277
# so following check will be like
1278
# if (exists $knows_method_names{$method}) {...}
1279
my $sub;
1280
if ($method =~ /^([a-z]+)([A-Z][a-z]+)$/) {
1281
my ($meth, $submeth) = ($1, lcfirst($2));
1282
# break into $method $submethod and call
1283
$sub = $fast ? sub {
1284
my $int = shift;
1285
$int->invoke($meth, $submeth, @_);
1286
} : sub {
1287
my $int = shift;
1288
$int->call($meth, $submeth, @_);
1289
};
1290
}
1291
else {
1292
# Default case, call as method of $int
1293
$sub = $fast ? sub {
1294
my $int = shift;
1295
$int->invoke($method, @_);
1296
} : sub {
1297
my $int = shift;
1298
$int->call($method, @_);
1299
};
1300
}
1301
no strict 'refs';
1302
*{"$package$fast$method0"} = $sub;
1303
Sub::Name::subname("$package$fast$method0", $sub) if( $Tcl::pTk::DEBUG);
1304
return $sub->($int,@_);
1305
}
1306
1307
# Sub to support the "Ev('x'), Ev('y'), etc" syntax that perltk uses to supply event information
1308
# to bind callbacks. This sub-name is exported with the other perltk subs (like MainLoop, etc).
1309
sub Ev {
1310
my @events = @_;
1311
return bless \@events, "Tcl::pTk::Ev";
1312
}
1313
1314
# Tcl::pTk::break, used to break out of event bindings (i.e. don't process anymore bind subs after break is called).
1315
# This is handled by the wrapper tcl code setup in Tcl::pTk::bind
1316
sub break
1317
{
1318
# Check to see if we are being called from Tcl::pTk::Callback, if so, then this is a valid 'break' call
1319
# and we will die with _TK_BREAK_
1320
my @callInfo;
1321
my $index = 0;
1322
my $callback; # Flag = 1 if this is a callback
1323
while (@callInfo = caller($index)){
1324
#print STDERR "Break Caller = ".join(", ", @callInfo)."\n";
1325
if( $callInfo[3] eq 'Tcl::pTk::Callback::BindCall'){
1326
$callback = 1;
1327
}
1328
$index++;
1329
}
1330
1331
die "_TK_BREAK_\n" if($callback);
1332
1333
}
1334
1335
# Wrappers for the Event Flag subs in Tcl (for compatiblity with perl/tk code
1336
sub DONT_WAIT{ Tcl::DONT_WAIT()};
1337
sub WINDOW_EVENTS{ Tcl::WINDOW_EVENTS()};
1338
sub FILE_EVENTS{ Tcl::FILE_EVENTS()};
1339
sub TIMER_EVENTS{ Tcl::TIMER_EVENTS()};
1340
sub IDLE_EVENTS{ Tcl::IDLE_EVENTS()};
1341
sub ALL_EVENTS{ Tcl::ALL_EVENTS()};
1342
1343
# Wrappers for the Tk color functions (for compatibility with perl/tk
1344
sub NORMAL_BG{
1345
if($^O eq 'cygwin' || $^O =~ /win32/ ){
1346
return 'systembuttonface';
1347
}
1348
elsif( $^O =~ /darwin/i ){ # MacOS
1349
return 'systemWindowBody';
1350
}
1351
else{ # Must be unix
1352
return '#d9d9d9';
1353
}
1354
}
1355
1356
sub ACTIVE_BG{
1357
if($^O eq 'cygwin' || $^O =~ /win32/ ){
1358
return 'systembuttonface';
1359
}
1360
elsif( $^O =~ /darwin/i ){ # MacOS
1361
return 'systemButtonFacePressed';
1362
}
1363
else{ # Must be unix
1364
return '#ececec';
1365
}
1366
}
1367
1368
sub SELECT_BG{
1369
if($^O eq 'cygwin' || $^O =~ /win32/ ){
1370
return 'SystemHighlight';
1371
}
1372
elsif( $^O =~ /darwin/i ){ # MacOS
1373
return 'systemHighlightSecondary';
1374
}
1375
else{ # Must be unix
1376
return '#c3c3c3';
1377
}
1378
}
1379
1380
# Background error routine that calls Tcl::pTk::Error, similar to perltk calling Tk::Error
1381
# Upon Tcl interp creation, this routine is created in Tcl (called the special name bgerror) so that this Tcl::pTk:;bgerror
1382
# will be called for background errors
1383
sub bgerror{
1384
my ($what,$obj, $sub, $message) = @_;
1385
1386
# Note: what is undefined, $obj is the current interp, sub is the name of the Tcl error handler (e.g. bgerror)
1387
#
1388
#print "what = $what, obj = $obj, sub = $sub, message = $message\n";
1389
# Variables for creating a "sanitized" stack trace
1390
# (i.e. stack trace that won't include a lot of Tcl::pTk internal info)
1391
1392
1393
my $mw; # Mainwindow of the current interpreter
1394
$mw = $obj->mainwindow if( ref( $obj ));
1395
1396
1397
my ($stackMessage, $shortLocation, $errorInfo);
1398
local $Carp::Internal{'Tcl::pTk::Callback'} = 1;
1399
local $Carp::Internal{'Tcl::pTk::Widget'} = 1;
1400
local $Carp::Internal{'Tcl'} = 1;
1401
$stackMessage = Carp::longmess();
1402
$shortLocation = Carp::shortmess();
1403
$errorInfo = $obj->Eval('set ::errorInfo');
1404
1405
# For compatibility with perl/tk, build the error message and stack info as an array
1406
my @stack = ("Stack Trace:", split(/\n/, $stackMessage) );
1407
my $errorMess = $errorInfo . "\n\n Error Started$shortLocation\n";
1408
$mw->Tcl::pTk::Error( $errorMess, @stack); # Call Tcl::pTk::Error like Tk::Error would get called
1409
}
1410
1411
1;
1412
1413
__END__