[gtk+] Get paper sizes from IPP query



commit e78c3e2c8c0a5c48516d02d7b084c7bc15e9d112
Author: Marek Kasik <mkasik redhat com>
Date:   Thu Oct 2 13:50:47 2014 +0200

    Get paper sizes from IPP query
    
    Query printer via IPP for paper sizes if there is no
    or empty PPD file.
    Parse "media-supported" and "media-size-supported" attributes for list
    of paper sizes. Parse "media-default" and "media-col-default" attributes
    for default settings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=725441

 modules/printbackends/cups/gtkprintbackendcups.c |  404 ++++++++++++++++++----
 modules/printbackends/cups/gtkprintercups.c      |   12 +
 modules/printbackends/cups/gtkprintercups.h      |    9 +
 3 files changed, 360 insertions(+), 65 deletions(-)
---
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c 
b/modules/printbackends/cups/gtkprintbackendcups.c
index 1c69b6b..7cdb43e 100644
--- a/modules/printbackends/cups/gtkprintbackendcups.c
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -56,6 +56,8 @@
 #include "gtkcupsutils.h"
 #include "gtkcupssecretsutils.h"
 
+#include <gtkprintutils.h>
+
 #ifdef HAVE_COLORD
 #include <colord.h>
 #endif
@@ -1858,6 +1860,39 @@ static const char * const printer_attrs[] =
     "number-up-supported"
   };
 
+/* Attributes we're interested in for printers without PPD */
+static const char * const printer_attrs_detailed[] =
+  {
+    "printer-name",
+    "printer-uri-supported",
+    "member-uris",
+    "printer-location",
+    "printer-info",
+    "printer-state-message",
+    "printer-state-reasons",
+    "printer-state",
+    "queued-job-count",
+    "printer-is-accepting-jobs",
+    "job-sheets-supported",
+    "job-sheets-default",
+    "printer-type",
+    "auth-info-required",
+    "number-up-default",
+    "ipp-versions-supported",
+    "multiple-document-handling-supported",
+    "copies-supported",
+    "number-up-supported"
+    "media-col-default",
+    "media-col-supported",
+    "media-default",
+    "media-size-supported",
+    "media-supported",
+    "media-left-margin-supported",
+    "media-right-margin-supported",
+    "media-bottom-margin-supported",
+    "media-top-margin-supported",
+  };
+
 typedef enum
   {
     GTK_PRINTER_STATE_LEVEL_NONE = 0,
@@ -1868,6 +1903,12 @@ typedef enum
 
 typedef struct
 {
+  float x_dimension;
+  float y_dimension;
+} MediaSize;
+
+typedef struct
+{
   const gchar *printer_name;
   const gchar *printer_uri;
   const gchar *member_uris;
@@ -1895,6 +1936,14 @@ typedef struct
   gboolean supports_copies;
   gboolean supports_collate;
   gboolean supports_number_up;
+  gchar    *media_default;
+  GList    *media_supported;
+  GList    *media_size_supported;
+  float     media_bottom_margin_default;
+  float     media_top_margin_default;
+  float     media_left_margin_default;
+  float     media_right_margin_default;
+  gboolean  media_margin_default_set;
 } PrinterSetupInfo;
 
 static void
@@ -2151,6 +2200,103 @@ cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend,
             }
         }
     }
