printing works; font sizes are weird
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 14 Dec 2020 07:43:03 +0000 (23:43 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 14 Dec 2020 07:43:03 +0000 (23:43 -0800)
src/output/cairo-fsm.c
src/output/cairo-fsm.h
src/output/cairo-pager.c
src/output/cairo-pager.h
src/output/cairo.c
src/ui/gui/psppire-output-view.c

index 5d1b63e4f1937780333bbcae6e9e1a538d2e115e..54b65dd9c02d20ce66d6c59b455856274721a33c 100644 (file)
@@ -52,7 +52,7 @@
 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
 #define H TABLE_HORZ
 #define V TABLE_VERT
-
+\f
 struct xr_fsm_style *
 xr_fsm_style_ref (const struct xr_fsm_style *style_)
 {
@@ -63,6 +63,24 @@ xr_fsm_style_ref (const struct xr_fsm_style *style_)
   return style;
 }
 
+struct xr_fsm_style *
+xr_fsm_style_unshare (struct xr_fsm_style *old)
+{
+  assert (old->ref_cnt > 0);
+  if (old->ref_cnt == 1)
+    return old;
+
+  xr_fsm_style_unref (old);
+
+  struct xr_fsm_style *new = xmemdup (old, sizeof *old);
+  new->ref_cnt = 1;
+  for (int i = 0; i < XR_N_FONTS; i++)
+    if (old->fonts[i])
+      new->fonts[i] = pango_font_description_copy (old->fonts[i]);
+
+  return new;
+}
+
 void
 xr_fsm_style_unref (struct xr_fsm_style *style)
 {
@@ -608,7 +626,7 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell,
   if (font_style->typeface)
       desc = parse_font (
         font_style->typeface,
-        font_style->size ? font_style->size * 1000 * xr->style->font_scale : 10000,
+        (font_style->size ? font_style->size * 1000 : 10000) * xr->style->font_scale,
         font_style->bold, font_style->italic);
   if (!desc)
     desc = xr->style->fonts[font_type];
@@ -1094,7 +1112,6 @@ xr_fsm_create (const struct output_item *item_,
       .ops = &xrr_render_ops,
       .aux = fsm,
       .size = { [H] = style->size[H], [V] = style->size[V] },
-      /* XXX font_size */
       .line_widths = xr_line_widths,
       .min_break = { [H] = style->min_break[H], [V] = style->min_break[V] },
       .supports_margins = true,
index f89acbe5372a9e65557970c5bfa6da158a47efd7..b61f099035246de8a5237d37c1b97a56f9f785b9 100644 (file)
@@ -43,7 +43,7 @@ struct xr_fsm_style
   {
     int ref_cnt;
 
-    int size[TABLE_N_AXES];     /* Page size. */
+    int size[TABLE_N_AXES];      /* Page size. */
     int min_break[TABLE_N_AXES]; /* Minimum cell size to allow breaking. */
     PangoFontDescription *fonts[XR_N_FONTS];
     struct cell_color fg;
@@ -52,6 +52,7 @@ struct xr_fsm_style
     double font_scale;
   };
 struct xr_fsm_style *xr_fsm_style_ref (const struct xr_fsm_style *);
+struct xr_fsm_style *xr_fsm_style_unshare (struct xr_fsm_style *);
 void xr_fsm_style_unref (struct xr_fsm_style *);
 bool xr_fsm_style_equals (const struct xr_fsm_style *,
                           const struct xr_fsm_style *);
index 8a0f948cc86ab89a70495b2add3273cc64c2c211..2d287499a2b43858c2914186bea386aec1b001ae 100644 (file)
@@ -55,8 +55,6 @@ xr_page_style_unshare (struct xr_page_style *old)
   new->ref_cnt = 1;
   for (int i = 0; i < 2; i++)
     page_heading_copy (&new->headings[i], &old->headings[i]);
-  if (old->font)
-    new->font = pango_font_description_copy (old->font);
 
   return new;
 }
@@ -71,53 +69,37 @@ xr_page_style_unref (struct xr_page_style *ps)
         {
           for (int i = 0; i < 2; i++)
             page_heading_uninit (&ps->headings[i]);
-          if (ps->font)
-            pango_font_description_free (ps->font);
           free (ps);
         }
     }
 }
 
