gtkpapersize.c 24 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3
 * gtkpapersize.c: Paper Size
 * Copyright (C) 2006, Red Hat, Inc.
4
 * Copyright © 2006, 2007 Christian Persch
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * 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>
#if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
#include <langinfo.h>
#endif

#include "gtkpapersize.h"
Matthias Clasen's avatar
Matthias Clasen committed
31
#include "gtkprintutils.h"
Matthias Clasen's avatar
Matthias Clasen committed
32
#include "gtkprintoperation.h"  /* for GtkPrintError */
33
#include "gtkintl.h"
34 35 36

#include "paper_names_offsets.c"

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

/**
 * SECTION:gtkpapersize
 * @Short_description: Support for named paper sizes
 * @Title: GtkPaperSize
 * @See_also:#GtkPageSetup
 *
 * GtkPaperSize handles paper sizes. It uses the standard called
 * <ulink url="http://www.pwg.org/standards.html">"PWG 5101.1-2002 PWG: Standard for Media Standardized Names"</ulink>
 * 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 <link linkend="print-margins">print margins</link>.
 *
 * Printing support has been added in GTK+ 2.10.
 */


58 59 60 61 62
struct _GtkPaperSize
{
  const PaperInfo *info;

  /* If these are not set we fall back to info */
63 64 65
  gchar *name;
  gchar *display_name;
  gchar *ppd_name;
66

67
  gdouble width, height; /* Stored in mm */
68 69 70
  gboolean is_custom;
};

71 72 73
G_DEFINE_BOXED_TYPE (GtkPaperSize, gtk_paper_size,
                     gtk_paper_size_copy,
                     gtk_paper_size_free)
74

75 76
static const PaperInfo *
lookup_paper_info (const gchar *name)
77 78 79 80 81 82
{
  int lower = 0;
  int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
  int mid;
  int cmp;

83
  do
84 85 86 87 88 89 90 91
    {
       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
92
         return &standard_names_offsets[mid];
93 94 95 96 97 98 99
    }
  while (lower <= upper);

  return NULL;
}

static gboolean
100
parse_media_size (const gchar *size,
101 102
                  gdouble     *width_mm,
                  gdouble     *height_mm)
103 104 105 106 107 108
{
  const char *p;
  char *e;
  double short_dim, long_dim;

  p = size;
109

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
  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;
136 137

  return TRUE;
138 139 140
}

static gboolean
141
parse_full_media_size_name (const gchar  *full_name,
142 143 144
                            gchar       **name,
                            gdouble      *width_mm,
                            gdouble      *height_mm)
145 146 147
{
  const char *p;
  const char *end_of_name;
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  /* 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 _ */
173

174 175 176 177 178 179 180 181 182 183 184 185 186
  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);
187 188

  return TRUE;
189 190 191 192 193 194
}

static GtkPaperSize *
gtk_paper_size_new_from_info (const PaperInfo *info)
{
  GtkPaperSize *size;
195

196
  size = g_slice_new0 (GtkPaperSize);
197 198 199
  size->info = info;
  size->width = info->width;
  size->height = info->height;
200

201 202 203
  return size;
}

204 205
/**
 * gtk_paper_size_new:
206 207 208
 * @name: (allow-none): a paper size name, or %NULL
 *
 * Creates a new #GtkPaperSize object by parsing a
209
 * <ulink url="ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf">PWG 5101.1-2002</ulink>
210
 * paper name.
211 212 213
 *
 * If @name is %NULL, the default paper size is returned,
 * see gtk_paper_size_get_default().
214
 *
215 216 217 218 219
 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
 * to free it
 *
 * Since: 2.10
 */
220
GtkPaperSize *
221
gtk_paper_size_new (const gchar *name)
222 223 224 225
{
  GtkPaperSize *size;
  char *short_name;
  double width, height;
226
  const PaperInfo *info;
227 228 229

  if (name == NULL)
    name = gtk_paper_size_get_default ();
230

231 232
  if (parse_full_media_size_name (name, &short_name, &width, &height))
    {
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
      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_slice_new0 (GtkPaperSize);

          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;
        }
250 251 252 253 254
    }
  else
    {
      info = lookup_paper_info (name);
      if (info != NULL)
255
        size = gtk_paper_size_new_from_info (info);
256
      else
257 258 259 260 261 262 263 264 265
        {
          g_warning ("Unknown paper size %s\n", name);
          size = g_slice_new0 (GtkPaperSize);
          size->name = g_strdup (name);
          size->display_name = g_strdup (name);
          /* Default to A4 size */
          size->width = 210;
          size->height = 297;
        }
266
    }
267