+  else if (g_strcmp0 (ippGetName (attr), "media-default") == 0)
+    {
+      if (ippGetValueTag (attr) == IPP_TAG_KEYWORD ||
+          ippGetValueTag (attr) == IPP_TAG_NAME)
+        info->media_default = g_strdup (ippGetString (attr, 0, NULL));
+    }
+  else if (g_strcmp0 (ippGetName (attr), "media-col-default") == 0)
+    {
+      ipp_attribute_t *iter;
+      ipp_t           *col;
+      gint             num_of_margins = 0;
+
+      for (i = 0; i < ippGetCount (attr); i++)
+        {
+          col = ippGetCollection (attr, i);
+          for (iter = ippFirstAttribute (col); iter != NULL; iter = ippNextAttribute (col))
+            {
+              switch (ippGetValueTag (iter))
+                {
+                  case IPP_TAG_INTEGER:
+                    if (g_strcmp0 (ippGetName (iter), "media-bottom-margin") == 0)
+                      {
+                        info->media_bottom_margin_default = ippGetInteger (iter, 0) / 100.0;
+                        num_of_margins++;
+                      }
+                    else if (g_strcmp0 (ippGetName (iter), "media-top-margin") == 0)
+                      {
+                        info->media_top_margin_default = ippGetInteger (iter, 0) / 100.0;
+                        num_of_margins++;
+                      }
+                    else if (g_strcmp0 (ippGetName (iter), "media-left-margin") == 0)
+                      {
+                        info->media_left_margin_default = ippGetInteger (iter, 0) / 100.0;
+                        num_of_margins++;
+                      }
+                    else if (g_strcmp0 (ippGetName (iter), "media-right-margin") == 0)
+                      {
+                        info->media_right_margin_default = ippGetInteger (iter, 0) / 100.0;
+                        num_of_margins++;
+                      }
+                    break;
+
+                  default:
+                    break;
+                }
+            }
+        }
+
+      if (num_of_margins == 4)
+        info->media_margin_default_set = TRUE;
+    }
+  else if (g_strcmp0 (ippGetName (attr), "media-supported") == 0)
+    {
+      for (i = 0; i < ippGetCount (attr); i++)
+        info->media_supported = g_list_prepend (info->media_supported, g_strdup (ippGetString (attr, i, 
NULL)));
+
+      info->media_supported = g_list_reverse (info->media_supported);
+    }
+  else if (g_strcmp0 (ippGetName (attr), "media-size-supported") == 0)
+    {
+      ipp_attribute_t *iter;
+      MediaSize       *media_size;
+      gboolean         number_of_dimensions;
+      ipp_t           *media_size_collection;
+
+      for (i = 0; i < ippGetCount (attr); i++)
+        {
+          media_size_collection = ippGetCollection (attr, i);
+          media_size = g_new0 (MediaSize, 1);
+          number_of_dimensions = 0;
+
+          for (iter = ippFirstAttribute (media_size_collection);
+               iter != NULL;
+               iter = ippNextAttribute (media_size_collection))
+            {
+              if (g_strcmp0 (ippGetName (iter), "x-dimension") == 0 &&
+                  ippGetValueTag (iter) == IPP_TAG_INTEGER)
+                {
+                  media_size->x_dimension = ippGetInteger (iter, 0) / 100.0;
+                  number_of_dimensions++;
+                }
+              else if (g_strcmp0 (ippGetName (iter), "y-dimension") == 0 &&
+                  ippGetValueTag (iter) == IPP_TAG_INTEGER)
+                {
+                  media_size->y_dimension = ippGetInteger (iter, 0) / 100.0;
+                  number_of_dimensions++;
+                }
+            }
+
+          if (number_of_dimensions == 2)
+            info->media_size_supported = g_list_prepend (info->media_size_supported, media_size);
+          else
+            g_free (media_size);
+        }
+
+      info->media_size_supported = g_list_reverse (info->media_size_supported);
+    }
   else
     {
       GTK_NOTE (PRINTING,
@@ -2371,9 +2517,9 @@ set_default_printer (GtkPrintBackendCups *cups_backend,
 
 #ifdef HAVE_CUPS_API_1_6
 static void
-cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
-                                    GtkCupsResult       *result,
-                                    gpointer             user_data)
+cups_request_printer_info_cb (GtkPrintBackendCups *cups_backend,
+                              GtkCupsResult       *result,
+                              gpointer             user_data)
 {
   PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
   GtkPrintBackend  *backend = GTK_PRINT_BACKEND (cups_backend);
@@ -2417,7 +2563,7 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
 
           printer = gtk_print_backend_find_printer (backend, info->printer_name);
           if (printer != NULL &&
-              GTK_PRINTER_CUPS (printer)->avahi_browsed)
+              GTK_PRINTER_CUPS (printer)->ppd_file == NULL)
             {
               g_object_ref (printer);
             }
@@ -2449,6 +2595,18 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
 
           set_printer_icon_name_from_info (printer, info);
 
+          GTK_PRINTER_CUPS (printer)->media_default = info->media_default;
+          GTK_PRINTER_CUPS (printer)->media_supported = info->media_supported;
+          GTK_PRINTER_CUPS (printer)->media_size_supported = info->media_size_supported;
+          if (info->media_margin_default_set)
+            {
+              GTK_PRINTER_CUPS (printer)->media_margin_default_set = TRUE;
+              GTK_PRINTER_CUPS (printer)->media_bottom_margin_default = info->media_bottom_margin_default;
+              GTK_PRINTER_CUPS (printer)->media_top_margin_default = info->media_top_margin_default;
+              GTK_PRINTER_CUPS (printer)->media_left_margin_default = info->media_left_margin_default;
+              GTK_PRINTER_CUPS (printer)->media_right_margin_default = info->media_right_margin_default;
+            }
+
           gtk_printer_set_has_details (printer, TRUE);
           g_signal_emit_by_name (printer, "details-acquired", TRUE);
 
@@ -2476,10 +2634,10 @@ done:
 }
 
 static void
-cups_request_avahi_printer_info (const gchar         *printer_uri,
-                                 const gchar         *host,
-                                 gint                 port,
-                                 GtkPrintBackendCups *backend)
+cups_request_printer_info (const gchar         *printer_uri,
+                           const gchar         *host,
+                           gint                 port,
+                           GtkPrintBackendCups *backend)
 {
   GtkCupsRequest *request;
   http_t         *http;
@@ -2501,12 +2659,12 @@ cups_request_avahi_printer_info (const gchar         *printer_uri,
                                        "printer-uri", NULL, printer_uri);
 
       gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
-                                        "requested-attributes", G_N_ELEMENTS (printer_attrs),
-                                        NULL, printer_attrs);
+                                        "requested-attributes", G_N_ELEMENTS (printer_attrs_detailed),
+                                        NULL, printer_attrs_detailed);
 
       cups_request_execute (backend,
                             request,
-                            (GtkPrintCupsResponseCallbackFunc) cups_request_avahi_printer_info_cb,
+                            (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
                             http,
                             (GDestroyNotify) httpClose);
     }