-static bool
-pfd_equals (const PangoFontDescription *a,
-            const PangoFontDescription *b)
-{
-  return a && b ? pango_font_description_equal (a, b) : !a && !b;
-}
-
 bool
 xr_page_style_equals (const struct xr_page_style *a,
                       const struct xr_page_style *b)
 {
   for (int i = 0; i < TABLE_N_AXES; i++)
-    {
-      if (a->size[i] != b->size[i])
+    for (int j = 0; j < 2; j++)
+      if (a->margins[i][j] != b->margins[i][j])
         return false;
 
-      for (int j = 0; j < 2; j++)
-        if (a->margins[i][j] != b->margins[i][j])
-          return false;
-    }
-
   for (int i = 0; i < 2; i++)
     if (!page_heading_equals (&a->headings[i], &b->headings[i]))
       return false;
 
-  return (pfd_equals (a->font, b->font)
-          && a->font_scale == b->font_scale
-          && a->initial_page_number == b->initial_page_number
+  return (a->initial_page_number == b->initial_page_number
           && a->object_spacing == b->object_spacing);
 }
 \f
 struct xr_pager
   {
     struct xr_page_style *page_style;
+    struct xr_fsm_style *fsm_style;
     int page_index;
     int heading_heights[2];
 
     /* Current output item. */
     struct xr_fsm *fsm;
-    struct xr_fsm_style *fsm_style;
     struct output_item *item;
 
     /* Current output page. */
@@ -200,7 +182,9 @@ xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
 }
 
 static void
-xr_measure_headings (const struct xr_page_style *ps, int heading_heights[2])
+xr_measure_headings (const struct xr_page_style *ps,
+                     const struct xr_fsm_style *fs,
+                     int heading_heights[2])
 {
   cairo_surface_t *surface = cairo_recording_surface_create (
     CAIRO_CONTENT_COLOR, NULL);
@@ -208,8 +192,9 @@ xr_measure_headings (const struct xr_page_style *ps, int heading_heights[2])
   for (int i = 0; i < 2; i++)
     {
       int *h = &heading_heights[i];
-      *h = xr_render_page_heading (cairo, ps->font, &ps->headings[i], -1,
-                                   ps->size[H], false, 0);
+      *h = xr_render_page_heading (cairo, fs->fonts[XR_FONT_PROPORTIONAL],
+                                   &ps->headings[i], -1, fs->size[H], false,
+                                   0);
       if (*h)
         *h += ps->object_spacing;
     }
@@ -218,24 +203,28 @@ xr_measure_headings (const struct xr_page_style *ps, int heading_heights[2])
 }
 
 struct xr_pager *
-xr_pager_create (const struct xr_page_style *ps_)
+xr_pager_create (const struct xr_page_style *ps_,
+                 const struct xr_fsm_style *fs_)
 {
+  printf ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
   struct xr_page_style *ps = xr_page_style_ref (ps_);
+  struct xr_fsm_style *fs = xr_fsm_style_ref (fs_);
 
   int heading_heights[2];
-  xr_measure_headings (ps, heading_heights);
+  xr_measure_headings (ps, fs, heading_heights);
   int total = heading_heights[0] + heading_heights[1];
-  if (total > 0 && total < ps->size[V])
+  if (total > 0 && total < fs->size[V])
     {
+      fs = xr_fsm_style_unshare (fs);
       ps = xr_page_style_unshare (ps);
 
       for (int i = 0; i < 2; i++)
         ps->margins[V][i] += heading_heights[i];
-      ps->size[V] -= total;
+      fs->size[V] -= total;
     }
 
   struct xr_pager *p = xmalloc (sizeof *p);
-  *p = (struct xr_pager) { .page_style = ps };
+  *p = (struct xr_pager) { .page_style = ps, .fsm_style = fs };
   return p;
 }
 
@@ -244,13 +233,18 @@ xr_pager_destroy (struct xr_pager *p)
 {
   if (p)
     {
-      xr_fsm_destroy (p->fsm);
+      printf (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+      xr_page_style_unref (p->page_style);
       xr_fsm_style_unref (p->fsm_style);
+
+      xr_fsm_destroy (p->fsm);
       output_item_unref (p->item);
 
-      xr_page_style_unref (p->page_style);
       if (p->cr)
-        cairo_destroy (p->cr);
+        {
+          cairo_restore (p->cr);
+          cairo_destroy (p->cr);
+        }
       free (p);
     }
 }
@@ -262,12 +256,11 @@ xr_pager_has_item (const struct xr_pager *p)
 }
 
 void
-xr_pager_add_item (struct xr_pager *p, const struct xr_fsm_style *fsm_style,
-                   const struct output_item *item)
+xr_pager_add_item (struct xr_pager *p, const struct output_item *item)
 {
+  printf ("add_item\n");
   assert (!p->item);
   p->item = output_item_ref (item);
-  p->fsm_style = xr_fsm_style_ref (fsm_style);
   xr_pager_run (p);
 }
 
@@ -280,10 +273,13 @@ xr_pager_has_page (const struct xr_pager *p)
 void
 xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
 {
+  printf ("add_page\n");
   assert (!p->cr);
+  cairo_save (cr);
   p->cr = cr;
   p->y = 0;
 
+  const struct xr_fsm_style *fs = p->fsm_style;
   const struct xr_page_style *ps = p->page_style;
   const struct cell_color *bg = &ps->bg;
   if (bg->alpha)
@@ -291,7 +287,7 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
       cairo_save (cr);
       cairo_set_source_rgba (cr, bg->r / 255.0, bg->g / 255.0,
                           bg->b / 255.0, bg->alpha / 255.0);
-      cairo_rectangle (cr, 0, 0, ps->size[H], ps->size[V]);
+      cairo_rectangle (cr, 0, 0, fs->size[H], fs->size[V]);
       cairo_fill (cr);
       cairo_restore (cr);
     }
@@ -299,15 +295,16 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
                    xr_to_pt (ps->margins[H][0]),
                    xr_to_pt (ps->margins[V][0]));
 