268 269 270
  return size;
}

271 272 273 274 275 276
/**
 * 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
277 278 279 280 281 282
 *
 * 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
283 284 285 286 287 288 289
 * construct a custom #GtkPaperSize object.
 *
 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
 * to free it
 *
 * Since: 2.10
 */
290
GtkPaperSize *
291
gtk_paper_size_new_from_ppd (const gchar *ppd_name,
292 293 294
                             const gchar *ppd_display_name,
                             gdouble      width,
                             gdouble      height)
295 296 297 298 299 300 301 302
{
  char *name;
  const char *lookup_ppd_name;
  char *freeme;
  GtkPaperSize *size;
  int i;

  lookup_ppd_name = ppd_name;
303

304 305 306 307 308
  freeme = NULL;
  /* Strip out Traverse suffix in matching. */
  if (g_str_has_suffix (ppd_name, ".Transverse"))
    {
      lookup_ppd_name = freeme =
309
        g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
310
    }
311

312 313 314
  for (i = 0; i < G_N_ELEMENTS(standard_names_offsets); i++)
    {
      if (standard_names_offsets[i].ppd_name != -1 &&
315 316 317 318 319
          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;
        }
320
    }
321

322 323 324
  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)
325 326 327 328
        {
          size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
          goto out;
        }
329 330
    }

331
  name = g_strconcat ("ppd_", ppd_name, NULL);
332 333 334 335 336 337 338 339 340
  size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
  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);
341

342
  g_free (freeme);
343

344 345 346
  return size;
}

347 348
/**
 * gtk_paper_size_new_custom:
349
 * @name: the paper name
350 351 352 353
 * @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
354
 *
355 356
 * Creates a new #GtkPaperSize object with the
 * given parameters.
357
 *
358 359 360 361 362
 * Return value: a new #GtkPaperSize object, use gtk_paper_size_free()
 * to free it
 *
 * Since: 2.10
 */
363
GtkPaperSize *
364 365 366 367 368
gtk_paper_size_new_custom (const gchar *name,
                           const gchar *display_name,
                           gdouble      width,
                           gdouble      height,
                           GtkUnit      unit)
369 370 371 372 373
{
  GtkPaperSize *size;
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (unit != GTK_UNIT_PIXEL, NULL);

374
  size = g_slice_new0 (GtkPaperSize);
375

376 377 378
  size->name = g_strdup (name);
  size->display_name = g_strdup (display_name);
  size->is_custom = TRUE;
379

Matthias Clasen's avatar
Matthias Clasen committed
380 381
  size->width = _gtk_print_convert_to_mm (width, unit);
  size->height = _gtk_print_convert_to_mm (height, unit);
382

383 384 385
  return size;
}

386 387 388
/**
 * gtk_paper_size_copy:
 * @other: a #GtkPaperSize
389
 *
390
 * Copies an existing #GtkPaperSize.
391
 *
392 393 394 395
 * Return value: a copy of @other
 *
 * Since: 2.10
 */
396 397 398 399 400
GtkPaperSize *
gtk_paper_size_copy (GtkPaperSize *other)
{
  GtkPaperSize *size;

401
  size = g_slice_new0 (GtkPaperSize);
402 403 404 405 406 407 408 409

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

411 412 413 414 415 416 417
  size->width = other->width;
  size->height = other->height;
  size->is_custom = other->is_custom;

  return size;
}

418 419 420
/**
 * gtk_paper_size_free:
 * @size: a #GtkPaperSize
421
 *
422 423 424 425
 * Free the given #GtkPaperSize object.
 *
 * Since: 2.10
 */
426 427 428 429 430 431
void
gtk_paper_size_free (GtkPaperSize *size)
{
  g_free (size->name);
  g_free (size->display_name);
  g_free (size->ppd_name);
432 433

  g_slice_free (GtkPaperSize, size);
434 435
}

436 437 438
/**
 * gtk_paper_size_is_equal:
 * @size1: a #GtkPaperSize object
439
 * @size2: another #GtkPaperSize object
440
 *
441
 * Compares two #GtkPaperSize objects.
442 443
 *
 * Return value: %TRUE, if @size1 and @size2
444 445 446 447
 * represent the same paper size
 *
 * Since: 2.10
 */
448 449
gboolean
gtk_paper_size_is_equal (GtkPaperSize *size1,
450
                         GtkPaperSize *size2)
451 452 453
{
  if (size1->info != NULL && size2->info != NULL)
    return size1->info == size2->info;
454

455
  return strcmp (gtk_paper_size_get_name (size1),
456
                 gtk_paper_size_get_name (size2)) == 0;
457
}
458

