NAME¶
CallingTk - what is Perl Tk interface doing when you call Tk functions.
This information is worse than useless for "perlTk" users, but can of
some help for people interested in using modified Tk source with
"perlTk".
This document is under construction. The information is believed to be pertinent
to the version of "portableTk" available when it was created. All
the details are subject to change.
DESCRIPTION¶
- PreCompiling
- Before the actual compilation stage a script scans the
source and extracts the subcommands of different commands. This
information resides in the file "pTk/Methods.def".
- Compilation
- During compilation the above file is included in the source
of booting routine of dynamic (or static) library. More precisely, the
booting code of module "Tk" calls the subroutine
Boot_Glue() from the module "tkGlue.c", and this
subroutine includes the file (with appropriate macro definitions).
- Inside "use Tk;"
- The module bootstraps the C code, then loads the Perl
libraries. The heart of the Perl code is contained in the
"Tk::Widget" library, all the widgets inherit from this module.
Code for toplevels is loaded from "Tk::MainWindow".
During bootstrap of the C glue code the "Xevent::?" codes and a
handful of "Tk::Widget" and "Tk::Image" routines are
defined. (Much more XSUBs are created from "Tk.xs" code.) The
widget subcommands are glued to Perl basing on the list included from
"pTk/Methods.def". In fact all the subcommands are glued to
XSUBs that are related to the same C subroutine XStoWidget(), but
have different data parts.
During the Perl code bootstrap the method "Tk::Widget::import" is
called. This call requires all the code from particular widget packages.
Code from the widget packages calls an obscure command like
(bless \"Text")->WidgetClass;
This command (actually Tk::Widget::WidgetClass()) creates three
routines: Tk::Widget::Text(), Tk::Widget::isText(), and
Tk::Text::isText(). The first one is basically "new" of
"Tk::Text", the other two return constants. It also puts the
class into depository.
- Inside "$top = MainWindow->new;"
- This is quite intuitive. This call goes direct to
"Tk::MainWindow::new", that calls XSUB
"Tk::MainWindow::CreateMainWindow", that calls C subroutine
Tk_CreateMainWindow(). It is a "Tk" subroutine, so here
black magic ends (almost).
The only remaining black magic is that the "Tk" initialization
routine creates a lot of commands, but the subroutine for creation is
usurped by portableTk and the commands are created in the package
"Tk". They are associated to XSUBs that are related to one of
three C subroutines XStoSubCmd(), XStoBind(), or
XStoTk(), but have different data parts.
The result of the call is blessed into "Tk::MainWindow", as it
should.
- Inside "$top->title('Text demo');"
- The package "Tk::Toplevel" defines a lot of
subroutines on the fly on some list. All the commands from the list are
converted to the corresponding subcommands of "wm" method of the
widget. Here subcommand is a command with some particular second argument
(in this case "title"). Recall that the first argument is $self.
Now "Tk::Toplevel" @ISA "Tk::Widget", that in turn @ISA
"Tk". So a call to "$top->wm('title','Text demo')"
calls "Tk::wm", that is defined during call to
Tk_CreateMainWindow(). As it is described above, the XSUB
associated to XStoSubCmd() is called.
This C routine is defined in "tkGlue.c". It gets the data part of
XSUB, creates a "SV" with the name of the command, and calls
Call_Tk() with the XSUB data as the first argument, and with the
name of XSUB stuffed into the Perl stack in the place there "tk"
expects it. (In fact it can also reorder the arguments if it thinks it is
what you want).
The latter procedure extracts name of "tk" procedure and
"clientData" from the first argument and makes a call, using
Perl stack as "argv" for the procedure. A lot of black magic is
performed afterwards to convert result of the procedure to a Perl array
return.
- Inside "$text = $top->Text(background =>
$txtBg);"
- Above we discussed how the command
"Tk::Widget::Text" is created. The above command calls it via
inheritance. It is translated to
Tk::Text::new($top, background => $txtBg);
The package "Tk::Text" has no method "new", so the
"Tk::Widget::new" is called. In turn it calls
"Tk::Text->DoInit($top)", that is
"Tk::Widget::DoInit(Tk::Text,$top)", that initializes the
bindings if necessary. Then it creates the name for the widget of the form
".text0", and calls "Tk::text('.text0', background =>
$txtBg)" (note lowercase). The result of the call is blessed into
"Tk::Text", and the method "bindtags" for this object
is called.
Now the only thing to discuss is who defines the methods "text"
and "bindtags". The answer is that they are defined in
"tkWindow.c", and these commands are created in the package
"Tk" in the same sweep that created the command
"Tk::wm" discussed above.
So the the same C code that corresponds to the processing of corresponding
TCL commands is called here as well (this time via "XStoTk"
interface).
- Inside "$text->insert('insert','Hello,
world!');"
- As we discussed above, the subcommands of widget procedures
correspond to XSUB "XStoWidget". This XSUB substitutes the first
argument $text (that is a hash reference) to an appropriate value from
this hash, adds the additional argument after the first one that contains
the name of the subcommand extracted from the data part of XSUB, and calls
the corresponding Tk C subroutine via "Call_Tk".
Ilya Zakharevich <ilya@math.ohio-state.edu>