INSIGHT PLUG-INS HOW-TO
=======================

This text describes the technical aspects of adding a plug-in window
to Insight, the graphical front-end to the GNU debugger GDB.


1) INTRODUCTION

The plug-in facility allows for the addition of custom windows to
Insight.  These windows are not to become part of the Insight
distribution, but rather to be distributed separately.  They can be
downloaded from the authors web site, may accompany some development
board or embedded OS or come with anything else that can benefit from
a custom window being added to the standard Insight.  As the plug-ins
will be loaded into Insight/GDB for execution, the terms of the GPL
also apply to the plug-in code.  Also, Red Hat provides this facility
as-is and accepts no responsibility from its use.  Please refer to the
text of the GPL for more details.

The facilities described here provide support for custom
visualizations (custom windows for displaying information retrieved
from the target).  By writing a plug-in, it is possible to visualize
target specific data that is not shown in the standard Insight
windows.

The plug-in facility cannot be used to control target execution.  The
current implementation of Insight assumes that only the Source Window
issues commands related to target execution control.  There is no
mechanism to prevent one to call the commands that control execution,
but its use may result in inconsistent GUI states.  This restriction
may be lifted in future versions of Insight.

The facility works as follows: A "plugins" subdirectory is added under
the gdbtcl directory where Insight Tcl code is installed.  The custom
plug-in code will be installed in a subdirectory of this "plugins"
directory.  The plug-in window will be written as a [incr Tcl/Tk]
class which inherits from the provided PluginWindow class and
implements the methods necessary to display the desired custom
data. GDB will read plug-in files on start-up and add a menu item to
the PlugIn menu of the Insight Source Window.  When the menu item is
chosen, GDB instantiates the custom plug-in class.

The PluginWindow base class constructor creates a toplevel window (an
Insight ManagedWin) which contains a "childsite".  In this case, the
"childsite" is a frame in which the derived class (the custom plug-in)
can draw.  The PluginWindow class also provides facilities to add a
menu and a toolbar.  Among the methods provided by this class, the
"running" method is called every time the debugger starts the target
and the "stopped" method is called every time the target stops. In the
"stopped" method, information can be gathered from the target and
displayed.  The "running" method indicates that GDB is busy running
the target.  No activities should be initiated by any GUI component
while in this state (except for the STOP button in the Source Window).

The remainder of this document describes how to install a custom
plug-in and some details of the PluginWindow class.  Writing Tcl
Extensions (technically is what plug-ins are) is beyond the scope of
this document, but a simple example is given and some documentation
references are provided.

Please see the file CONTRIBUTE in this directory for some
administrative details before you start developing your plug-in.


2) HOW TO ADD A PLUG-IN WINDOW TO INSIGHT

Once you have your plug-in class ready, here is how to make it show up
in the Insight Source Window "PlugIn" menu.  You may perform these
steps manually, but if you are distributing your plug-in, it may be
convenient to provide with it an installation script that automate
this steps.

The examples in this section refer to the sample plug-in code provided
with the Insight sources, located in the
$(SOURCE)/gdb/gdbtk/library/plugins and
$(SOURCE)/gdb/gdbtk/library/plugins/rhabout directories.

Custom plug-ins are provided as "packages" (see [Welch 2000] and
[Smith 2000]).  The following setup will cause your plug-in package to
be loaded. 

i) First, locate the $(INSTALL)/share/gdbtcl directory.  This is the
directory which contains the Tcl/Tk code used by Insight.  Create a
"plugins" subdirectory if it does not exist yet (i.e., if your plug-in
is the first to be installed).  Now you must have a directory:
   $(INSTALL)/share/gdbtcl/plugins
in your installation tree.

ii) Create a subdirectory for your plug-in code (named in accordance to
the conventions set forth in the CONTRIBUTE file).  Add all your code
to that directory.  Make sure you have a tclIndex file or use
auto_mkindex to create it.  For instance, in the sample case we would
have:
   $(INSTALL)/share/gdbtcl/plugins/rhabout
and it would contain:
   rhabout.itcl  rhabout.so  tclIndex

iii) In the "plugins" directory create a file that will actually load your
plug-in package (named accordingly to the CONTRIBUTE conventions).  In
the provided sample, this file is "rhabout.tcl" and would contain the
following lines:

   package provide RHABOUT 1.0
   set dirname [file dirname [info script]]
   lappend auto_path [file join $dirname rhabout]
   load [file join $dirname rhabout rhabout.so] RHABOUT

The first line states what package the sample plug-in code is
providing.  Note that the subdirectory "rhabout" which contains the
sample plug-in is added to the auto_path in the third line and there
is a tclIndex file in that directory (that is how plug-in classes and
methods are found).

The last line is only necessary if your plug-in contains Tcl command
procedures written in C.  Loading Tcl libraries is described in [Welch
2000] and the [incr Tcl/Tk] bits can be found in [Smith 2000].  It is
recommended that the reader also refer to the "load" Tcl man page if
these dynamic libraries are to be loaded.

