Haiku API Bindings
Printing
Not logged in

Documentation | Manual: Printing

Chapter 10: Printing

In this chapter, we will learn how to print using the Haiku API.

This program for this chapter is called Printing.ext.

Views

The first thing to understand is that the only thing you can really print in Haiku is a View. However, since it is relatively easy to print text and images to a View, this is not a great limitation.

But it does mean that you have to have a View. Furthermore, that View must be attached to a Window. And since you have a Window, you must also have an Application. In our example, the Application, Window, and View will all be trivial, so we can concentrate on the printing code.

Perl

use Haiku::Window qw(B_TITLED_WINDOW B_QUIT_ON_WINDOW_CLOSE B_ASYNCHRONOUS_CONTROLS B_CURRENT_WORKSPACE);
use Haiku::PrintJob qw(:printer_type);

my $wframe = Haiku::Rect->new(50, 50, 300, 300);
my $title = "Print Window";
my $type = B_TITLED_WINDOW;
my $window_flags = B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS;
my $workspaces = B_CURRENT_WORKSPACE;

my $app = Haiku::Application->new('application/x.vnd-hab.perl.Printing');

my $window = Haiku::Window->new(
    frame      => $wframe,
    title      => $title,
    type       => $type,
    flags      => $window_flags,
    workspaces => $workspaces,
);

my $vframe = Haiku::Rect->new(5,5,105,25);
my $name = 'Button';
my $label = "Button!";

my $button = Haiku::Button->new(
    frame        => $vframe,
    name         => "$name 1",
    label        => $label,
);

$window->AddChild($button);

Python

wframe = Rect(50, 50, 300, 300)
title = "Print Window"
type = B_TITLED_WINDOW
window_flags = B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS
workspaces = B_CURRENT_WORKSPACE

app = Application('application/x.vnd-hab.python.Printing')

window = Window(
    frame      = wframe,
    title      = title,
    type       = type,
    flags      = window_flags,
    workspaces = workspaces,
)

vframe = Rect(5,5,105,25)
name = 'Button'
label = "Button!"

button = Button(
    frame        = vframe,
    name         = "name 1",
    label        = label,
)

window.AddChild(button)

Settings

Every PrintJob has settings, which are set or fetched as a Message. The Message can be Flattened and stored (as an attribute of the file to be printed, for example) and then later read back in and passed to the PrintJob to use the same settings.

The Message holds two sets of settings, each of which is controlled by a different user dialog. The "Page setup" dialog (called by the ConfigPage method) controls page layout, and the "Print setup" dialog (called by ConfigJob) controls the print session.

As currently designed, however, the page layout is also available from the "Print setup" dialog, so you don't actually need to call ConfigPage at all, unless you need to set the page layout without a print session; for example, to set margins in a WYSIWYG editor.

Perl

# if we had saved seetings from a previous session, we could load them here
my $settings;

my $job = Haiku::PrintJob->new("job");
if ($job->IsSettingsMessageValid($settings)) {
    $job->SetSettings($settings)
}
else {
    # if the user cancels, ConfigPage will generate an error, so trap it
    eval { $job->ConfigPage() };
    $settings = $job->Settings();
    # here we would save off the settings for later reprinting of the same document
}

# if the user cancels, ConfigJob will generate an error, so trap it
eval { $job->ConfigJob() };
$settings = $job->Settings();

Python

# if we had saved seetings from a previous session, we could load them here
settings = None

job = PrintJob("job")
if job.IsSettingsMessageValid(settings):
    job.SetSettings(settings)
else:
    # if the user cancels, ConfigPage will generate an error, so trap it
    try:
        job.ConfigPage()
    except:
        pass
    settings = job.Settings()
    # here we would save off the settings for later reprinting of the same document

# if the user cancels, ConfigJob will generate an error, so trap it
try:
    job.ConfigJob()
except:
    pass
settings = job.Settings()

Printing

As a convenience, the first and last page numbers are available from the PrintJOb object, so you don't need to pull them from the settings Message.

The PrintJob will also calculate two rectangles for you, the PaperRect (representing the size of the paper) and the PrintableRect (representing the space within the margins set by the user in the "Page setup" dialog.)

The basic flow of a printing session is:

Perl

# if the user chooses to print all pages, LastPage may be something like 2147483647
# so don't assume it's the actual page count
my $pagemax = $job->LastPage() - $job->FirstPage() + 1;

my $paper_rect = $job->PaperRect();
my $print_rect = $job->PrintableRect();

my $bounds = $print_rect->OffsetToCopy(0,0);

$job->BeginJob();
my $pagenum = 0;
while ($job->CanContinue() && $pagenum < $pagemax) {
    $pagenum++;

    $job->DrawView($button, $bounds, [0,0]);
    $job->SpoolPage();

    last; # just print a single page for this sample
    # if we were going to print more, we would adjust the bounds to
    # point to the next section of the View
}
$job->CommitJob();

Python

# if the user chooses to print all pages, LastPage may be something like 2147483647
# so don't assume it's the actual page count
pagemax = job.LastPage() - job.FirstPage() + 1

paper_rect = job.PaperRect()
print_rect = job.PrintableRect()

bounds = print_rect.OffsetToCopy(0,0)

job.BeginJob()
pagenum = 0
while job.CanContinue() and pagenum < pagemax:
    pagenum = pagenum + 1

    job.DrawView(button, bounds, [0,0])
    job.SpoolPage()

    break # just print a single page for this sample
    # if we were going to print more, we would adjust the bounds to
    # point to the next section of the View
job.CommitJob()

And that's basically it. Haiku makes printing easy.

Errors

There is, however, one final caveat:

According the the Be Book, CanContinue will return false "if the user has canceled the job, the spool file has grown too big, or something else has happened to terminate printing". However, as of this writing, CanContinue will only return false in one of the following conditions:

Note that neither DrawView nor SpoolPage will cause CanContinue to return false; therefore, under Haiku, neither the size of the spool file nor a problem during drawing will in fact cause the job to terminate. (Although you could of course, call CancelJob in your print loop if you make that loop smart enough to detect such problems.)

This also means that unless you call CancelJob from your print loop, you don't actually need to check CanContinue at the top of the loop, since the underlying Haiku code will not affect the return value. But it's probably a good idea to check anyway; that way, if at some point the Haiku code is changed to update the internal error marker during drawing or spooling, your code will continue to work with those changes.