Files
gtk/gtk/gtkpapersize.c
Alexander Larsson 65df7d0a56 Import print-operation into gtk+
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
2006-03-24 16:33:21 +00:00

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);
}