2006-03-24 Alexander Larsson <alexl@redhat.com> Import print-operation into gtk+ * .cvsignore: * Makefile.am: * gtk+-unix-print-2.0.pc.in: Add gtk+-unix-print-2.0.pc * configure.in: Look for cups Look for various _NL_* extensions Output new makefiles and .pc.in * gtk/Makefile.am: Add new files * gtk/gtk.h: Include gtkprintoperation.h * gtk/gtkenums.h: Add printing enums * gtk/gtkmarshalers.list: Add required new marshallers * gtk/gtkpagesetup.[ch]: * gtk/gtkpagesetupunixdialog.[ch]: * gtk/gtkpagesetupunixdialog.h: * gtk/gtkpapersize.[ch]: * gtk/gtkprint-win32.[ch]: * gtk/gtkprintbackend.[ch]: * gtk/gtkprintcontext.[ch]: * gtk/gtkprinter-private.h: * gtk/gtkprinter.[ch]: * gtk/gtkprinteroption.[ch]: * gtk/gtkprinteroptionset.[ch]: * gtk/gtkprinteroptionwidget.[ch]: * gtk/gtkprintjob.[ch]: * gtk/gtkprintoperation-private.h: * gtk/gtkprintoperation-unix.c: * gtk/gtkprintoperation-win32.c: * gtk/gtkprintoperation.[ch]: * gtk/gtkprintsettings.[ch]: * gtk/gtkprintunixdialog.[ch]: * gtk/paper_names.c: Generic printing support * modules/Makefile.am: * modules/printbackends/Makefile.am: * modules/printbackends/cups/Makefile.am: * modules/printbackends/cups/gtkcupsutils.[ch]: * modules/printbackends/cups/gtkprintbackendcups.[ch]: * modules/printbackends/cups/gtkprintercups.[ch]: Cups backend * tests/.cvsignore: * tests/Makefile.am: * tests/print-editor.c: Add printing test app
534 lines
12 KiB
C
534 lines
12 KiB
C
/* GTK - The GIMP Toolkit
|
|
* gtkpapersize.c: Paper Size
|
|
* Copyright (C) 2006, Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <locale.h>
|
|
#include <langinfo.h>
|
|
|
|
#include "gtkpapersize.h"
|
|
|
|
#define MM_PER_INCH 25.4
|
|
#define POINTS_PER_INCH 72
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
const char *size;
|
|
const char *display_name;
|
|
const char *ppd_name;
|
|
} PaperInfo;
|
|
|
|
struct _GtkPaperSize
|
|
{
|
|
const PaperInfo *info;
|
|
|
|
/* If these are not set we fall back to info */
|
|
char *name;
|
|
char *display_name;
|
|
char *ppd_name;
|
|
|
|
double width, height; /* Stored in mm */
|
|
gboolean is_custom;
|
|
};
|
|
|
|
#include "paper_names.c"
|
|
|
|
GType
|
|
gtk_paper_size_get_type (void)
|
|
{
|
|
static GType our_type = 0;
|
|
|
|
if (our_type == 0)
|
|
our_type = g_boxed_type_register_static ("GtkPaperSize",
|
|
(GBoxedCopyFunc)gtk_paper_size_copy,
|
|
(GBoxedFreeFunc)gtk_paper_size_free);
|
|
return our_type;
|
|
}
|
|
|
|
static int
|
|
paper_info_compare (const void *_a, const void *_b)
|
|
{
|
|
const PaperInfo *a = _a;
|
|
const PaperInfo *b = _b;
|
|
|
|
return strcmp (a->name, b->name);
|
|
}
|
|
|
|
static PaperInfo *
|
|
lookup_paper_info (const char *name)
|
|
{
|
|
PaperInfo key;
|
|
PaperInfo *info;
|
|
|
|
key.name = name;
|
|
info = bsearch (&key, standard_names, G_N_ELEMENTS (standard_names),
|
|
sizeof (PaperInfo), paper_info_compare);
|
|
|
|
return info;
|
|
}
|
|
|
|
static double
|
|
to_mm (double len, GtkUnit unit)
|
|
{
|
|
switch (unit)
|
|
{
|
|
case GTK_UNIT_MM:
|
|
return len;
|
|
case GTK_UNIT_INCH:
|
|
return len * MM_PER_INCH;
|
|
default:
|
|
case GTK_UNIT_PIXEL:
|
|
g_warning ("Unsupported unit");
|
|
/* Fall through */
|
|
case GTK_UNIT_POINTS:
|
|
return len * (MM_PER_INCH / POINTS_PER_INCH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static double
|
|
from_mm (double len, GtkUnit unit)
|
|
{
|
|
switch (unit)
|
|
{
|
|
case GTK_UNIT_MM:
|
|
return len;
|
|
case GTK_UNIT_INCH:
|
|
return len / MM_PER_INCH;
|
|
default:
|
|
case GTK_UNIT_PIXEL:
|
|
g_warning ("Unsupported unit");
|
|
/* Fall through */
|
|
case GTK_UNIT_POINTS:
|
|
return len / (MM_PER_INCH / POINTS_PER_INCH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
parse_media_size (const char *size,
|
|
double *width_mm, double *height_mm)
|
|
{
|
|
const char *p;
|
|
char *e;
|
|
double short_dim, long_dim;
|
|
|
|
p = size;
|
|
|
|
short_dim = g_ascii_strtod (p, &e);
|
|
|
|
if (p == e || *e != 'x')
|
|
return FALSE;
|
|
|
|
p = e + 1; /* Skip x */
|
|
|
|
long_dim = g_ascii_strtod (p, &e);
|
|
|
|
if (p == e)
|
|
return FALSE;
|
|
|
|
p = e;
|
|
|
|
if (strcmp (p, "in") == 0)
|
|
{
|
|
short_dim = short_dim * MM_PER_INCH;
|
|
long_dim = long_dim * MM_PER_INCH;
|
|
}
|
|
else if (strcmp (p, "mm") != 0)
|
|
return FALSE;
|
|
|
|
if (width_mm)
|
|
*width_mm = short_dim;
|
|
if (height_mm)
|
|
*height_mm = long_dim;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
parse_full_media_size_name (const char *full_name,
|
|
char **name,
|
|
double *width_mm, double *height_mm)
|
|
{
|
|
const char *p;
|
|
const char *end_of_name;
|
|
|
|
/* From the spec:
|
|
media-size-self-describing-name =
|
|
( class-in "_" size-name "_" short-dim "x" long-dim "in" ) |
|
|
( class-mm "_" size-name "_" short-dim "x" long-dim "mm" )
|
|
class-in = "custom" | "na" | "asme" | "roc" | "oe"
|
|
class-mm = "custom" | "iso" | "jis" | "jpn" | "prc" | "om"
|
|
size-name = ( lowalpha | digit ) *( lowalpha | digit | "-" )
|
|
short-dim = dim
|
|
long-dim = dim
|
|
dim = integer-part [fraction-part] | "0" fraction-part
|
|
integer-part = non-zero-digit *digit
|
|
fraction-part = "." *digit non-zero-digit
|
|
lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
|
|
"j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
|
|
"s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
|
|
non-zero-digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
|
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
|
*/
|
|
|
|
p = strchr (full_name, '_');
|
|
if (p == NULL)
|
|
return FALSE;
|
|
|
|
p++; /* Skip _ */
|
|
|
|
p = strchr (p, '_');
|
|
if (p == NULL)
|
|
return FALSE;
|
|
|
|
end_of_name = p;
|
|
|
|
p++; /* Skip _ */
|
|
|
|
if (!parse_media_size (p, width_mm, height_mm))
|
|
return FALSE;
|
|
|
|
if (name)
|
|
*name = g_strndup (full_name, end_of_name - full_name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkPaperSize *
|
|
gtk_paper_size_new_from_info (const PaperInfo *info)
|
|
{
|
|
GtkPaperSize *size;
|
|
|
|
size = g_new0 (GtkPaperSize, 1);
|
|
size->info = info;
|
|
parse_media_size (info->size, &size->width, &size->height);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
GtkPaperSize *
|
|
gtk_paper_size_new (const char *name)
|
|
{
|
|
GtkPaperSize *size;
|
|
char *short_name;
|
|
double width, height;
|
|
PaperInfo *info;
|
|
|
|
if (name == NULL)
|
|
name = gtk_paper_size_get_default ();
|
|
|
|
if (parse_full_media_size_name (name, &short_name, &width, &height))
|
|
{
|
|
size = g_new0 (GtkPaperSize, 1);
|
|
|
|
size->width = width;
|
|
size->height = height;
|
|
size->name = short_name;
|
|
size->display_name = g_strdup (short_name);
|
|
}
|
|
else
|
|
{
|
|
info = lookup_paper_info (name);
|
|
if (info != NULL)
|
|
size = gtk_paper_size_new_from_info (info);
|
|
else
|
|
{
|
|
g_warning ("Unknown paper size %s\n", name);
|
|
size = g_new0 (GtkPaperSize, 1);
|
|
size->name = g_strdup (name);
|
|
size->display_name = g_strdup (name);
|
|
/* Default to A4 size */
|
|
size->width = 210;
|
|
size->height = 297;
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
GtkPaperSize *
|
|
gtk_paper_size_new_from_ppd (const char *ppd_name,
|
|
const char *ppd_display_name,
|
|
double width,
|
|
double height)
|
|
{
|
|
char *name;
|
|
GtkPaperSize *size;
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(standard_names); i++)
|
|
{
|
|
if (standard_names[i].ppd_name != NULL &&
|
|
strcmp (standard_names[i].ppd_name, ppd_name) == 0)
|
|
return gtk_paper_size_new_from_info (&standard_names[i]);
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(extra_ppd_names); i++)
|
|
{
|
|
if (strcmp (extra_ppd_names[i].ppd_name, ppd_name) == 0)
|
|
{
|
|
size = gtk_paper_size_new (extra_ppd_names[i].standard_name);
|
|
size->ppd_name = g_strdup (ppd_name);
|
|
return size;
|
|
}
|
|
}
|
|
|
|
name = g_strdup_printf ("ppd_%s", ppd_name);
|
|
size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
|
|
g_free (name);
|
|
size->ppd_name = g_strdup (ppd_name);
|
|
return size;
|
|
}
|
|
|
|
|
|
GtkPaperSize *
|
|
gtk_paper_size_new_custom (const char *name, const char *display_name,
|
|
double width, double height, GtkUnit unit)
|
|
{
|
|
GtkPaperSize *size;
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
g_return_val_if_fail (unit != GTK_UNIT_PIXEL, NULL);
|
|
|
|
size = g_new0 (GtkPaperSize, 1);
|
|
|
|
size->name = g_strdup (name);
|
|
size->display_name = g_strdup (display_name);
|
|
size->is_custom = TRUE;
|
|
|
|
/* Width is always the shorter one */
|
|
if (width > height)
|
|
{
|
|
double t = width;
|
|
width = height;
|
|
height = t;
|
|
}
|
|
|
|
size->width = to_mm (width, unit);
|
|
size->height = to_mm (height, unit);
|
|
|
|
return size;
|
|
}
|
|
|
|
GtkPaperSize *
|
|
gtk_paper_size_copy (GtkPaperSize *other)
|
|
{
|
|
GtkPaperSize *size;
|
|
|
|
size = g_new0 (GtkPaperSize, 1);
|
|
|
|
size->info = other->info;
|
|
if (other->name)
|
|
size->name = g_strdup (other->name);
|
|
if (other->display_name)
|
|
size->display_name = g_strdup (other->display_name);
|
|
if (other->ppd_name)
|
|
size->ppd_name = g_strdup (other->ppd_name);
|
|
|
|
size->width = other->width;
|
|
size->height = other->height;
|
|
size->is_custom = other->is_custom;
|
|
|
|
return size;
|
|
}
|
|
|
|
void
|
|
gtk_paper_size_free (GtkPaperSize *size)
|
|
{
|
|
g_free (size->name);
|
|
g_free (size->display_name);
|
|
g_free (size->ppd_name);
|
|
g_free (size);
|
|
}
|
|
|
|
gboolean
|
|
gtk_paper_size_is_equal (GtkPaperSize *size1,
|
|
GtkPaperSize *size2)
|
|
{
|
|
if (size1->info != NULL && size2->info != NULL)
|
|
return size1->info == size2->info;
|
|
|
|
return strcmp (gtk_paper_size_get_name (size1),
|
|
gtk_paper_size_get_name (size2)) == 0;
|
|
}
|
|
|
|
G_CONST_RETURN char *
|
|
gtk_paper_size_get_name (GtkPaperSize *size)
|
|
{
|
|
if (size->name)
|
|
return size->name;
|
|
g_assert (size->info != NULL);
|
|
return size->info->name;
|
|
}
|
|
|
|
G_CONST_RETURN char *
|
|
gtk_paper_size_get_display_name (GtkPaperSize *size)
|
|
{
|
|
if (size->display_name)
|
|
return size->display_name;
|
|
g_assert (size->info != NULL);
|
|
return size->info->display_name;
|
|
}
|
|
|
|
G_CONST_RETURN char *
|
|
gtk_paper_size_get_ppd_name (GtkPaperSize *size)
|
|
{
|
|
if (size->ppd_name)
|
|
return size->ppd_name;
|
|
if (size->info)
|
|
return size->info->ppd_name;
|
|
return NULL;
|
|
}
|
|
|
|
double
|
|
gtk_paper_size_get_width (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
return from_mm (size->width, unit);
|
|
}
|
|
double
|
|
gtk_paper_size_get_height (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
return from_mm (size->height, unit);
|
|
}
|
|
|
|
gboolean
|
|
gtk_paper_size_is_custom (GtkPaperSize *size)
|
|
{
|
|
return size->is_custom;
|
|
}
|
|
|
|
/* Only for custom sizes: */
|
|
void
|
|
gtk_paper_size_set_size (GtkPaperSize *size, double width, double height, GtkUnit unit)
|
|
{
|
|
g_return_if_fail (size != NULL);
|
|
g_return_if_fail (size->is_custom);
|
|
|
|
/* Width is always the shorter one */
|
|
if (width > height)
|
|
{
|
|
double t = width;
|
|
width = height;
|
|
height = t;
|
|
}
|
|
|
|
size->width = to_mm (width, unit);
|
|
size->height = to_mm (height, unit);
|
|
}
|
|
|
|
#define NL_PAPER_GET(x) \
|
|
((union { char *string; unsigned int word; })nl_langinfo(x)).word
|
|
|
|
G_CONST_RETURN char *
|
|
gtk_paper_size_get_default (void)
|
|
{
|
|
char *locale;
|
|
|
|
#if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
|
|
{
|
|
int width = NL_PAPER_GET (_NL_PAPER_WIDTH);
|
|
int height = NL_PAPER_GET (_NL_PAPER_HEIGHT);
|
|
|
|
if (width == 210 && height == 297)
|
|
return GTK_PAPER_NAME_A4;
|
|
|
|
if (width == 216 && height == 279)
|
|
return GTK_PAPER_NAME_LETTER;
|
|
}
|
|
#endif
|
|
|
|
#ifdef LC_PAPER
|
|
locale = setlocale(LC_PAPER, NULL);
|
|
#else
|
|
locale = setlocale(LC_MESSAGES, NULL);
|
|
#endif
|
|
|
|
if (g_str_has_prefix (locale, "en_CA") ||
|
|
g_str_has_prefix (locale, "en_US") ||
|
|
g_str_has_prefix (locale, "es_PR") ||
|
|
g_str_has_prefix (locale, "es_US"))
|
|
return GTK_PAPER_NAME_LETTER;
|
|
|
|
return GTK_PAPER_NAME_A4;
|
|
}
|
|
|
|
/* These get the default margins used for the paper size. Its
|
|
* larger than most printers margins, so that it will be within
|
|
* the imageble area on any printer.
|
|
*
|
|
* I've taken the actual values used from the OSX page setup dialog.
|
|
* I'm not sure exactly where they got these values for, but might
|
|
* correspond to this (from ghostscript docs):
|
|
*
|
|
* All DeskJets have 0.5 inches (1.27cm) of unprintable bottom margin,
|
|
* due to the mechanical arrangement used to grab the paper. Side margins
|
|
* are approximately 0.25 inches (0.64cm) for U.S. letter paper, and 0.15
|
|
* inches (0.38cm) for A4.
|
|
*/
|
|
|
|
double
|
|
gtk_paper_size_get_default_top_margin (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
double margin;
|
|
|
|
margin = to_mm (0.25, GTK_UNIT_INCH);
|
|
return from_mm (margin, unit);
|
|
}
|
|
|
|
double
|
|
gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
double margin;
|
|
const char *name;
|
|
|
|
margin = to_mm (0.25, GTK_UNIT_INCH);
|
|
|
|
name = gtk_paper_size_get_name (size);
|
|
if (strcmp (name, "na_letter") == 0 ||
|
|
strcmp (name, "na_legal") == 0 ||
|
|
strcmp (name, "iso_a4") == 0)
|
|
margin = to_mm (0.56, GTK_UNIT_INCH);
|
|
|
|
return from_mm (margin, unit);
|
|
}
|
|
|
|
double
|
|
gtk_paper_size_get_default_left_margin (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
double margin;
|
|
|
|
margin = to_mm (0.25, GTK_UNIT_INCH);
|
|
return from_mm (margin, unit);
|
|
}
|
|
|
|
double
|
|
gtk_paper_size_get_default_right_margin (GtkPaperSize *size, GtkUnit unit)
|
|
{
|
|
double margin;
|
|
|
|
margin = to_mm (0.25, GTK_UNIT_INCH);
|
|
return from_mm (margin, unit);
|
|
}
|