iv) In the "plugins" directory, add an entry to the pkgIndex.tcl file,
if it exists, with a "package ifneeded" command to source the file
created in step (iii).  If the file does not exist, create it.  For
the sample plug-in, this entry is:

   package ifneeded RHABOUT 1.0 [list source [file join $dir rhabout.tcl]]

This roughly corresponds to what would be created by a pkg_mkIndex
command with the "-direct" option.

If you are writing a install script, make sure to append to this file,
not overwrite it.  If there are other plug-ins already installed you
don't want to remove their "package ifneeded" commands (e.g., use ">>"
in a c-shell script).  Be considerate.

v) Create the file "plugins.tcl" in the "plugins" directory if it does
not yet exist.  Again, this is a file shared by all plug-ins so make
sure your install script does not overwrite, but append to it.

This is a Tcl code fragment that will be sourced by the Insight Source
Window constructor to add menu entries to the "PlugIn" menu that will
instantiate the plug-in classes.  If there is any error in this few
lines of code Insight will not start and a Tcl stack trace will be
shown.  So test it in your build directory before installing in a
system shared by others.

For the sample plug-in, this lines would be:

   # Add your window to the PlugIn menu here
   # Don't forget to add your packet as well

   if {1} {  #test here if your target is configured
     #package require LIBGDB 1.0
     package require RHABOUT 1.0
     $Menu add command Other "About Red Hat" \
       {ManagedWin::open RHAbout} \
       -underline 0
     set plugins_available 1
   }

You can ignore the LIBGDB "package require" command for now.  LIBGDB
is under construction and not yet available.  But do not forget to
add a "package require" command for your plug-in package.  Otherwise,
when someone choses your plug-in menu entry a stack trace will be
produced.

The Tcl command starting with "$Menu" is similar to the ones provided
by the "menubar" component of the PluginWindow class (described later
in this document), but all one needs to do is to copy the above
replacing the menu entry text "About Red Hat", the plug-in class name
"RHAbout" and the underline index with the appropriate values.

The "set plugins_available 1" command is important.  If the variable
"plugins_available" is not set to 1 by any of the plug-in code
fragments, the Source Window will not have a "PlugIn" menu.

This brings us to the "if" statement in the first line.  The sample
plug-in is generic, it works with any target.  However, a custom
plug-in may be written for a specific target and be of no generic
use. Furthermore, a target specific plug-in may not even work with
other host and target configurations different from the one it was
designed for.

The Tcl code used by Insight is shared by all configurations (thus the
subdirectory name "shared") and adding a plug-in in the wrong
configuration could render Insight unusable.  To avoid this, a test
for the right configuration must be made so that the plug-in menu
entry is only added in the configurations that support it (the
"package require" must also be protected).

Insight has a global variable which contains configuration
information. The array "GDBStartup" has the elements:
   host_name     - host configuration triplet
   target_name   - target configuration triplet 

Use these values, $GDBStartup(host_name) and $GDBStartup(target_name),
to verify that your plug-in code is supported.  Don't forget to add
"global GDBStartup" before you refer to this array.

For instance, if the sample code could only be used with Linux hosts,
the sample code above would look like this:

   # Add your window to the PlugIn menu here
   # Don't forget to add your packet as well

   global GDBStartup
   if {[string first "linux" $GDBStartup(host_name)] != -1} {
     #package require LIBGDB 1.0
     package require RHABOUT 1.0
     $Menu add command Other "About Red Hat" \
       {ManagedWin::open RHAbout} \
       -underline 0
     set plugins_available 1
   }


3) DEVELOPING AN INSIGHT PLUG-IN

Only itcl based windows will work.  They must also be derived (i.e.,
inherit) from the PluginWindow class described in the next section.
You must also follow the name conventions described in the CONTRIBUTE
file to avoid class name clashes.

The PluginWindow base class has facilities for adding a menu and a
toolbar.  It already provides the code to deactivate buttons and menu
entries when GDB is busy (running the target) and reactivate them when
the target stops.  Your job usually consists of calling a method to
redraw your window with updated information when the target stops.
You can do this simply by adding a call to this method inside the
"stopped" method provided.

The Insight Tcl source file gdb/gdbtk/library/interface.tcl and the C
file gdb/gdbtk/generic/gdbtk-cmds.c contain a (quite volatile) set of
Tcl commands that can be used to retrieve information from and about
the target.  Examples of the use of such commands exist all around the
Insight source code and details are usually given near the procedure
or function definitions.  Please refrain from using commands that
control the target execution or change the GDB state in any way, they
are reserved for use by the Source Window only.  Remember, plug-ins are
a visualization facility only.

A special remark is necessary about the gdb_cmd and gdb_immediate
commands.  These are deprecated and will disappear (stop working) soon.
The GDB maintainers have asked the Insight maintainers to stop using
the hooks in GDB code that make them possible.  Conversion is already
under way.  You can use them for prototyping (for now), but be
prepared to write Tcl command procedures instead of parsing console text
output.  

If you need to issue target-dependent commands to retrieve information
from your target (that cannot be retrieved with the standard register
and memory access operations), you can write Tcl command procedures
and add them to your target dependent file enclosed in 
   #ifdef GDBTK
   #endif