@@ -3423,6 +3581,7 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
                      GetPPDData          *data)
 {
   GtkPrinter *printer;
+  struct stat data_info;
 
   gdk_threads_enter ();
 
@@ -3433,36 +3592,42 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
   GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
   print_backend->reading_ppds--;
 
+#ifdef HAVE_CUPS_API_1_6
+  fstat (g_io_channel_unix_get_fd (data->ppd_io), &data_info);
+  /* Standalone Avahi printers and raw printers don't have PPD files or have
+     empty PPD files. Try to get printer details via IPP. */
+  if (data_info.st_size == 0 ||
+      (gtk_cups_result_is_error (result) &&
+       (GTK_PRINTER_CUPS (printer)->avahi_browsed ||
+        ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
+         (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND)))))
+    {
+      cups_request_printer_info (GTK_PRINTER_CUPS (printer)->printer_uri,
+                                 GTK_PRINTER_CUPS (printer)->hostname,
+                                 GTK_PRINTER_CUPS (printer)->port,
+                                 GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)));
+      goto done;
+    }
+#else
   if (gtk_cups_result_is_error (result))
     {
       gboolean success = FALSE;
 
-#ifdef HAVE_CUPS_API_1_6
-      /* Standalone Avahi printers don't have PPD files. */
-      if (GTK_PRINTER_CUPS (printer)->avahi_browsed)
+      /* If we get a 404 then it is just a raw printer without a ppd
+         and not an error. */
+      if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
+          (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
         {
-          cups_request_avahi_printer_info (GTK_PRINTER_CUPS (printer)->printer_uri,
-                                           GTK_PRINTER_CUPS (printer)->hostname,
-                                           GTK_PRINTER_CUPS (printer)->port,
-                                           GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)));
+          gtk_printer_set_has_details (printer, TRUE);
+          success = TRUE;
         }
-      else
-#endif
-        {
-          /* If we get a 404 then it is just a raw printer without a ppd
-             and not an error. */
-          if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
-              (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
-            {
-              gtk_printer_set_has_details (printer, TRUE);
-              success = TRUE;
-            }
 
-          g_signal_emit_by_name (printer, "details-acquired", success);
-        }
+      g_signal_emit_by_name (printer, "details-acquired", success);
 
       goto done;
     }
+#endif
+
 
   /* let ppdOpenFd take over the ownership of the open file */
   g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