459 460
GList * _gtk_load_custom_papers (void);

461
/**
462 463 464
 * gtk_paper_size_get_paper_sizes:
 * @include_custom: whether to include custom paper sizes
 *     as defined in the page setup dialog
465
 *
466
 * Creates a list of known paper sizes.
467 468
 *
 * Return value:  (element-type GtkPaperSize) (transfer full): a newly allocated list of newly
469 470 471 472 473
 *    allocated #GtkPaperSize objects
 *
 * Since: 2.12
 */
GList *
474
gtk_paper_size_get_paper_sizes (gboolean include_custom)
475 476 477
{
  GList *list = NULL;
  guint i;
478
#ifdef G_OS_UNIX                /* _gtk_load_custom_papers() only on Unix so far  */
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
  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_foreach (page_setups, (GFunc) g_object_unref, NULL);
      g_list_free (page_setups);
    }
496
#endif
497 498 499 500 501 502 503 504
  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);
    }

505
  return g_list_reverse (list);
506 507
}

508

509 510 511
/**
 * gtk_paper_size_get_name:
 * @size: a #GtkPaperSize object
512
 *
513
 * Gets the name of the #GtkPaperSize.
514
 *
515 516 517 518
 * Return value: the name of @size
 *
 * Since: 2.10
 */
519
const gchar *
520 521 522 523 524 525 526 527
gtk_paper_size_get_name (GtkPaperSize *size)
{
  if (size->name)
    return size->name;
  g_assert (size->info != NULL);
  return paper_names + size->info->name;
}

528 529 530
/**
 * gtk_paper_size_get_display_name:
 * @size: a #GtkPaperSize object
531
 *
532
 * Gets the human-readable name of the #GtkPaperSize.
533
 *
534 535 536 537
 * Return value: the human-readable name of @size
 *
 * Since: 2.10
 */
538
const gchar *
539 540
gtk_paper_size_get_display_name (GtkPaperSize *size)
{
541 542
  const gchar *display_name;

543 544
  if (size->display_name)
    return size->display_name;
545

546
  g_assert (size->info != NULL);
547 548

  display_name = paper_names + size->info->display_name;
549
  return g_dpgettext2 (GETTEXT_PACKAGE, "paper size", display_name);
550 551
}

552 553 554
/**
 * gtk_paper_size_get_ppd_name:
 * @size: a #GtkPaperSize object
555
 *
556 557
 * Gets the PPD name of the #GtkPaperSize, which
 * may be %NULL.
558
 *
559 560 561 562
 * Return value: the PPD name of @size
 *
 * Since: 2.10
 */
563
const gchar *
564 565 566 567 568 569 570 571 572
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;
}

573 574 575 576
/**
 * gtk_paper_size_get_width:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
577 578
 *
 * Gets the paper width of the #GtkPaperSize, in
579
 * units of @unit.
580 581
 *
 * Return value: the paper width
582 583 584 585
 *
 * Since: 2.10
 */
gdouble
586 587
gtk_paper_size_get_width (GtkPaperSize *size,
                          GtkUnit       unit)
588
{
Matthias Clasen's avatar
Matthias Clasen committed
589
  return _gtk_print_convert_from_mm (size->width, unit);
590
}
591 592 593 594 595

/**
 * gtk_paper_size_get_height:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
596 597
 *
 * Gets the paper height of the #GtkPaperSize, in
598
 * units of @unit.
599 600
 *
 * Return value: the paper height
601 602 603 604
 *
 * Since: 2.10
 */
gdouble
605 606
gtk_paper_size_get_height (GtkPaperSize *size,
                           GtkUnit       unit)
607
{
Matthias Clasen's avatar
Matthias Clasen committed
608
  return _gtk_print_convert_from_mm (size->height, unit);
609 610
}

611 612 613
/**
 * gtk_paper_size_is_custom:
 * @size: a #GtkPaperSize object
614
 *
615
 * Returns %TRUE if @size is not a standard paper size.
616
 *
617 618
 * Return value: whether @size is a custom paper size.
 **/
619 620 621 622 623 624
gboolean
gtk_paper_size_is_custom (GtkPaperSize *size)
{
  return size->is_custom;
}

625 626 627 628 629 630
/**
 * 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
631
 *
632 633 634 635
 * Changes the dimensions of a @size to @width x @height.
 *
 * Since: 2.10
 */
636
void
637 638 639 640
gtk_paper_size_set_size (GtkPaperSize *size,
                         gdouble       width,
                         gdouble       height,
                         GtkUnit       unit)
