1120 lines
30 KiB
C
1120 lines
30 KiB
C
/* GTK - The GIMP Toolkit
|
||
* gtkpapersize.c: Paper Size
|
||
* Copyright (C) 2006, Red Hat, Inc.
|
||
* Copyright © 2006, 2007 Christian Persch
|
||
*
|
||
* 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, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "config.h"
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <locale.h>
|
||
#if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
|
||
#include <langinfo.h>
|
||
#endif
|
||
#include <math.h>
|
||
|
||
#include <glib/gi18n-lib.h>
|
||
|
||
#include "gtkpapersize.h"
|
||
#include "gtkprintutilsprivate.h"
|
||
#include "gtkprintoperation.h" /* for GtkPrintError */
|
||
|
||
/* _gtk_load_custom_papers() only on Unix so far */
|
||
#ifdef G_OS_UNIX
|
||
#include "gtkcustompaperunixdialog.h"
|
||
#endif
|
||
|
||
#include "paper_names_offsets.c"
|
||
|
||
|
||
/**
|
||
* GtkPaperSize:
|
||
*
|
||
* `GtkPaperSize` handles paper sizes.
|
||
*
|
||
* It uses the standard called
|
||
* [PWG 5101.1-2002 PWG: Standard for Media Standardized Names](http://www.pwg.org/standards.html)
|
||
* to name the paper sizes (and to get the data for the page sizes).
|
||
* In addition to standard paper sizes, `GtkPaperSize` allows to
|
||
* construct custom paper sizes with arbitrary dimensions.
|
||
*
|
||
* The `GtkPaperSize` object stores not only the dimensions (width
|
||
* and height) of a paper size and its name, it also provides
|
||
* default print margins.
|
||
*/
|
||
|
||
|
||
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;
|
||
gboolean is_ipp;
|
||
};
|
||
|
||
G_DEFINE_BOXED_TYPE (GtkPaperSize, gtk_paper_size,
|
||
gtk_paper_size_copy,
|
||
gtk_paper_size_free)
|
||
|
||
static const PaperInfo *
|
||
lookup_paper_info (const char *name)
|
||
{
|
||
int lower = 0;
|
||
int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
|
||
int mid;
|
||
int cmp;
|
||
|
||
do
|
||
{
|
||
mid = (lower + upper) / 2;
|
||
cmp = strcmp (name, paper_names + standard_names_offsets[mid].name);
|
||
if (cmp < 0)
|
||
upper = mid - 1;
|
||
else if (cmp > 0)
|
||
lower = mid + 1;
|
||
else
|
||
return &standard_names_offsets[mid];
|
||
}
|
||
while (lower <= upper);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
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;
|
||
size->width = info->width;
|
||
size->height = info->height;
|
||
|
||
return size;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_new:
|
||
* @name: (nullable): a paper size name
|
||
*
|
||
* Creates a new `GtkPaperSize` object by parsing a
|
||
* [PWG 5101.1-2002](ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf)
|
||
* paper name.
|
||
*
|
||
* If @name is %NULL, the default paper size is returned,
|
||
* see [func@Gtk.PaperSize.get_default].
|
||
*
|
||
* Returns: a new `GtkPaperSize`, use [method@Gtk.PaperSize.free]
|
||
* to free it
|
||
*/
|
||
GtkPaperSize *
|
||
gtk_paper_size_new (const char *name)
|
||
{
|
||
GtkPaperSize *size;
|
||
char *short_name;
|
||
double width, height;
|
||
const PaperInfo *info;
|
||
|
||
if (name == NULL)
|
||
name = gtk_paper_size_get_default ();
|
||
|
||
if (parse_full_media_size_name (name, &short_name, &width, &height))
|
||
{
|
||
info = lookup_paper_info (short_name);
|
||
if (info != NULL && info->width == width && info->height == height)
|
||
{
|
||
size = gtk_paper_size_new_from_info (info);
|
||
g_free (short_name);
|
||
}
|
||
else
|
||
{
|
||
size = g_new0 (GtkPaperSize, 1);
|
||
|
||
size->width = width;
|
||
size->height = height;
|
||
size->name = short_name;
|
||
size->display_name = g_strdup (short_name);
|
||
if (strncmp (short_name, "custom", 6) == 0)
|
||
size->is_custom = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
info = lookup_paper_info (name);
|
||
if (info != NULL)
|
||
size = gtk_paper_size_new_from_info (info);
|
||
else
|
||
{
|
||
g_warning ("Unknown paper size %s", 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;
|
||
}
|
||
|
||
static char *
|
||
improve_displayname (const char *name)
|
||
{
|
||
char *p, *p1, *p2, *s;
|
||
|
||
p = strrchr (name, 'x');
|
||
if (p && p != name &&
|
||
g_ascii_isdigit (*(p - 1)) &&
|
||
g_ascii_isdigit (*(p + 1)))
|
||
{
|
||
p1 = g_strndup (name, p - name);
|
||
p2 = g_strdup (p + 1);
|
||
s = g_strconcat (p1, "×", p2, NULL);
|
||
g_free (p1);
|
||
g_free (p2);
|
||
}
|
||
else
|
||
s = g_strdup (name);
|
||
|
||
return s;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_new_from_ppd:
|
||
* @ppd_name: a PPD paper name
|
||
* @ppd_display_name: the corresponding human-readable name
|
||
* @width: the paper width, in points
|
||
* @height: the paper height in points
|
||
*
|
||
* Creates a new `GtkPaperSize` object by using
|
||
* PPD information.
|
||
*
|
||
* If @ppd_name is not a recognized PPD paper name,
|
||
* @ppd_display_name, @width and @height are used to
|
||
* construct a custom `GtkPaperSize` object.
|
||
*
|
||
* Returns: a new `GtkPaperSize`, use [method@Gtk.PaperSize.free]
|
||
* to free it
|
||
*/
|
||
GtkPaperSize *
|
||
gtk_paper_size_new_from_ppd (const char *ppd_name,
|
||
const char *ppd_display_name,
|
||
double width,
|
||
double height)
|
||
{
|
||
char *name;
|
||
const char *lookup_ppd_name;
|
||
char *freeme;
|
||
GtkPaperSize *size;
|
||
int i;
|
||
char *display_name;
|
||
|
||
lookup_ppd_name = ppd_name;
|
||
|
||
freeme = NULL;
|
||
/* Strip out Traverse suffix in matching. */
|
||
if (g_str_has_suffix (ppd_name, ".Transverse"))
|
||
{
|
||
lookup_ppd_name = freeme =
|
||
g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
|
||
}
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); i++)
|
||
{
|
||
if (standard_names_offsets[i].ppd_name != -1 &&
|
||
strcmp (paper_names + standard_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
|
||
{
|
||
size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (extra_ppd_names_offsets); i++)
|
||
{
|
||
if (strcmp (paper_names + extra_ppd_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
|
||
{
|
||
size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
name = g_strconcat ("ppd_", ppd_name, NULL);
|
||
display_name = improve_displayname (ppd_display_name);
|
||
size = gtk_paper_size_new_custom (name, display_name, width, height, GTK_UNIT_POINTS);
|
||
g_free (display_name);
|
||
g_free (name);
|
||
|
||
out:
|
||
|
||
if (size->info == NULL ||
|
||
size->info->ppd_name == -1 ||
|
||
strcmp (paper_names + size->info->ppd_name, ppd_name) != 0)
|
||
size->ppd_name = g_strdup (ppd_name);
|
||
|
||
g_free (freeme);
|
||
|
||
return size;
|
||
}
|
||
|
||
/* Tolerance of paper size in points according to PostScript Language Reference */
|
||
#define PAPER_SIZE_TOLERANCE 5
|
||
|
||
/**
|
||
* gtk_paper_size_new_from_ipp:
|
||
* @ipp_name: an IPP paper name
|
||
* @width: the paper width, in points
|
||
* @height: the paper height in points
|
||
*
|
||
* Creates a new `GtkPaperSize` object by using
|
||
* IPP information.
|
||
*
|
||
* If @ipp_name is not a recognized paper name,
|
||
* @width and @height are used to
|
||
* construct a custom `GtkPaperSize` object.
|
||
*
|
||
* Returns: a new `GtkPaperSize`, use [method@Gtk.PaperSize.free]
|
||
* to free it
|
||
*/
|
||
GtkPaperSize *
|
||
gtk_paper_size_new_from_ipp (const char *ipp_name,
|
||
double width,
|
||
double height)
|
||
{
|
||
GtkPaperSize *size;
|
||
const char *name = NULL;
|
||
gboolean found = FALSE;
|
||
float x_dimension;
|
||
float y_dimension;
|
||
char *display_name = NULL;
|
||
int i;
|
||
|
||
/* Find paper size according to its name */
|
||
for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); i++)
|
||
{
|
||
if (standard_names_offsets[i].name != -1)
|
||
name = paper_names + standard_names_offsets[i].name;
|
||
if (name != NULL &&
|
||
/* Given paper size name is equal to a name
|
||
from the standard paper size names list. */
|
||
((g_strcmp0 (ipp_name, name) == 0) ||
|
||
/* Given paper size name is prefixed by a name
|
||
from the standard paper size names list +
|
||
it consists of size in its name (e.g. iso_a4_210x297mm). */
|
||
(g_str_has_prefix (ipp_name, name) &&
|
||
strlen (ipp_name) > strlen (name) + 2 &&
|
||
ipp_name[strlen (ipp_name)] == '_' &&
|
||
g_ascii_isdigit (ipp_name[strlen (ipp_name) + 1]) &&
|
||
(g_str_has_suffix (ipp_name, "mm") ||
|
||
g_str_has_suffix (ipp_name, "in")))))
|
||
{
|
||
display_name = g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,
|
||
"paper size",
|
||
paper_names + standard_names_offsets[i].display_name));
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Find paper size according to its size */
|
||
if (display_name == NULL)
|
||
{
|
||
for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); i++)
|
||
{
|
||
x_dimension = _gtk_print_convert_from_mm (standard_names_offsets[i].width, GTK_UNIT_POINTS);
|
||
y_dimension = _gtk_print_convert_from_mm (standard_names_offsets[i].height, GTK_UNIT_POINTS);
|
||
|
||
if (fabs (x_dimension - width) <= PAPER_SIZE_TOLERANCE &&
|
||
fabs (y_dimension - height) <= PAPER_SIZE_TOLERANCE)
|
||
{
|
||
display_name = g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,
|
||
"paper size",
|
||
paper_names + standard_names_offsets[i].display_name));
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Fallback to name of the paper size as given in "ipp_name" parameter */
|
||
if (display_name == NULL)
|
||
display_name = g_strdup (ipp_name);
|
||
|
||
size = gtk_paper_size_new_custom (ipp_name, display_name, width, height, GTK_UNIT_POINTS);
|
||
size->is_custom = !found;
|
||
size->is_ipp = found;
|
||
|
||
g_free (display_name);
|
||
|
||
return size;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_new_custom:
|
||
* @name: the paper name
|
||
* @display_name: the human-readable name
|
||
* @width: the paper width, in units of @unit
|
||
* @height: the paper height, in units of @unit
|
||
* @unit: the unit for @width and @height. not %GTK_UNIT_NONE.
|
||
*
|
||
* Creates a new `GtkPaperSize` object with the
|
||
* given parameters.
|
||
*
|
||
* Returns: a new `GtkPaperSize` object, use [method@Gtk.PaperSize.free]
|
||
* to free it
|
||
*/
|
||
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_NONE, NULL);
|
||
|
||
size = g_new0 (GtkPaperSize, 1);
|
||
|
||
size->name = g_strdup (name);
|
||
size->display_name = g_strdup (display_name);
|
||
size->is_custom = TRUE;
|
||
|
||
size->width = _gtk_print_convert_to_mm (width, unit);
|
||
size->height = _gtk_print_convert_to_mm (height, unit);
|
||
|
||
return size;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_copy:
|
||
* @other: a `GtkPaperSize`
|
||
*
|
||
* Copies an existing `GtkPaperSize`.
|
||
*
|
||
* Returns: a copy of @other
|
||
*/
|
||
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;
|
||
size->is_ipp = other->is_ipp;
|
||
|
||
return size;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_free:
|
||
* @size: a `GtkPaperSize`
|
||
*
|
||
* Free the given `GtkPaperSize` object.
|
||
*/
|
||
void
|
||
gtk_paper_size_free (GtkPaperSize *size)
|
||
{
|
||
g_free (size->name);
|
||
g_free (size->display_name);
|
||
g_free (size->ppd_name);
|
||
g_free (size);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_is_equal:
|
||
* @size1: a `GtkPaperSize` object
|
||
* @size2: another `GtkPaperSize` object
|
||
*
|
||
* Compares two `GtkPaperSize` objects.
|
||
*
|
||
* Returns: %TRUE, if @size1 and @size2
|
||
* represent the same paper 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;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_paper_sizes:
|
||
* @include_custom: whether to include custom paper sizes
|
||
* as defined in the page setup dialog
|
||
*
|
||
* Creates a list of known paper sizes.
|
||
*
|
||
* Returns: (element-type GtkPaperSize) (transfer full): a newly allocated list of newly
|
||
* allocated `GtkPaperSize` objects
|
||
*/
|
||
GList *
|
||
gtk_paper_size_get_paper_sizes (gboolean include_custom)
|
||
{
|
||
GList *list = NULL;
|
||
guint i;
|
||
/* _gtk_load_custom_papers() only on Unix so far */
|
||
#ifdef G_OS_UNIX
|
||
if (include_custom)
|
||
{
|
||
GList *page_setups, *l;
|
||
|
||
page_setups = _gtk_load_custom_papers ();
|
||
for (l = page_setups; l != NULL; l = l->next)
|
||
{
|
||
GtkPageSetup *setup = (GtkPageSetup *) l->data;
|
||
GtkPaperSize *size;
|
||
|
||
size = gtk_page_setup_get_paper_size (setup);
|
||
list = g_list_prepend (list, gtk_paper_size_copy (size));
|
||
}
|
||
|
||
g_list_free_full (page_setups, g_object_unref);
|
||
}
|
||
#endif
|
||
for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); ++i)
|
||
{
|
||
GtkPaperSize *size;
|
||
|
||
size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
|
||
list = g_list_prepend (list, size);
|
||
}
|
||
|
||
return g_list_reverse (list);
|
||
}
|
||
|
||
|
||
/**
|
||
* gtk_paper_size_get_name:
|
||
* @size: a `GtkPaperSize` object
|
||
*
|
||
* Gets the name of the `GtkPaperSize`.
|
||
*
|
||
* Returns: the name of @size
|
||
*/
|
||
const char *
|
||
gtk_paper_size_get_name (GtkPaperSize *size)
|
||
{
|
||
if (size->name)
|
||
return size->name;
|
||
g_assert (size->info != NULL);
|
||
return paper_names + size->info->name;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_display_name:
|
||
* @size: a `GtkPaperSize` object
|
||
*
|
||
* Gets the human-readable name of the `GtkPaperSize`.
|
||
*
|
||
* Returns: the human-readable name of @size
|
||
*/
|
||
const char *
|
||
gtk_paper_size_get_display_name (GtkPaperSize *size)
|
||
{
|
||
const char *display_name;
|
||
|
||
if (size->display_name)
|
||
return size->display_name;
|
||
|
||
g_assert (size->info != NULL);
|
||
|
||
display_name = paper_names + size->info->display_name;
|
||
return g_dpgettext2 (GETTEXT_PACKAGE, "paper size", display_name);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_ppd_name:
|
||
* @size: a `GtkPaperSize` object
|
||
*
|
||
* Gets the PPD name of the `GtkPaperSize`, which
|
||
* may be %NULL.
|
||
*
|
||
* Returns: the PPD name of @size
|
||
*/
|
||
const char *
|
||
gtk_paper_size_get_ppd_name (GtkPaperSize *size)
|
||
{
|
||
if (size->ppd_name)
|
||
return size->ppd_name;
|
||
if (size->info)
|
||
return paper_names + size->info->ppd_name;
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_width:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the paper width of the `GtkPaperSize`, in
|
||
* units of @unit.
|
||
*
|
||
* Returns: the paper width
|
||
*/
|
||
double
|
||
gtk_paper_size_get_width (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
return _gtk_print_convert_from_mm (size->width, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_height:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the paper height of the `GtkPaperSize`, in
|
||
* units of @unit.
|
||
*
|
||
* Returns: the paper height
|
||
*/
|
||
double
|
||
gtk_paper_size_get_height (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
return _gtk_print_convert_from_mm (size->height, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_is_custom:
|
||
* @size: a `GtkPaperSize` object
|
||
*
|
||
* Returns %TRUE if @size is not a standard paper size.
|
||
*
|
||
* Returns: whether @size is a custom paper size.
|
||
**/
|
||
gboolean
|
||
gtk_paper_size_is_custom (GtkPaperSize *size)
|
||
{
|
||
return size->is_custom;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_is_ipp:
|
||
* @size: a `GtkPaperSize` object
|
||
*
|
||
* Returns %TRUE if @size is an IPP standard paper size.
|
||
*
|
||
* Returns: whether @size is not an IPP custom paper size.
|
||
**/
|
||
gboolean
|
||
gtk_paper_size_is_ipp (GtkPaperSize *size)
|
||
{
|
||
return size->is_ipp;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_set_size:
|
||
* @size: a custom `GtkPaperSize` object
|
||
* @width: the new width in units of @unit
|
||
* @height: the new height in units of @unit
|
||
* @unit: the unit for @width and @height
|
||
*
|
||
* Changes the dimensions of a @size to @width x @height.
|
||
*/
|
||
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);
|
||
|
||
size->width = _gtk_print_convert_to_mm (width, unit);
|
||
size->height = _gtk_print_convert_to_mm (height, unit);
|
||
}
|
||
|
||
#define NL_PAPER_GET(x) \
|
||
((union { char *string; unsigned int word; })nl_langinfo(x)).word
|
||
|
||
/**
|
||
* gtk_paper_size_get_default:
|
||
*
|
||
* Returns the name of the default paper size, which
|
||
* depends on the current locale.
|
||
*
|
||
* Returns: the name of the default paper size. The string
|
||
* is owned by GTK and should not be modified.
|
||
*/
|
||
const char *
|
||
gtk_paper_size_get_default (void)
|
||
{
|
||
char *locale, *freeme = NULL;
|
||
const char *paper_size;
|
||
|
||
#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 G_OS_WIN32
|
||
freeme = locale = g_win32_getlocale ();
|
||
#elif defined(LC_PAPER)
|
||
locale = setlocale(LC_PAPER, NULL);
|
||
#else
|
||
locale = setlocale(LC_MESSAGES, NULL);
|
||
#endif
|
||
|
||
if (!locale)
|
||
return GTK_PAPER_NAME_A4;
|
||
|
||
/* CLDR 1.8.1
|
||
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/territory_language_information.html
|
||
*/
|
||
if (g_regex_match_simple("[^_.@]{2,3}_(BZ|CA|CL|CO|CR|GT|MX|NI|PA|PH|PR|SV|US|VE)",
|
||
locale, G_REGEX_ANCHORED, G_REGEX_MATCH_ANCHORED))
|
||
paper_size = GTK_PAPER_NAME_LETTER;
|
||
else
|
||
paper_size = GTK_PAPER_NAME_A4;
|
||
|
||
g_free (freeme);
|
||
return paper_size;
|
||
}
|
||
|
||
/* 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.
|
||
*/
|
||
|
||
/**
|
||
* gtk_paper_size_get_default_top_margin:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the default top margin for the `GtkPaperSize`.
|
||
*
|
||
* Returns: the default top margin
|
||
*/
|
||
double
|
||
gtk_paper_size_get_default_top_margin (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
double margin;
|
||
|
||
margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
|
||
return _gtk_print_convert_from_mm (margin, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_default_bottom_margin:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the default bottom margin for the `GtkPaperSize`.
|
||
*
|
||
* Returns: the default bottom margin
|
||
*/
|
||
double
|
||
gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
double margin;
|
||
const char *name;
|
||
|
||
margin = _gtk_print_convert_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 = _gtk_print_convert_to_mm (0.56, GTK_UNIT_INCH);
|
||
|
||
return _gtk_print_convert_from_mm (margin, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_default_left_margin:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the default left margin for the `GtkPaperSize`.
|
||
*
|
||
* Returns: the default left margin
|
||
*/
|
||
double
|
||
gtk_paper_size_get_default_left_margin (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
double margin;
|
||
|
||
margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
|
||
return _gtk_print_convert_from_mm (margin, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_get_default_right_margin:
|
||
* @size: a `GtkPaperSize` object
|
||
* @unit: the unit for the return value, not %GTK_UNIT_NONE
|
||
*
|
||
* Gets the default right margin for the `GtkPaperSize`.
|
||
*
|
||
* Returns: the default right margin
|
||
*/
|
||
double
|
||
gtk_paper_size_get_default_right_margin (GtkPaperSize *size,
|
||
GtkUnit unit)
|
||
{
|
||
double margin;
|
||
|
||
margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
|
||
return _gtk_print_convert_from_mm (margin, unit);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_new_from_key_file:
|
||
* @key_file: the `GKeyFile` to retrieve the papersize from
|
||
* @group_name: (nullable): the name of the group in the key file to read,
|
||
* or %NULL to read the first group
|
||
* @error: (nullable): return location for an error
|
||
*
|
||
* Reads a paper size from the group @group_name in the key file
|
||
* @key_file.
|
||
*
|
||
* Returns: a new `GtkPaperSize` object with the restored paper size
|
||
*/
|
||
GtkPaperSize *
|
||
gtk_paper_size_new_from_key_file (GKeyFile *key_file,
|
||
const char *group_name,
|
||
GError **error)
|
||
{
|
||
GtkPaperSize *paper_size = NULL;
|
||
char *name = NULL;
|
||
char *ppd_name = NULL;
|
||
char *display_name = NULL;
|
||
char *freeme = NULL;
|
||
double width, height;
|
||
GError *err = NULL;
|
||
|
||
g_return_val_if_fail (key_file != NULL, NULL);
|
||
|
||
if (!group_name)
|
||
group_name = freeme = g_key_file_get_start_group (key_file);
|
||
if (!group_name || !g_key_file_has_group (key_file, group_name))
|
||
{
|
||
g_set_error_literal (error,
|
||
GTK_PRINT_ERROR,
|
||
GTK_PRINT_ERROR_INVALID_FILE,
|
||
_("Not a valid page setup file"));
|
||
goto out;
|
||
}
|
||
|
||
#define GET_DOUBLE(kf, group, name, v) \
|
||
v = g_key_file_get_double (kf, group, name, &err); \
|
||
if (err != NULL) \
|
||
{\
|
||
g_propagate_error (error, err);\
|
||
goto out;\
|
||
}
|
||
|
||
GET_DOUBLE (key_file, group_name, "Width", width);
|
||
GET_DOUBLE (key_file, group_name, "Height", height);
|
||
|
||
#undef GET_DOUBLE
|
||
|
||
name = g_key_file_get_string (key_file, group_name,
|
||
"Name", NULL);
|
||
ppd_name = g_key_file_get_string (key_file, group_name,
|
||
"PPDName", NULL);
|
||
display_name = g_key_file_get_string (key_file, group_name,
|
||
"DisplayName", NULL);
|
||
/* Fallback for old ~/.gtk-custom-paper entries */
|
||
if (!display_name)
|
||
display_name = g_strdup (name);
|
||
|
||
if (ppd_name != NULL)
|
||
paper_size = gtk_paper_size_new_from_ppd (ppd_name,
|
||
display_name,
|
||
_gtk_print_convert_from_mm (width, GTK_UNIT_POINTS),
|
||
_gtk_print_convert_from_mm (height, GTK_UNIT_POINTS));
|
||
else if (name != NULL)
|
||
paper_size = gtk_paper_size_new_custom (name, display_name,
|
||
width, height, GTK_UNIT_MM);
|
||
else
|
||
{
|
||
g_set_error_literal (error,
|
||
GTK_PRINT_ERROR,
|
||
GTK_PRINT_ERROR_INVALID_FILE,
|
||
_("Not a valid page setup file"));
|
||
goto out;
|
||
}
|
||
|
||
g_assert (paper_size != NULL);
|
||
|
||
out:
|
||
g_free (ppd_name);
|
||
g_free (name);
|
||
g_free (display_name);
|
||
g_free (freeme);
|
||
|
||
return paper_size;
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_to_key_file:
|
||
* @size: a `GtkPaperSize`
|
||
* @key_file: the `GKeyFile` to save the paper size to
|
||
* @group_name: the group to add the settings to in @key_file
|
||
*
|
||
* This function adds the paper size from @size to @key_file.
|
||
*/
|
||
void
|
||
gtk_paper_size_to_key_file (GtkPaperSize *size,
|
||
GKeyFile *key_file,
|
||
const char *group_name)
|
||
{
|
||
const char *name, *ppd_name, *display_name;
|
||
|
||
g_return_if_fail (size != NULL);
|
||
g_return_if_fail (key_file != NULL);
|
||
|
||
name = gtk_paper_size_get_name (size);
|
||
display_name = gtk_paper_size_get_display_name (size);
|
||
ppd_name = gtk_paper_size_get_ppd_name (size);
|
||
|
||
if (ppd_name != NULL)
|
||
g_key_file_set_string (key_file, group_name,
|
||
"PPDName", ppd_name);
|
||
else
|
||
g_key_file_set_string (key_file, group_name,
|
||
"Name", name);
|
||
|
||
if (display_name)
|
||
g_key_file_set_string (key_file, group_name,
|
||
"DisplayName", display_name);
|
||
|
||
g_key_file_set_double (key_file, group_name,
|
||
"Width", gtk_paper_size_get_width (size, GTK_UNIT_MM));
|
||
g_key_file_set_double (key_file, group_name,
|
||
"Height", gtk_paper_size_get_height (size, GTK_UNIT_MM));
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_to_gvariant:
|
||
* @paper_size: a `GtkPaperSize`
|
||
*
|
||
* Serialize a paper size to an `a{sv}` variant.
|
||
*
|
||
* Returns: (transfer none): a new, floating, `GVariant`
|
||
*/
|
||
GVariant *
|
||
gtk_paper_size_to_gvariant (GtkPaperSize *paper_size)
|
||
{
|
||
const char *name;
|
||
const char *ppd_name;
|
||
const char *display_name;
|
||
GVariantBuilder builder;
|
||
|
||
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
||
|
||
name = gtk_paper_size_get_name (paper_size);
|
||
ppd_name = gtk_paper_size_get_ppd_name (paper_size);
|
||
display_name = gtk_paper_size_get_display_name (paper_size);
|
||
|
||
if (ppd_name != NULL)
|
||
g_variant_builder_add (&builder, "{sv}", "PPDName", g_variant_new_string (ppd_name));
|
||
else
|
||
g_variant_builder_add (&builder, "{sv}", "Name", g_variant_new_string (name));
|
||
|
||
if (display_name != NULL)
|
||
g_variant_builder_add (&builder, "{sv}", "DisplayName", g_variant_new_string (display_name));
|
||
|
||
g_variant_builder_add (&builder, "{sv}", "Width", g_variant_new_double (gtk_paper_size_get_width (paper_size, GTK_UNIT_MM)));
|
||
g_variant_builder_add (&builder, "{sv}", "Height", g_variant_new_double (gtk_paper_size_get_height (paper_size, GTK_UNIT_MM)));
|
||
|
||
return g_variant_builder_end (&builder);
|
||
}
|
||
|
||
/**
|
||
* gtk_paper_size_new_from_gvariant:
|
||
* @variant: an a{sv} `GVariant`
|
||
*
|
||
* Deserialize a paper size from a `GVariant`.
|
||
*
|
||
* The `GVariant must be in the format produced by
|
||
* [method@Gtk.PaperSize.to_gvariant].
|
||
*
|
||
* Returns: (transfer full): a new `GtkPaperSize` object
|
||
*/
|
||
GtkPaperSize *
|
||
gtk_paper_size_new_from_gvariant (GVariant *variant)
|
||
{
|
||
GtkPaperSize *paper_size;
|
||
const char *name;
|
||
const char *ppd_name;
|
||
const char *display_name;
|
||
double width, height;
|
||
|
||
g_return_val_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT), NULL);
|
||
|
||
if (!g_variant_lookup (variant, "Width", "d", &width) ||
|
||
!g_variant_lookup (variant, "Height", "d", &height))
|
||
return NULL;
|
||
|
||
if (!g_variant_lookup (variant, "Name", "&s", &name))
|
||
name = NULL;
|
||
|
||
if (!g_variant_lookup (variant, "PPDName", "&s", &ppd_name))
|
||
ppd_name = NULL;
|
||
|
||
if (!g_variant_lookup (variant, "DisplayName", "&s", &display_name))
|
||
display_name = name;
|
||
|
||
if (ppd_name != NULL)
|
||
paper_size = gtk_paper_size_new_from_ppd (ppd_name,
|
||
display_name,
|
||
_gtk_print_convert_from_mm (width, GTK_UNIT_POINTS),
|
||
_gtk_print_convert_from_mm (height, GTK_UNIT_POINTS));
|
||
else if (name != NULL)
|
||
paper_size = gtk_paper_size_new_custom (name, display_name,
|
||
width, height, GTK_UNIT_MM);
|
||
else
|
||
paper_size = NULL;
|
||
|
||
return paper_size;
|
||
}
|