@@ -5727,6 +5892,8 @@ cups_printer_prepare_for_print (GtkPrinter       *printer,
   ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
   if (ppd_paper_name != NULL)
     gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
+  else if (gtk_paper_size_is_ipp (paper_size))
+    gtk_print_settings_set (settings, "cups-media", gtk_paper_size_get_name (paper_size));
   else
     {
       char width[G_ASCII_DTOSTR_BUF_SIZE];
@@ -5822,54 +5989,150 @@ create_page_setup (ppd_file_t *ppd_file,
   return page_setup;
 }
 
+static GtkPageSetup *
+create_page_setup_from_media (gchar     *media,
+                              MediaSize *media_size,
+                              gboolean   media_margin_default_set,
+                              gint       media_bottom_margin_default,
+                              gint       media_top_margin_default,
+                              gint       media_left_margin_default,
+                              gint       media_right_margin_default)
+{
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+
+  page_setup = gtk_page_setup_new ();
+  paper_size = gtk_paper_size_new_from_ipp (media,
+                                            POINTS_PER_INCH * (media_size->x_dimension / MM_PER_INCH),
+                                            POINTS_PER_INCH * (media_size->y_dimension / MM_PER_INCH));
+  gtk_page_setup_set_paper_size (page_setup, paper_size);
+  gtk_paper_size_free (paper_size);
+
+  if (media_margin_default_set)
+    {
+      gtk_page_setup_set_bottom_margin (page_setup, media_bottom_margin_default, GTK_UNIT_MM);
+      gtk_page_setup_set_top_margin (page_setup, media_top_margin_default, GTK_UNIT_MM);
+      gtk_page_setup_set_left_margin (page_setup, media_left_margin_default, GTK_UNIT_MM);
+      gtk_page_setup_set_right_margin (page_setup, media_right_margin_default, GTK_UNIT_MM);
+    }
+
+  return page_setup;
+}
+
 static GList *
 cups_printer_list_papers (GtkPrinter *printer)
 {
   ppd_file_t *ppd_file;
   ppd_size_t *size;
   GtkPageSetup *page_setup;
-  GList *l;
+  GtkPrinterCups *cups_printer = GTK_PRINTER_CUPS (printer);
+  GList *result = NULL;
   int i;
 
-  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
-  if (ppd_file == NULL)
-    return NULL;
-
-  l = NULL;
-
-  for (i = 0; i < ppd_file->num_sizes; i++)
+  ppd_file = gtk_printer_cups_get_ppd (cups_printer);
+  if (ppd_file != NULL)
     {
-      size = &ppd_file->sizes[i];
+      for (i = 0; i < ppd_file->num_sizes; i++)
+        {
+          size = &ppd_file->sizes[i];
 
-      page_setup = create_page_setup (ppd_file, size);
+          page_setup = create_page_setup (ppd_file, size);
 
-      l = g_list_prepend (l, page_setup);
+          result = g_list_prepend (result, page_setup);
+        }
+    }
+  else if (cups_printer->media_supported != NULL &&
+           cups_printer->media_size_supported != NULL &&
+           /*
+            * 'media_supported' list can contain names of minimal and maximal sizes
+            * for which we don't create item in 'media_size_supported' list.
+            */
+           g_list_length (cups_printer->media_supported) >=
+           g_list_length (cups_printer->media_size_supported))
+    {
+      MediaSize *media_size;
+      GList     *media_iter;
+      GList     *media_size_iter;
+      gchar     *media;
+
+      for (media_iter = cups_printer->media_supported,
+           media_size_iter = cups_printer->media_size_supported;
+           media_size_iter != NULL;
+           media_iter = media_iter->next,
+           media_size_iter = media_size_iter->next)
+        {
+          media = (gchar *) media_iter->data;
+          media_size = (MediaSize *) media_size_iter->data;
+
+          page_setup = create_page_setup_from_media (media,
+                                                     media_size,
+                                                     cups_printer->media_margin_default_set,
+                                                     cups_printer->media_bottom_margin_default,
+                                                     cups_printer->media_top_margin_default,
+                                                     cups_printer->media_left_margin_default,
+                                                     cups_printer->media_right_margin_default);
+
+          result = g_list_prepend (result, page_setup);
+        }
     }
 
-  return g_list_reverse (l);
+  result = g_list_reverse (result);
+
+  return result;
 }
 
 static GtkPageSetup *
 cups_printer_get_default_page_size (GtkPrinter *printer)
 {
-  ppd_file_t *ppd_file;
-  ppd_size_t *size;
-  ppd_option_t *option;
-
+  GtkPrinterCups *cups_printer = GTK_PRINTER_CUPS (printer);
+  GtkPageSetup   *result = NULL;
+  ppd_option_t   *option;
+  ppd_file_t     *ppd_file;
+  ppd_size_t     *size;
 
   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
-  if (ppd_file == NULL)
-    return NULL;
+  if (ppd_file != NULL)
+    {
+      option = ppdFindOption (ppd_file, "PageSize");
+      if (option == NULL)
+        return NULL;
 
-  option = ppdFindOption (ppd_file, "PageSize");
-  if (option == NULL)
-    return NULL;
+      size = ppdPageSize (ppd_file, option->defchoice);
+      if (size == NULL)
+        return NULL;
 
-  size = ppdPageSize (ppd_file, option->defchoice);
-  if (size == NULL)
-    return NULL;
+      result = create_page_setup (ppd_file, size);
+    }
+  else if (cups_printer->media_default != NULL)
+    {
+      MediaSize *media_size;
+      GList     *media_iter;
+      GList     *media_size_iter;
+      gchar     *media;
+
+      for (media_iter = cups_printer->media_supported,
+           media_size_iter = cups_printer->media_size_supported;
+           media_size_iter != NULL;
+           media_iter = media_iter->next,
+           media_size_iter = media_size_iter->next)
+        {
+          media = (gchar *) media_iter->data;
+          media_size = (MediaSize *) media_size_iter->data;
 
-  return create_page_setup (ppd_file, size);
+          if (g_strcmp0 (cups_printer->media_default, media) == 0)
+            {
+              result = create_page_setup_from_media (media,
+                                                     media_size,
+                                                     cups_printer->media_margin_default_set,
+                                                     cups_printer->media_bottom_margin_default,
+                                                     cups_printer->media_top_margin_default,
+                                                     cups_printer->media_left_margin_default,
+                                                     cups_printer->media_right_margin_default);
+            }
+        }
+    }
+
+  return result;
 }
 
 static gboolean
@@ -5879,18 +6142,29 @@ cups_printer_get_hard_margins (GtkPrinter *printer,
                               gdouble    *left,
                               gdouble    *right)
 {
-  ppd_file_t *ppd_file;
+  GtkPrinterCups *cups_printer = GTK_PRINTER_CUPS (printer);
+  ppd_file_t     *ppd_file;
+  gboolean        result = FALSE;
 
   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
-  if (ppd_file == NULL)
-    return FALSE;
-
-  *left = ppd_file->custom_margins[0];
-  *bottom = ppd_file->custom_margins[1];
-  *right = ppd_file->custom_margins[2];
-  *top = ppd_file->custom_margins[3];
+  if (ppd_file != NULL)
+    {
+      *left = ppd_file->custom_margins[0];
+      *bottom = ppd_file->custom_margins[1];
+      *right = ppd_file->custom_margins[2];
+      *top = ppd_file->custom_margins[3];
+      result = TRUE;
+    }
+  else if (cups_printer->media_margin_default_set)
+    {
+      *left = cups_printer->media_left_margin_default;
+      *bottom = cups_printer->media_bottom_margin_default;
+      *right = cups_printer->media_right_margin_default;
+      *top = cups_printer->media_top_margin_default;
+      result = TRUE;
+    }
 
-  return TRUE;
+  return result;
 }
 
 static GtkPrintCapabilities
diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c
index 880c88b..7fd828e 100644
--- a/modules/printbackends/cups/gtkprintercups.c
+++ b/modules/printbackends/cups/gtkprintercups.c
@@ -125,6 +125,14 @@ gtk_printer_cups_init (GtkPrinterCups *printer)
   printer->supports_copies = FALSE;
   printer->supports_collate = FALSE;
   printer->supports_number_up = FALSE;
+  printer->media_default = NULL;
+  printer->media_supported = NULL;
+  printer->media_size_supported = NULL;
+  printer->media_bottom_margin_default = 0;
+  printer->media_top_margin_default = 0;
+  printer->media_left_margin_default = 0;
+  printer->media_right_margin_default = 0;
+  printer->media_margin_default_set = FALSE;
 }
 
 static void
@@ -169,6 +177,10 @@ gtk_printer_cups_finalize (GObject *object)
   if (printer->ppd_file)
     ppdClose (printer->ppd_file);
 
+  g_free (printer->media_default);
+  g_list_free_full (printer->media_supported, g_free);
+  g_list_free_full (printer->media_size_supported, g_free);
+
   if (printer->get_remote_ppd_poll > 0)
     g_source_remove (printer->get_remote_ppd_poll);
   printer->get_remote_ppd_attempts = 0;
diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h
index 10002cd..aeded4f 100644
--- a/modules/printbackends/cups/gtkprintercups.h
+++ b/modules/printbackends/cups/gtkprintercups.h
@@ -58,6 +58,15 @@ struct _GtkPrinterCups
   gchar      *ppd_name;
   ppd_file_t *ppd_file;
 
+  gchar    *media_default;
+  GList    *media_supported;
+  GList    *media_size_supported;
+  gint      media_bottom_margin_default;
+  gint      media_top_margin_default;
+  gint      media_left_margin_default;
+  gint      media_right_margin_default;
+  gboolean  media_margin_default_set;
+
   gchar  *default_cover_before;
   gchar  *default_cover_after;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]