The target dependent Tcl code will move to a subdirectory of gdbtk in
the future, but for now, just add it to your existent target-dependent
file.

If you must access gdb functions that are not yet available in
gdbtk-cmds.c (or in any of the spun-offs that will soon exist in the
gdb/gdbtk/generic directory), consider writing to the Insight
maintainers.  They will be able to tell you what command should be
implemented and, if they have the time, add it to Insight.  As they
may be busy, consider offering to write the code yourself and
submitting it for approval (see CONTRIBUTE).  You can see how these
Tcl command procedures in C are written by looking at what it is done
in the gdbtk-cmds.c file and others in the gdb/gdbtk/generic
subdirectory.  Again, you can use the gdb_cmd and gdb_immediate
commands to invoke a GDB command line interface command, but they will
not be available for long.

Please refer to the sample source code located in the files:
  gdb/gdbtk/library/plugins/rhabout/rhabout.itcl
  gdb/gdbtk/library/plugins/rhabout/rhabout.c 

The comments in these files provide a basic framework for a Insight
plug-in.


4) THE "PluginWindow" BASE CLASS

The PluginWindow base class provides the following methods:

childsite  -  returns the path of the frame component that can be used
by the plug-in code to pack its custom display components.

stopped  -  called when the target stops.  It should be overloaded and
call the plug-in procedure that updates the display.  The child
version must call the base class method implementation if it wants
menu items and/or buttons to be automatically controlled.

running  -  called when GDB becomes busy by running the target.  No
commands shall be issued by a plug-in while GDB is busy.  The child
version must call the base class method implementation if it wants
menu items and/or buttons to be automatically controlled.

no_inferior  -  called when GDB disconnects from the target.  The
plug-in may want to forget some context information in this case,
depending on the specifics of its implementation.  The child
version must call the base class method implementation if it wants
menu items and/or buttons to be automatically controlled.


The PluginWindow base class contains two components which can be
optionally used:

menubar  -  allows a menu to be added to the plug-in window.  This
facility is implemented by the GDBMenuBar class (gdbmenubar.itcl).

toolbar  -  allows a toolbar to be added to the plug-in window.  This
facility is implemented by the GDBToolBar class (gdbtoolbar.itcl).


Both buttons and menu entries have "class" attributes.  Button classes
and Menu entry classes are specified when they are created and are
used for the automatic control of button and menu entry states.
If the class is specified as "None", the menu entry or button will
remain always active.  The classes "Control" and "Other" follow the
following convention:

   Control    Other     State
     off       off      gdb is busy
     on        on       gdb has inferior, and is idle
     off       on       gdb has no inferior, and is idle


The "menubutton" component offers the following supported commands:

add menubutton  - add a menu button to the window menu bar.
add command     - add an entry to the last menu created.
add separator   - add a separator to the last menu created.
show            - attach the created menu to the window.

If the show command is not issued, the plug-in window will have no
menu bar.  There are other methods and commands defined in the
GDBMenuBar class.  They are for Insight internal use only and should
not be used by plug-in windows.

A menu named "help" will automatically be aligned to the right.

The sample plug-in code creates a simple menu with the following commands:

    $menubar add menubutton file "File" 0
    $menubar add command None "Close" \
      [code $this destroy_toplevel] \
      -underline 1
    $menubar add menubutton help "Help" 0
    $menubar add command Other "Help Topics" \
      {HtmlViewer::open_help index.html} \
      -underline 0
    $menubar add separator
    $menubar add command Other "About GDB..." \
      {ManagedWin::open About -transient} \
      -underline 0

    # The menu only shows up if you do this:
    $menubar show


The "toolbar" component offers the following supported commands:

add button      - add a button to the window tool bar.
add label       - add an label widget to the tool bar.
add separator   - add a separator to the tool bar.
itemconfigure   - configure a tool bar element.
show            - make the toolbar visible.

If the show command is not issued, the plug-in window will have no
tool bar.  There are other methods and commands defined in the
GDBToolBar class.  They are for Insight internal use only and should
not be used by plug-in windows.

Use the "itemconfigure" command to fill the label elements with the
current data as necessary.

The sample plug-in code creates a single button with the following commands:

    $toolbar add button con Other {ManagedWin::open Console} \
                           "Console (Ctrl+N)" -image console_img

    # The toolbar will only show up if you do this:
    $toolbar show


The complete Tcl code of the sample plug-in can be found in the file
   gdb/gdbtk/library/plugins/rhabout/rhabout.itcl
and the PluginWindow class definition and implementation is in the file
   gdb/gdbtk/library/pluginwin.itcl

Please refer to the files
   gdb/gdbtk/library/gdbmenubar.itcl
and
   gdb/gdbtk/library/gdbtoolbar.itcl
for the current arguments accepted by the menubar and toolbar commands
respectively.


REFERENCES

[Smith 2000] Chad Smith, "[incr Tcl/Tk] from the Ground Up".
Chapters 9 and 10.  Osborne/McGraw-Hill, 2000. 

[Welch 2000] Brent B. Welch, "Practical Programming in Tcl and Tk",
3/e.  Chapters 12, 14, 44, 45, 46 and 47.  Prentice Hall PTR, 2000.
