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