+  const PangoFontDescription *font = fs->fonts[XR_FONT_PROPORTIONAL];
   int page_number = p->page_index++ + ps->initial_page_number;
   if (p->heading_heights[0])
-    xr_render_page_heading (cr, ps->font, &ps->headings[0], page_number,
-                            ps->size[H], true, -p->heading_heights[0]);
+    xr_render_page_heading (cr, font, &ps->headings[0], page_number,
+                            fs->size[H], true, -p->heading_heights[0]);
 
   if (p->heading_heights[1])
-    xr_render_page_heading (cr, ps->font, &ps->headings[1], page_number,
-                            ps->size[H], true,
-                            ps->size[V] + ps->object_spacing);
+    xr_render_page_heading (cr, font, &ps->headings[1], page_number,
+                            fs->size[H], true,
+                            fs->size[V] + ps->object_spacing);
 
   xr_pager_run (p);
 }
@@ -315,10 +312,14 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
 bool
 xr_pager_needs_new_page (struct xr_pager *p)
 {
-  if (p->item && p->y >= p->page_style->size[V])
+  if (p->item && (!p->cr || p->y >= p->fsm_style->size[V]))
     {
-      cairo_destroy (p->cr);
-      p->cr = NULL;
+      if (p->cr)
+        {
+          cairo_restore (p->cr);
+          cairo_destroy (p->cr);
+          p->cr = NULL;
+        }
       return true;
     }
   else
@@ -328,16 +329,16 @@ xr_pager_needs_new_page (struct xr_pager *p)
 static void
 xr_pager_run (struct xr_pager *p)
 {
-  if (p->item && p->cr && p->y < p->page_style->size[V])
+  printf ("run:\n");
+  if (p->item && p->cr && p->y < p->fsm_style->size[V])
     {
       if (!p->fsm)
         {
-          /* XXX fsm_style needs to account for heading_heights */
+          printf ("\tcreate fsm\n");
           p->fsm = xr_fsm_create (p->item, p->fsm_style, p->cr);
           if (!p->fsm)
             {
-              xr_fsm_style_unref (p->fsm_style);
-              p->fsm_style = NULL;
+              printf ("\t(was null)\n");
               output_item_unref (p->item);
               p->item = NULL;
 
@@ -347,28 +348,34 @@ xr_pager_run (struct xr_pager *p)
 
       for (;;)
         {
+          printf ("\tdraw slice\n");
           int spacing = p->page_style->object_spacing;
           int chunk = xr_fsm_draw_slice (p->fsm, p->cr,
-                                         p->page_style->size[V] - p->y);
+                                         p->fsm_style->size[V] - p->y);
           p->y += chunk + spacing;
           cairo_translate (p->cr, 0, xr_to_pt (chunk + spacing));
 
           if (xr_fsm_is_empty (p->fsm))
             {
+              printf ("\tfinished object\n");
               xr_fsm_destroy (p->fsm);
               p->fsm = NULL;
-              xr_fsm_style_unref (p->fsm_style);
-              p->fsm_style = NULL;
               output_item_unref (p->item);
               p->item = NULL;
               return;
             }
           else if (!chunk)
             {
+              printf ("\tobject doesn't fit on page\n");
               assert (p->y > 0);
               p->y = INT_MAX;
               return;
             }
+          printf ("\tneed to draw another slice\n");
         }
     }
+  if (!p->item)
+    printf ("\tno item\n");
+  if (!p->cr)
+    printf ("\tno page\n");
 }
index b0cdfdf9144e4ce84c91db657a943230dbea7318..ab843ee30e6973d1585f303622253640d27e5526 100644 (file)
@@ -33,14 +33,11 @@ struct xr_page_style
   {
     int ref_cnt;
 
-    int size[TABLE_N_AXES];          /* Page size minus margins. */
     int margins[TABLE_N_AXES][2];    /* Margins. */
 
     struct page_heading headings[2]; /* Top and bottom headings. */
-    PangoFontDescription *font;
 
     struct cell_color bg;            /* Background color. */
-    double font_scale;
     int initial_page_number;
     int object_spacing;
   };
@@ -52,9 +49,10 @@ bool xr_page_style_equals (const struct xr_page_style *,
 struct xr_page_style *xr_page_style_default (void);
 
 static inline int
-xr_page_style_paper_size (const struct xr_page_style *ps, enum table_axis a)
+xr_page_style_paper_size (const struct xr_page_style *ps,
+                          const struct xr_fsm_style *fs, enum table_axis a)
 {
-  return ps->size[a] + ps->margins[a][0] + ps->margins[a][1];
+  return fs->size[a] + ps->margins[a][0] + ps->margins[a][1];
 }
 
 struct xr_pager *xr_pager_create (const struct xr_page_style *,
@@ -62,8 +60,7 @@ struct xr_pager *xr_pager_create (const struct xr_page_style *,
 void xr_pager_destroy (struct xr_pager *);
 
 bool xr_pager_has_item (const struct xr_pager *);
-void xr_pager_add_item (struct xr_pager *, const struct xr_fsm_style *,
-                        const struct output_item *);
+void xr_pager_add_item (struct xr_pager *, const struct output_item *);
 
 bool xr_pager_has_page (const struct xr_pager *);
 void xr_pager_add_page (struct xr_pager *, cairo_t *);
index 16738897130a2c8d951faee4f951a2baef257042..a85054ebccc0ca5f6fd78d8a5264df8ac0556ddd 100644 (file)
@@ -238,16 +238,12 @@ xr_allocate (const char *name, int device_type, struct string_map *o,
   *xr->page_style = (struct xr_page_style) {
     .ref_cnt = 1,
 
-    .size = { [H] = size[H], [V] = size[V] },
     .margins = {
       [H] = { margins[H][0], margins[H][1], },
       [V] = { margins[V][0], margins[V][1], },
     },
 
-    .font = pango_font_description_copy (proportional_font),
-
     .bg = bg,
-    .font_scale = font_scale,
     .initial_page_number = 1,
     .object_spacing = object_spacing,
   };
@@ -279,7 +275,8 @@ xr_create (struct file_handle *fh, enum settings_output_devices device_type,
 
   double paper[TABLE_N_AXES];
   for (int a = 0; a < TABLE_N_AXES; a++)
-    paper[a] = xr_to_pt (xr_page_style_paper_size (xr->page_style, a));
+    paper[a] = xr_to_pt (xr_page_style_paper_size (xr->page_style,
+                                                   xr->fsm_style, a));
   if (file_type == XR_PDF)
     xr->surface = cairo_pdf_surface_create (file_name, paper[H], paper[V]);
   else if (file_type == XR_PS)
@@ -374,19 +371,12 @@ xr_update_page_setup (struct output_driver *driver,
   *page_style = (struct xr_page_style) {
     .ref_cnt = 1,
 
-    .size = {
-      [H] = (ps->paper[h] - ps->margins[h][0] - ps->margins[h][1]) * scale,
-      [V] = (ps->paper[v] - ps->margins[v][0] - ps->margins[v][1]) * scale,
-    },
     .margins = {
       [H] = { ps->margins[h][0] * scale, ps->margins[h][1] * scale },
       [V] = { ps->margins[v][0] * scale, ps->margins[v][1] * scale },
     },
 
-    .font = pango_font_description_copy (xr->page_style->font),
-
     .bg = xr->page_style->bg,
-    .font_scale = xr->page_style->font_scale,
     .initial_page_number = ps->initial_page_number,
     .object_spacing = ps->object_spacing * 72 * XR_POINT,
   };
@@ -412,11 +402,11 @@ xr_submit (struct output_driver *driver, const struct output_item *output_item)
 
   if (!xr->pager)
     {
-      xr->pager = xr_pager_create (xr->page_style);
+      xr->pager = xr_pager_create (xr->page_style, xr->fsm_style);
       xr_pager_add_page (xr->pager, cairo_create (xr->surface));
     }
 
-  xr_pager_add_item (xr->pager, xr->fsm_style, output_item);
+  xr_pager_add_item (xr->pager, output_item);
   while (xr_pager_needs_new_page (xr->pager))
     {
       cairo_surface_show_page (xr->surface);
index 38dbf1a060a19fcd1612ca3f2256b96845472a68..ff19f64babe68d5ff3b88a7d850859170ce85c1b 100644 (file)
@@ -985,21 +985,9 @@ static cairo_t *
 get_cairo_context_from_print_context (GtkPrintContext *context)
 {
   cairo_t *cr = gtk_print_context_get_cairo_context (context);
-
-  /*
-    For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
-    Windows returns 600.
-  */
-  double xres = gtk_print_context_get_dpi_x (context);
-  double yres = gtk_print_context_get_dpi_y (context);
-
-  /* This means that the cairo context now has its dimensions in Points */
-  cairo_scale (cr, xres / 72.0, yres / 72.0);
-
-  return cr;
+  return cairo_reference (cr);
 }
 
-
 static void
 create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
 {
@@ -1011,11 +999,13 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
     [V] = gtk_page_setup_get_paper_height (ps, GTK_UNIT_POINTS) * XR_POINT,
   };
 
+  /* These are all 1/2 inch.  The "margins" that GTK+ gives us are useless:
+     they are the printer's imagable area. */
   int margins[TABLE_N_AXES][2] = {
-    [H][0] = gtk_page_setup_get_left_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
-    [H][1] = gtk_page_setup_get_right_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
-    [V][0] = gtk_page_setup_get_top_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
-    [V][1] = gtk_page_setup_get_bottom_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
+    [H][0] = XR_POINT * 36,
+    [H][1] = XR_POINT * 36,
+    [V][0] = XR_POINT * 36,
+    [V][1] = XR_POINT * 36,
   };
 
   double size[TABLE_N_AXES];
@@ -1031,14 +1021,11 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
   *view->page_style = (struct xr_page_style) {
     .ref_cnt = 1,
 
-    .size = { [H] = size[H], [V] = size[V] },
     .margins = {
       [H] = { margins[H][0], margins[H][1] },
       [V] = { margins[V][0], margins[V][1] },
     },
-    .font = pango_font_description_copy (proportional_font),
     .bg = { .alpha = 0 },
-    .font_scale = 72.0 / 128.0,
     .initial_page_number = 1,
     .object_spacing = 12 * XR_POINT,
   };
@@ -1048,6 +1035,7 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
     .ref_cnt = 1,
 
     .size = { [H] = size[H], [V] = size[V] },
+    .min_break = { [H] = size[H] / 2, [V] = size[V] / 2 },
     .fonts = {
       [XR_FONT_PROPORTIONAL] = proportional_font,
       [XR_FONT_FIXED] = fixed_font,
@@ -1058,7 +1046,7 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
     .font_scale = 72.0 / 128.0
   };
 
-  view->pager = xr_pager_create (view->page_style);
+  view->pager = xr_pager_create (view->page_style, view->fsm_style);
 }
 
 static gboolean
@@ -1074,8 +1062,7 @@ paginate (GtkPrintOperation *operation,
     }
   else if (view->print_item < view->n_items)
     {
-      xr_pager_add_item (view->pager, view->fsm_style,
-                         view->items[view->print_item++].item);
+      xr_pager_add_item (view->pager, view->items[view->print_item++].item);
       while (xr_pager_needs_new_page (view->pager))
        {
          xr_pager_add_page (view->pager,
@@ -1086,11 +1073,11 @@ paginate (GtkPrintOperation *operation,
     }
   else
     {
-      gtk_print_operation_set_n_pages (operation, view->print_n_pages);
+      gtk_print_operation_set_n_pages (operation, MAX (1, view->print_n_pages));
 
       /* Re-create the driver to do the real printing. */
       xr_pager_destroy (view->pager);
-      view->pager = xr_pager_create (view->page_style);
+      view->pager = xr_pager_create (view->page_style, view->fsm_style);
       view->print_item = 0;
       view->paginated = TRUE;
 
@@ -1106,7 +1093,7 @@ begin_print (GtkPrintOperation *operation,
   create_xr_print_driver (context, view);
 
   view->print_item = 0;
-  view->print_n_pages = 1;
+  view->print_n_pages = 0;
   view->paginated = FALSE;
 }
 
@@ -1116,6 +1103,7 @@ end_print (GtkPrintOperation *operation,
           struct psppire_output_view *view)
 {
   xr_pager_destroy (view->pager);
+  view->pager = NULL;
 }
 
 
@@ -1129,8 +1117,7 @@ draw_page (GtkPrintOperation *operation,
                      get_cairo_context_from_print_context (context));
   while (!xr_pager_needs_new_page (view->pager)
          && view->print_item < view->n_items)
-    xr_pager_add_item (view->pager, view->fsm_style,
-                       view->items [view->print_item++].item);
+    xr_pager_add_item (view->pager, view->items [view->print_item++].item);
 }
 
 
@@ -1145,6 +1132,9 @@ psppire_output_view_print (struct psppire_output_view *view,
   if (view->print_settings != NULL)
     gtk_print_operation_set_print_settings (print, view->print_settings);
 
+  gtk_print_operation_set_use_full_page (print, TRUE);
+  gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
+
   g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
   g_signal_connect (print, "end_print",   G_CALLBACK (end_print),   view);
   g_signal_connect (print, "paginate",    G_CALLBACK (paginate),    view);