641 642 643 644
{
  g_return_if_fail (size != NULL);
  g_return_if_fail (size->is_custom);

Matthias Clasen's avatar
Matthias Clasen committed
645 646
  size->width = _gtk_print_convert_to_mm (width, unit);
  size->height = _gtk_print_convert_to_mm (height, unit);
647 648 649 650 651
}

#define NL_PAPER_GET(x)         \
  ((union { char *string; unsigned int word; })nl_langinfo(x)).word

652 653 654
/**
 * gtk_paper_size_get_default:
 *
655 656 657
 * Returns the name of the default paper size, which
 * depends on the current locale.
 *
658 659
 * Return value: the name of the default paper size. The string
 * is owned by GTK+ and should not be modified.
660
 *
661 662
 * Since: 2.10
 */
663
const gchar *
664 665 666 667 668 669 670 671 672
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);
673

674 675
    if (width == 210 && height == 297)
      return GTK_PAPER_NAME_A4;
676

677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
    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;

693 694 695 696 697
  /* 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))
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
    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):
713
 *
714 715 716 717 718 719
 * 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.
 */

720 721 722 723
/**
 * gtk_paper_size_get_default_top_margin:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
724
 *
725
 * Gets the default top margin for the #GtkPaperSize.
726
 *
727 728 729 730 731
 * Return value: the default top margin
 *
 * Since: 2.10
 */
gdouble
732 733
gtk_paper_size_get_default_top_margin (GtkPaperSize *size,
                                       GtkUnit       unit)
734
{
735
  gdouble margin;
736

Matthias Clasen's avatar
Matthias Clasen committed
737 738
  margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
  return _gtk_print_convert_from_mm (margin, unit);
739 740
}

741 742 743 744
/**
 * gtk_paper_size_get_default_bottom_margin:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
745
 *
746
 * Gets the default bottom margin for the #GtkPaperSize.
747
 *
748 749 750 751 752
 * Return value: the default bottom margin
 *
 * Since: 2.10
 */
gdouble
753 754
gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size,
                                          GtkUnit       unit)
755
{
756 757
  gdouble margin;
  const gchar *name;
758

Matthias Clasen's avatar
Matthias Clasen committed
759
  margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
760 761 762 763 764

  name = gtk_paper_size_get_name (size);
  if (strcmp (name, "na_letter") == 0 ||
      strcmp (name, "na_legal") == 0 ||
      strcmp (name, "iso_a4") == 0)
Matthias Clasen's avatar
Matthias Clasen committed
765
    margin = _gtk_print_convert_to_mm (0.56, GTK_UNIT_INCH);
766

Matthias Clasen's avatar
Matthias Clasen committed
767
  return _gtk_print_convert_from_mm (margin, unit);
768 769
}

770 771 772 773
/**
 * gtk_paper_size_get_default_left_margin:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
774
 *
775
 * Gets the default left margin for the #GtkPaperSize.
776
 *
777 778 779 780 781
 * Return value: the default left margin
 *
 * Since: 2.10
 */
gdouble
782 783
gtk_paper_size_get_default_left_margin (GtkPaperSize *size,
                                        GtkUnit       unit)
784
{
785
  gdouble margin;
786

Matthias Clasen's avatar
Matthias Clasen committed
787 788
  margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
  return _gtk_print_convert_from_mm (margin, unit);
789 790
}

791 792 793 794
/**
 * gtk_paper_size_get_default_right_margin:
 * @size: a #GtkPaperSize object
 * @unit: the unit for the return value
795
 *
796
 * Gets the default right margin for the #GtkPaperSize.
797
 *
798 799 800 801 802
 * Return value: the default right margin
 *
 * Since: 2.10
 */
gdouble
803 804
gtk_paper_size_get_default_right_margin (GtkPaperSize *size,
                                         GtkUnit       unit)
805
{
806
  gdouble margin;
807

Matthias Clasen's avatar
Matthias Clasen committed
808 809
  margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
  return _gtk_print_convert_from_mm (margin, unit);
810 811
}

Matthias Clasen's avatar
Matthias Clasen committed
812 813 814 815 816
/**
 * gtk_paper_size_new_from_key_file:
 * @key_file: the #GKeyFile to retrieve the papersize from
 * @group_name: the name ofthe group in the key file to read,
 *     or %NULL to read the first group
817
 * @error: (allow-none): return location for an error, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
818 819
 *
 * Reads a paper size from the group @group_name in the key file
820
 * @key_file.
Matthias Clasen's avatar
Matthias Clasen committed
821 822
 *
 * Returns: a new #GtkPaperSize object with the restored
823
 *     paper size, or %NULL if an error occurred
Matthias Clasen's avatar
Matthias Clasen committed
824 825 826 827
 *
 * Since: 2.12
 */
