
             EUROBRIDGE WIDGET SET PRINTING SUPPORT (VERSION 4.0)
                                       
    1. Introduction
    2. Application interface
         1. Xew Printing Interface
              1. XePrint
              2. XePrinter structure
              3. XeImaging structure
              4. XePrintPageProc callback
              5. XePrintCancel, XePrintPause, XePrintResume
         2. X Print Server interface (Reynolds version)
              1. XOpenPrintWindow
              2. XClosePrintWindow
              3. XSetPrintParams
              4. Implementation limitations
         3. Xprinter interface (Bristol Inc.)
    3. Limitations and problems of the current implementation
         1. Window clipping problem
         2. MOTIF ResizeWrapper
         3. Only one print at time
         4. Foreign Composite widgets
    4. Implementation details
         1. Printing methods
              1. Print initialize method
              2. Print method
              3. Print Constraint initialize method
              4. Print Constraint destroy method
              5. Print cancel method
              6. Print destroy method
    5. Conclusions
       
   
     _________________________________________________________________
   
                                INTRODUCTION
                                       
   
   
   Currently X Window system does not give application any guidance about
   how to implement printing. Each application has been forced to invent
   their own private solutions.
   
   One possible solution to the printing problem might start from the
   following idea:
     * because application already is produding a image using X protocol,
       it might be possible to use the same code and/or protocol to
       produce the printout.
       
   
   
   One solution is to have an X Print Server which looks like ordinary X
   server to the application. Rumours have it that X Consortium is
   planning along these lines, and there also exists an independent
   prototype of X Print server impelementation (posted to the net by
   Matthew Reynolds ).
   
   Even though the principle is simple, application need to be aware of
   the printing, and has to provide a lot of "wrapper structure" to
   really get printing streamlined. The "idea" provides a basic frame
   work, but does only half of the job.
   
   The printing support in Xew is an experimental implementation and a
   study how a printing based on the Xlib/X Protocol could work in Xt
   framework.
   
   About the only assumption Xew makes about the printing support is that
   the printing occurs using standard Xlib calls and there exists
   something that looks like a Display structure for the printer. Thus,
   the Xew itself should not need (source) changes for different X
   Printing solutions. However, different X printing solutions need
   different setups in the application code. Currently, the following
   Xlib calls are used by the printing and must be supported by the
   printing solution:
     * all drawing primitives (XDraw...)
     * graphic context handling (XCreateGC, XChangeGC, XFreeGC and all GC
       related convenience functions)
     * color management (XCreateColormap, XFreeColormap, XQueryColors,
       XAllocColor, XFreeColors)
     * font management (XListFonts, XLoadQueryFont, XGetFontProperty and
       XInternAtom)
     * image operations (XPutImage)
       
   
   
   For a complete printing and display integration, the system should
   have three different "operating modes". The current Xew printing
   supports only the first one:
    1. display is generated using display metrics, printout is
       independently generated using printer metrics and capabilities.
    2. display is generated using display metrics, printout simulates the
       display ("screen dump" or WYSIWYG mode),
    3. display simulates the printout, printout is generated using full
       printer metrics and capabilities.
       
   
   
   In Xew the printing is based on Widget. After setting up the Print
   Server connection, any widget within application can be printed out
   with single function call (XePrint). For any non-Xew widget, printing
   tries to print a screen dump of the widget. But, Xew widgets are
   "printing aware":
     * XeText,XeTextEd perform a total relayout using the fonts and
       metrics provided by the print server, and generate the text
       directly to the print server. This is not a screen dump, and means
       that even almost unreadable text on the display is readable on the
       printout. While printing is in progress, expose events to the
       original XeText widget content and editing in XeTextEd are
       disabled (actually, while printing, the content of the original
       XeText is empty!.
     * XeRaster, XeVideo generate the print image from the current source
       data (in case of video, this is the current frame being shown).
     * XeFrame performs a geometry layout using the "printer changed"
       versions of the child widgets. This means that if the child
       geometries were changed due to printer requirements, the XeFrame
       will adjust to them.
       
   
   
   When XePrint is given a widget to print, it will first relayout the
   widget and all its descendants for the printer in depth first order.
   After this, the toplevel widget is tiled into pages, and each page is
   printed separately by the printing process. A single widget, such as
   large image, may extend over several pages.
   
   The XeText(Ed) widget as toplevel widget behaves specially: if the
   layout width or height (XtNcolumnWidth, XtNcolumnHeight) are not
   fixed, the layout will use the tiling (page) dimensions for this
   purpose, and the resulting new size of the TextEd widget is tiled
   (instead of the screen version).
   
                            APPLICATION INTERFACE
                                       
   
   
   The application interface divides into sections:
     * Xew Printing interface (same for each printing support)
     * X Printing setup for the chosen printing support (one for each
       kind)
       
Xew Printing interface

   
   
   To use Xew printing in the application, the following steps are
   needed:
    1. Define the XePrinter structure and initialize it with the printer
       connection (Display pointer). Once opened, the same structure can
       be used with multiple printings.
    2. To print a widget, decide how it should print and set the
       controlling fields in the XePrinter structure appropriately. The
       fields can be left to ZERO values for defaults, with exception of
       page_width and page_height. These two values define how the widget
       is to be tiled into pages.
    3. call XePrint with appropriate parameters and callback function
       that will arrange for page changes in a printer implementation
       specific way.
       
   
     _________________________________________________________________
   
  XePrintProcess XePrint(Widget, XePrinter *, XePrintPageProc, XtPointer)
  
   Widget w
          is the widget to be printed (including all children).
          
   XePrinter *p
          is a pointer to a control structure which specifies where and
          how the printing should occur.
          
   XePrintPageProc callback
          is a callback function which is called once before every new
          page (page > 0), and once after all output to the last page has
          been produced (page == 0).
          
   XtPointer client_data
          is the application data passed to the callback, whenever it is
          called.
          
   
   
   XePrint prints the content of the Widget (including all children)
   using the printing parameters given in the XePrinter structure.
   
   XePrint returns NULL, if all printing completed within this call, and
   a NON-ZERO opaque printing state pointer, if the printing process is
   still in progress. The only way to detect the completion of the
   printing process in such case, is to have the XePrintPageProc defined
   and watch for page==0 call.
   
   Warning!
          An application should take care not to start more than one
          printing for a widget. The Xew is not currently prepared to do
          multiple simultaneous printouts from the same widget.
          
   Note!
          The current printing implementation always completes within
          single XePrint call, unless the application chooses to use the
          XePrintPause in the page callback function.
          
   
     _________________________________________________________________
   
  XePrinter structure

typedef struct XePrinter
    {
        Display *printer;       /* Printer connection */
        Drawable page;          /* Printer page */
        int page_width;         /* Tiling into pages, width of the tile */
        int page_height;        /* Tiling into pages, height of the tile */
        Boolean background;     /* Use widget background */
        XeImaging imaging;
    } XePrinter;

   Display *printer
          is the Display pointer identifying the target printer.
          
   Drawable page
          is a Drawable that will be used in all Xlib functions that
          require a drawable. Whether this is needed or not, depends on
          the printer implementation.
          
   int page_width, page_height
          define the tiling of the widget being printed (using screen/src
          units, pixels). Each tile printed as a separate page.
          If the top level widget being printed is an XeText, and if
          columnWidth or columnHeight resource is undefined (has value
          0), then the XeText will temporarily substitute page_width and
          page_height for the corresponding resource value, before doing
          the layout for the printer.
          
   Boolean background
          if set 'True', the background is printed. When 'False', the
          widget background color is set to 'white' and 'foreground' (in
          Xew) is black (this is most useful for XeText widget, if the
          application is using white text on dark background, which is
          not so readable combination on a printed page).
          
   XeImaging imaging
          are printer imaging controls (this mostly intended to be used
          if you want to "downgrade" the features). For defaults,
          initialize to all ZERO is sufficient.
          
   
     _________________________________________________________________
   
  XeImaging structure
  
   
   
   This structure is defined in <X11/Xew/Basic.h> as

typedef struct
    {
        Boolean use_shm;
        XeColormapUse colormap_use;
        XeColorMode color_mode;
        XeDither dither;
        XeColorQuantize color_quantize;
        int max_colors;
    } XeImaging;

   and the use of this is not yet fully stabilized in the printing
   context. Currently some of the fields can be used to change the
   printing behaviour. Mostly, the fields have the same specification and
   effect as the corresponding XeBasic resources and most effects, if
   any, are to the printing of XeRaster or XeVideo widgets.
   
   Boolean use_shm
          will instruct the printing to utilize MIT shared memory option
          for images with the X printer. Do not set this, as none of the
          current X printing implementations support this!
          
   XeColormapUse colormap_use
          the possible values are
          
          + XeColormapUse_SHARED (default)
          + XeColormapUse_SHAREDOWN
          + XeColormapUse_OPTIONAL
          + XeColormapUse_PRIVATE
            
   It is somewhat questionable what use this will have on the printer.
          Not significant, if the print server is in TrueColor mode.
          
   XeColorMode color_mode
          the possible values are
          
          + XeColorMode_NONE, use same mode as specified for the widget
            (default)
          + XeColorMode_MONO, convert all images to black and white
            (bitmaps), before sending them to the printer,
          + XeColorMode_GRAY, convert all color images to grayscale,
            before sending to the printer,
          + XeColorMode_COLOR, use colors on printer (basicly, send
            images as they are to the printer, colors included).
            
   XeDither dither
          the possible values are
          
          + XeDither_NONE
          + XeDither_FS4
            
   and the effect, if any, depends on source image (for example,
          currently the dither parameter has no effect on palette
          images).
          
   XeColorQuantize color_quantize
          the possible values are
          
          + XeColorQuantize_FAST (default)
          + XeColorQuantize_HECKBERT
          + XeColorQuantize_PPMQUANT
            
   This has any effect only if the source image is TrueColor and printer
          shows as PseudoColor. Leave it to the default (0).
          
   int max_colors
          if > 0, defines the maximum number of colors to be used in any
          single image print. Perhaps useful for fancy effects with
          "PseudoColor" printers. Has no effect, if the printer is
          TrueColor. The default (0) makes printing to use the number of
          colors specified for the widget being printed.
          
   
     _________________________________________________________________
   
  void (*XePrintPageProc)(Widget, XePrintProcess, int, XtPointer)
  
   Widget w
          is the original Widget passed to the XePrint function
          
   XePrintProcess pp
          is an opaque data which identifies the internal printing state.
          This is used, if the callback needs to do some special control
          actions to the printing process using the other interface
          functions described later. When the callback is called by the
          XePrint (or by the printing process it started), this parameter
          is always NON-NULL.
          
   int page
          identifies the current page being printed (if > 0), and the
          final call after the last page, if == 0. Negative values of
          page are reserved for future use.
          
   XtPointer client_data
          is the client_data passed to the XePrint function.
          
   
   
   XePrintPageProc callback is called once before every new page (page >
   0), and once after all output to the last page hase been produced
   (page == 0).
   
   The task of this callback is to close printing of the previous page
   (page > 1) and prepare for a printing of a new/next page on the
   printer (page > 0). The exact code depends on the X Printing support
   being used.
   
   The negative values of page are reserved for future use, currently the
   callback should just return without doing anything for such cases. The
   negative values might be callbacks that would occur while printing a
   page, and would give the application more control over what and how
   the printing happens, perhaps allow changing of printing parameters
   depending on which child widget is being printed.
   
   Warning!
          When the callback is called with page==0, the XePrintProcess
          pointer should not be used for any further control calls. If
          the XePrint function returned with non-NULL value that got
          stored into some application structure, this callback must
          ensure that this value is not used anymore.
          
   
     _________________________________________________________________
   
  void XePrintCancel(XePrintProcess)
  void XePrintPause(XePrintProcess)
  void XePrintResume(XePrintProcess)
  
   XePrintProcess pp
          is the opaque printing process identification, either returned
          by the XePrint function, or the parameter of the
          XePrintPageProc.
          
   
   
   XePrintCancel, XePrintPause and XePrintResume are all control
   functions that can be used from the XePrintPageProc, or from the
   application (provided that XePrint returned NON-NULL and
   XePrintPageProc has not yet been called with page=0)
   
   XePrintCancel aborts the printing process as soon as possible. If the
   XePrintPageProc has not yet been called with the page=0 parameter, the
   callback occurs when the termination is completed.
   
   XePrintPause suspends the printing process.
   
   XePrintResume resumes the printing process suspended by XePrintPause
   
X Print Server interface (Reynolds version)

   
   
   Matthew Reynolds implementation of the X Print Server comes with a
   small interface library, which implements the following functions:
     * XSetPrintParams
     * XOpenPrintWindow
     * XClosePrintWindow
       
   In addition to these, the normal Xlib call
     * XOpenDisplay
       
   is used in opening the printer connection. The following documentation
   applies to the print server code specially modified for the Xew. About
   the simplest printing skeleton (without any error processing),
   assuming Matthew Reynolds X print server modified for Xew, would look
   something like
     _________________________________________________________________
   

#include <X11/Xew/Print.h>
#include "printlib.h"
static void PrintingPage
        (Widget w, XePrintProcess pp, int page, XtPointer data)
    {
        XePrinter *p = (XePrinter *)data;
        char page_file[80];
                if (page < 0)
                return;
        if (page != 1)
            {
                XClosePrintWindow(p->printer, p->page);
                XFlush(p->printer);
            }
        if (page > 0)
            {
                sprintf(page_file, "page-%d.ps", page);
                XOpenPrintWindow(p->printer, p->page, page_file);
            }
    }
void PrintWidget(Widget w)
    {
        static XePrinter p;

        p.page_height = 600; /* Tile into A4 size assuming 75dpi */
        p.page_width = 840;
        if (!p.printer)
            {
                p.printer = XOpenDisplay(getenv("PRINTSERVER"));
                p.page = DefaultRootWindow (p.printer);
            }
        XSetPrintParams (p.printer, XpScale_MAXASPECT, 1, 1,
                         p.page_width, p.page_height,
                         0, 0, NULL);
        (void)XePrint(p, &p, PrintingPage, (XtPointer)&p);
    }

   
     _________________________________________________________________
   
  XOpenPrintWindow(Display *, Drawable, char *)
  
   Display *dpy
          is the printer "display".
          
   Drawable drawable
          Currently ignored.
          
   char *printfile
          is the name of the output file (printDirect = 0), or the name
          of the printer device (printDirect != 0).
          
   
   
   Start printing a new postscript output file. Creates the file or
   starts piping to the lpr command.
   
   Note on printfile!
          This definition of XOpenPrintWindow is rather problematic if
          the X printserver will be used as a shared server between
          multiple users. First, unless the server is run as 'root', it
          may not be able to create these files. Second, user may not be
          able to read the created files (as they will be owned by the
          server). Third, allowing any random filename to be specified by
          the client is a serious security hole. For this reason the
          modified for Xew print server mangles the filename as follows:
          
         1. only the last component of the path is used, if any given,
         2. allow only alphanumeric, '-', '.' or '_' in the name,
         3. strip all leading '.'s
         4. strip leading '-'s
            
   The specified file will be created the to directory from which the X
          print server is started. As specified, the X Print Server is
          only usable by single user at a time, each user needs to start
          own private copy of the print server.
          
   
     _________________________________________________________________
   
  XClosePrintWindow(Display *, Drawable)
  
   Display *dpy
          is the printer "display".
          
   Drawable drawable
          Currently ignored.
          
   
   
   Finish printing and close the output stream opened by the
   XOpenPrintWindow.
   
   Note!
          This function should probably include an implicit XFlush(dpy).
          Currently it does not, and the application needs to do an
          explicit XFlush after the call to get the request forwarded to
          the server.
          
   
     _________________________________________________________________
   
  XSetPrintParams(Display *, Boolean, int, int, int, int, int, int, char *)
  
   Display *dpy
          is the printer "display".
          
   Boolean preserveAspect
          controls the fitting of the printed page (output page) to the
          physical printing area (bounding box) on the output. The value
          is actually an enumeration of 5 different possibilities:
          
          + XpScale_MAXASPECT, the output page is scaled to the bounding
            box and aspect ratio is preserved,
          + XpScale_FITAREA, the output page is exactly fit to the
            bounding box, changing the aspect ratio as needed,
          + XpScale_WIDTH, the output width is scaled to the width of the
            bounding box, and the height is computed so that the aspect
            ratio is preserved (possibly causing the output to extend
            outside the clipping box),
          + XpScale_HEIGHT, the output height is scaled to the height of
            the bounding box, and width is computed so that the aspect
            ratio is preserved (possibly causing the output to extend
            outside the clipping box),
          + XpScale_NONE, the current bounding box has no effect on the
            size (possibly causing the output page to get clipped both
            from right and bottom)
            
   int fontScale
          Ignored.
          
   int pixmapScale
          Ignored.
          
   int pageWidth, int PageHeight
          define the rectangle (output page) in pixels which will get
          fitted to the available printing area (bounding box) on the
          output paper using the method selected by the preserveAspect
          parameter.
          
   int printDirect
          defines whether the printfile in XOpenPrintWindow call is to be
          interpreted as a filename (ZERO) or as a printer name
          (NON-ZERO). If latter, then the ouput is piped to the Unix "lpr
          -P printfile" command.
          
   int landscape
          if NON-ZERO, the page rectangle (and printing output) is
          assumed to occur translated 90 degrees.
          
   char *correctFile
          if specified, gives the RGB correction values (see X Print
          Server README's for details).
          
   
   
   When the output file is printed as is on a PostScript printer, the
   bounding box is the printable area on the output paper. But, with
   care, it is also possible to include the output inside another
   PostScript stream, and bounding box can be some restricted smaller
   area within the page.
     _________________________________________________________________
   
  Implementation limitations
  
   
   
   The X Print Server code included in the Xew distribution is a modified
   version of the Matthew Reynolds original code (one version is
   available from ftp://ftp.x.org/contrib/extensions/ under name
   xpserv.*). The biggest functional change is the use Adobe Font Metrics
   (AFM) files for font metrics, instead of attempting to match the users
   display fonts to the printer. This fits well with Xew XeText, which
   already includes code that matches logical font attributes (weight,
   slant, size) to the fonts of the X server. Thus, having totally
   different font set does not hurt Xew.
   
   Note
          The AFM parser and support module only deals with 8 bit fonts.
          I would have added support for 16 bit fonts, if I had had any
          examples of such AFM files.
          
   
   
   In addition to the above major change, many other minor changes and
   fixes were necessary. Only the features, that were required and used
   by the Xew printing code, have been tested and fixed. Anything outside
   this functionality is totally unguaranteed.
   
   It would be best if the X Print server had the default visual set to
   TrueColor, but the support for this visual in the original code used
   as the base version, did not work properly. For this reason, the
   current Xew print server only has PseudoColor visual. This may cause
   images being produced with lesser color quality than would actually be
   necessary.
     _________________________________________________________________
   
Xprinter interface (Bristol Inc.)

   
   
   The detailed description of this interface is provided by the Bristol
   Inc. This here specifies just one example how to use the functions
   with the Xew printing.
   
   Currently the Xprinter support is not working order, as I have no way
   of testing it myself, and test reports say it does not work (due not
   being able to find a Visual structure for the printer).
   
   The most simple XePrintPageProc might be

#include <X11/Xew/Print.h>
static void PrintingPage(Widget w, XePrintProcess pp, int page, XtPointer data)
    {
        XePrinter *p = (XePrinter *)data;

        if (page < 0)
                return;
        else if (page > 0)
            {
                if (page != 1)
                        XpPageEject(p->printer);
            }
        else
            {
                XpEndPage(p->printer);
                XpEndDoc(p->printer);
                XpClosePrinter(p->printer);
                p->printer = NULL;
            }
    }

   And the matching setup to print a widget would be (without any error
   checks!)

void PrintWidget(Widget w)
    {
        static XePrinter p;

        XpPageInfo page_info;
        double scale;

        if (!p.printer)
            {
                p.printer = XpOpenPrinter();
                p.page = DefaultRootWindow(p.printer);
                XpMatch(XtDisplay(w), 0, p.printer);
            }
        XpStartDoc(p.printer, "EXAMPLE");
        XpStartPage(p.printer);
        XpQueryPageSize(p.printer, XpGetPageSize(p.printer), &page_info);
        scale = XpGetScale(p.printer);
        p.page_height = XpDisplayHeight(p.printer, DefaultScreen(p.printer));
        p.page_width = XpDisplayWidth(p.printer, DefaultScreen(p.printer));
        (void)XePrint(*wp, &p, PrintingPage, (XtPointer)&p);
    }

   
     _________________________________________________________________
   
X Consortium X Print server interface

   
   
   No information available.
   
           LIMITATIONS AND PROBLEMS OF THE CURRENT IMPLEMENTATION
                                       
Window clipping problem

   
   
   When printing widget hierarchies, the current implementation does not
   clip the child widget output by the parent window. If the child
   extends beyond the parent window, the printout may show these parts
   outside the parent, even if the screen display does not.
   
   The reason for this is, that it is uncertain who should do this job:
   the application or the print server? It relates to the issue how (or
   whether) the print server should support "window concept", and how the
   windows should work in printing context?
   
MOTIF ResizeWrapper

   
   
   When printing widget hiearchies, where some Xew widget is parent
   (usually XeFrame or XeText), the full geometry management is done for
   the printing. This implies calling the child resize methods.
   Unfortunately, if the Xew is compiled with USING_MOTIF_122, the resize
   methods are "wrapped" by Motif with something that requires "per
   display information" and cannot find it.
   
   The current workaround is that, with USING_MOTIF_122, the resize
   method is not called. The end result of this is, that in such case the
   geometry contraints specified for the children are not necessary in
   effect in the printed output.
   
   It might be possible to get rid of the "per display information"
   problem by using XtOpenDisplay instead of the XOpenDisplay for the
   printer connection, but this has not been tested.
   
Only one print at time

   
   
   Xew widget printing code is currently prepared to handle only one
   active print process per widget. The safeguards against multiple
   active printing processes for the same widget are rather weak.
   
   Application must not to start more than one printing process for the
   same widget. There is no limitation for simultanous printing of
   different widgets, as long as application can handle multiple
   asynchronous active printing processes.
   
   The printing solution may also allow only one printing at time (with
   the Xew modified X print server, you would need a separate printer
   connection, for simultaneous printing to work).
   
Foreign Composite widgets

   
   
   Foreign (non Xew) composite widgets are not printed.
   
   The only way to fully print unknown widgets is to take a screen dump
   out of them and then move this image to the printer. This is extremely
   heavy and wasteful operation, as composite widgets often have no
   special content to print, and are mostly covered by their child
   widgets. For this reason, the current implementation does not print
   such composites, only non-composite foreign widgets are printed.
   
   It might be sensible to add a flag to the XePrinter structure for
   controlling this option. Athena Tree widget is one example of a
   composite widget that does have useful information in the composite
   window itself, and where doing the screen dump routine would be
   desired.
   
                           IMPLEMENTATION DETAILS
                                       
   
   
   This section will describe how the printing actually works inside the
   Xew (and Xt). It must be said right from the beginning that this
   impelementation (architecture) may not be the right one. It does work,
   but at the same time, it is not as simple and easy to use from widget
   writers viewpoint, as I would have liked.
   
   The design goals were
     * produce quality output to the printer, not just "a screendump"
     * works with X server like Printer implementations
     * simple to use from the application,
       
   and already the first goal alone causes
     * quality output implies that at least the text should be laid out
       using printer metrics,
     * from this it follows, that all text widget geometries will be more
       or less different from the display version,
     * if such text widgets are embedded in composite widgets, printing
       should recompute the layouts for the composite widgets,
       
   and from the second
     * the display and the print server may have totally different
       capabilities (supported depths, fonts, visuals),
     * from this it follows, that the printing needs to translate colors,
       graphic contexts and fonts from the display to the printer for
       each widget being printed,
       
   and in general
     * if anything more than a screendump of the widget is wanted, the
       only one that knows how to create the printout is the widget
       itself,
     * thus, widgets need something that can be called to ask them to
       produce the printout of themselves,
     * as widget may extend across pages, the printing solution must be
       able to request rectangles from the widget in separate calls,
     * printing process may take long time, it should not block the
       normal Xt event loop while talking to the print server and
       application should be allowed to terminate the process at any
       point, at least between pages.
       
   
   
   To achieve the goals set, the following implementation strategy and
   printing architecture was chosen
     *
       
       the XeBasic widget class is enhanced with printing methods.
     *
       
       to have a place to store the printer modified resources, it was
       decided to make a copy of the each widget structure for the
       duration of the printing process. The cloned widget will have the
       core.screen pointing to the "printer screen" and core.window
       contains the "page window" on the printer.
     *
       
       the XePrint handles the building of the cloned widget tree,
       transforms the core fields directly and arranges calls to the
       widgets print initialize methods for the subclasses, when
       available (XeBasic subclasses).
     *
       
       after initialization, the top level widget is tiled into pages,
       and the cloned widget tree is traversed top down once for each
       page, printing each widget on the way either by the print method,
       or by a screen dump for foreign widgets.
     *
       
       after printing is complete, the cloned tree is traversed again and
       all resources are released by calling the appropriate print
       destroy methods, and finally the clone tree itself is released.
       
Printing methods

   
   
   The Xew printing solution adds total of 6(!) new widget methods to the
   XeBasic widget class structure
     * Print initialize method (XePrintInitializeProc)
     * Print method (XePrintProc)
     * Print destroy method (XePrintDestroyProc)
     * Print cancel method (XePrintCancelProc)
     * Print Constraint initialize method
       (XePrintConstraintInitializeProc)
     * Print Constraint destroy method (XePrintConstraintDestroyProc)

typedef struct _XeBasicClass
    {
        XePrintInitializeProc print_initialize;
        XePrintProc print;
        XePrintCancelProc print_cancel;
        XePrintDestroyProc print_destroy;
        XePrintConstraintInitializeProc print_constraint_initialize;
        XePrintConstraintDestroyProc print_constraint_destroy;
    } XeBasicClassPart;

   
   
   For a simple widget, most of these methods might be as easy as simply
   calling the corresponding standard method with the cloned widget.
     _________________________________________________________________
   
  Print initialize method
  
   void (*XePrintInitializeProc)(Widget, Widget, XePrintProcess)
          
   Widget widget
          is the source widget to be printed,
          
   Widget clone
          is a copy of the source widget being transformed for the
          printer
          
   XePrintProcess pp
          is the printing process context pointer (structure defined in
          PrintP.h).
          
   
   
   is somewhat similar to widget Initialize method (called in
   superclass-subclass order). This should make all the necessary changes
   for the printing process in the clone widget instance (a typical
   things that need be done are recreating GC's, recomputing any pixel
   values, reproducing the pixmaps etc..
     _________________________________________________________________
   
  Print method
  
   XtPointer (*XePrintProc)(Widget, Widget, int, int, XePrintProcess)
          
        Widget widget
   is the source widget to being printed,
   
   Widget clone
   is a copy of the source widget that has been transformed for the
   printer
   
   int x, int y
   specify the upper left corner of the quadrant to print in widget
   coordinate space.
   
   XePrintProcess pp
   is the printing process context pointer (structure defined in
   PrintP.h).
   
   is a somewhat similar to widget expose method. This should do the
   actual printing. If this returns non-NULL context pointer, the
   printing is active, but not completed. In that case main process
   (_XePrintProcess) will exit and it is the responsibility of the widget
   specific printing to resume the main process by calling
   _XePrintProcess after the widget print has been completed.
   
   If the widget extends across multiple pages, the print method is
   called once for each page.
   
   Note on (x,y) parameter
          The (x, y) parameter positions the widget content on the output
          space (the window attached to the clone widget). This position
          may be totally outside the window, and the intention is that
          the "expose" will actually produce the printout for the portion
          of the content that intersects the window.
          
          The (x, y) is also the mechanism that the controlling print
          driver process uses to implement multiple "exposes" from the
          same widget into different pages of the output.
          
          It would be tempting to make print method more like an ordinary
          expose method, and use expose event like structure and expose
          region parameters. Unfortunately, those structures would impose
          the X coordinate space restrictions (max 65535 x 65535) to the
          printing. The current solution allows much larger content to be
          safely printed.
          
   
     _________________________________________________________________
   
  Print Constraint initialize method
  
   void (*XePrintConstraintInitializeProc)(Widget, Widget,
          XePrintProcess)
          
   Widget widget
          is the source widget to be printed,
          
   Widget clone
          is a copy of the source widget that has been transformed for
          the printer
          
   XePrintProcess pp
          is the printing process context pointer (structure defined in
          PrintP.h).
          
   
   
   is similar to the widget Constraint Initialize method. This should
   make any necessary changes for the printing in the copied widget
   constraint record.
     _________________________________________________________________
   
  Print Constraint destroy method
  
   void (*XePrintConstraintDestroyProc)(Widget, Widget, XePrintProcess)
          
   Widget widget
          is the source widget to be printed,
          
   Widget clone
          is a copy of the source widget that has been transformed for
          the printer
          
   XePrintProcess pp
          is the printing process context pointer (structure defined in
          PrintP.h).
          
   
   
   is similar to the widget Constraint Destroy method. This should
   release any resources allocated in the Print Constraint Initialize.
     _________________________________________________________________
   
  Print cancel method
  
   void (*XePrintCancelProc)(Widget, Widget, XePrintProcess, XtPointer)
          
   Widget widget
          is the source widget to being printed,
          
   Widget clone
          is a copy of the source widget that has been transformed for
          the printer
          
   XePrintProcess pp
          is the printing process context pointer (structure defined in
          PrintP.h).
          
   XtPointer client_data
          is the context pointer returned by the print_method.
          
   
   
   is a method that is used to cancel the active printing process in the
   widget. The context parameter is the same as was returned by the print
   method. This function should abort whatever asynchronous printing is
   in progress and return the widget approximately to the state that it
   was before the print method call.
   
   Note
          This function should not do any tasks of the print_destroy
          method, which will get called later anyway.
          
   Note
          It is also guaranteed that print_destroy method is never called
          for a clone widget, if this printing is active on it.
          print_cancel is always called first in such cases.
          
   Note
          This function must not call the _XePrintProcess, which would
          normally happen when the active printing process completes.
          
   
     _________________________________________________________________
   
  Print destroy method
  
   void (*XePrintDestroyProc)(Widget, Widget, XePrintProcess)
          
   Widget widget
          is the source widget to being printed,
          
   Widget clone
          is a copy of the source widget that has been transformed for
          the printer
          
   XePrintProcess pp
          is the printing process context pointer (structure defined in
          PrintP.h).
          
   
   
   is similar to the widget Destroy method (called in subclass-superclass
   order). Its task is to release any resources allocated to the clone
   widget.
     _________________________________________________________________
   
Conclusions

   The following is a set of miscellanous comments and thoughts that have
   arisen from the implementation experience
     *
       
       The decision to build a cloned shadow widget tree is rather
       drastic one. The current implementation does not attempt to build
       a fully functioning widget tree, the current result is rather
       delicate and works only because the Xew printing methods attempt
       not to trigger any dangerous Xt tree traversing actions (such as
       geometry management). If the "clone tree solution" is used in the
       future, the building will probably need more work.
     *
       
       A related issue: current implementation is not prepared to handle
       multiple prints on same widget at same time, and printing is only
       loosely safeguarded against the source widget being destroyed or
       otherwise modified during the print process. Beware!.
     *
       
       If printing in Xt environment is further developed, instead of
       directly defining the methods in the widget class, printing should
       perhaps be defined as an extension record to the core class.
     *
       
       The "job description" of the print methods themselves needs some
       examination. Although, in principle they resemble their normal
       counterparts, in practise somewhat ugly compromises had to be made
       (for example, print_initialize of XeText needs to do partially the
       same job as is done in the print constraint initiliaze). This is
       an indication of some design flaws, which need some furher
       thought.
     *
       
       Neither of the test printing implementations (Xprinter or X Print
       server) use Window concept, and as a result, the printing process
       has to arrange for the relocation and clipping (not done
       currently) of the widget output. The implementation might become
       easier and cleaner if it would be possible to create own windows
       on the print server for each widget in the cloned tree. On the
       other hand, this would make the cloning process even heavier
       operation. If "printer windows" are implemented, some
       consideration of their function is needed. It seems likely that
       the window on printer should only provide coordinate translation
       and clipping, anything else, like automatic border drawing is
       problematic.
     *
       
       The printing uses the coordinate system defined by the screen.
       This is a serious drawback, especially on the text output. All
       widths are computed in screen units, which is way too coarse for a
       quality output. It would be desirable to use higher resolution on
       the printer (say 600dpi), but this would require much more work
       and care on building the cloned tree and initializing it to the
       printer, because all resources and internal state variables
       containing any dimension related values would need to be scaled
       (font sizes, geometry constraints, positions, widget sizes). This
       is doable, but was beyond the resources of this experimental
       implementation. Additionally, high resolution might cause
       overflows in many X fields that are defined as Position or
       Dimension.
     *
       
       Printed images are sent to printer scaled to the same dimensions
       as are shown in the display. Again, this is a loss, if the printer
       could do better than display. Having the print server to support
       XIE (image extension) might be a solution for this problem. Then,
       the printing would have an option to send the original source
       image to the printer, and define the desired output through the
       XIE operations (leaving the scaling, dithering, etc to the
       printer).
       
   
     _________________________________________________________________
   
   
     1995 Markku Savela