GtkPaperSize *
828 829 830
gtk_paper_size_new_from_key_file (GKeyFile     *key_file,
                                  const gchar  *group_name,
                                  GError      **error)
Matthias Clasen's avatar
Matthias Clasen committed
831 832
{
  GtkPaperSize *paper_size = NULL;
833 834 835 836
  gchar *name = NULL;
  gchar *ppd_name = NULL;
  gchar *display_name = NULL;
  gchar *freeme = NULL;
Matthias Clasen's avatar
Matthias Clasen committed
837 838 839 840 841 842 843 844 845
  gdouble 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))
    {
846 847 848 849
      g_set_error_literal (error,
                           GTK_PRINT_ERROR,
                           GTK_PRINT_ERROR_INVALID_FILE,
                           _("Not a valid page setup file"));
Matthias Clasen's avatar
Matthias Clasen committed
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
      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,
867
                                "Name", NULL);
Matthias Clasen's avatar
Matthias Clasen committed
868
  ppd_name = g_key_file_get_string (key_file, group_name,
869
                                    "PPDName", NULL);
Matthias Clasen's avatar
Matthias Clasen committed
870
  display_name = g_key_file_get_string (key_file, group_name,
871
                                        "DisplayName", NULL);
Matthias Clasen's avatar
Matthias Clasen committed
872 873 874 875 876
  /* Fallback for old ~/.gtk-custom-paper entries */
  if (!display_name)
    display_name = g_strdup (name);

  if (ppd_name != NULL)
877 878 879 880
    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));
Matthias Clasen's avatar
Matthias Clasen committed
881 882
  else if (name != NULL)
    paper_size = gtk_paper_size_new_custom (name, display_name,
883
                                            width, height, GTK_UNIT_MM);
Matthias Clasen's avatar
Matthias Clasen committed
884 885
  else
    {
886 887 888 889
      g_set_error_literal (error,
                           GTK_PRINT_ERROR,
                           GTK_PRINT_ERROR_INVALID_FILE,
                           _("Not a valid page setup file"));
Matthias Clasen's avatar
Matthias Clasen committed
890 891
      goto out;
    }
892

Matthias Clasen's avatar
Matthias Clasen committed
893 894 895 896 897 898 899 900 901 902 903 904 905
  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:
Matthias Clasen's avatar
Matthias Clasen committed
906
 * @size: a #GtkPaperSize
Matthias Clasen's avatar
Matthias Clasen committed
907 908 909
 * @key_file: the #GKeyFile to save the paper size to
 * @group_name: the group to add the settings to in @key_file
 *
Matthias Clasen's avatar
Matthias Clasen committed
910
 * This function adds the paper size from @size to @key_file.
Matthias Clasen's avatar
Matthias Clasen committed
911 912 913 914
 *
 * Since: 2.12
 */
void
Matthias Clasen's avatar
Matthias Clasen committed
915
gtk_paper_size_to_key_file (GtkPaperSize *size,
916 917
                            GKeyFile     *key_file,
                            const gchar  *group_name)
Matthias Clasen's avatar
Matthias Clasen committed
918 919 920
{
  const char *name, *ppd_name, *display_name;

Matthias Clasen's avatar
Matthias Clasen committed
921
  g_return_if_fail (size != NULL);
Matthias Clasen's avatar
Matthias Clasen committed
922 923
  g_return_if_fail (key_file != NULL);

Matthias Clasen's avatar
Matthias Clasen committed
924 925 926
  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);
Matthias Clasen's avatar
Matthias Clasen committed
927

928
  if (ppd_name != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
929
    g_key_file_set_string (key_file, group_name,
930
                           "PPDName", ppd_name);
Matthias Clasen's avatar
Matthias Clasen committed
931 932
  else
    g_key_file_set_string (key_file, group_name,
933
                           "Name", name);
Matthias Clasen's avatar
Matthias Clasen committed
934

935
  if (display_name)
Matthias Clasen's avatar
Matthias Clasen committed
936
    g_key_file_set_string (key_file, group_name,
937
                           "DisplayName", display_name);
Matthias Clasen's avatar
Matthias Clasen committed
938 939

  g_key_file_set_double (key_file, group_name,
940
                         "Width", gtk_paper_size_get_width (size, GTK_UNIT_MM));
Matthias Clasen's avatar
Matthias Clasen committed
941
  g_key_file_set_double (key_file, group_name,
942
                         "Height", gtk_paper_size_get_height (size, GTK_UNIT_MM));
Matthias Clasen's avatar
Matthias Clasen committed
943
}