]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkprintercups.c
printing: Use DBus calls instead of Avahi API
[~andy/gtk] / modules / printbackends / cups / gtkprintercups.c
1 /* GtkPrinterCupsCups
2  * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
3  * Copyright (C) 2011 Richard Hughes <rhughes@redhat.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "config.h"
20
21 #include <glib/gi18n-lib.h>
22
23 #ifdef HAVE_COLORD
24 #include <colord.h>
25 #endif
26
27 #include "gtkintl.h"
28 #include "gtkprintercups.h"
29
30 enum {
31   PROP_0,
32   PROP_PROFILE_TITLE
33 };
34
35 static void gtk_printer_cups_init       (GtkPrinterCups      *printer);
36 static void gtk_printer_cups_class_init (GtkPrinterCupsClass *class);
37 static void gtk_printer_cups_finalize   (GObject             *object);
38
39 static GtkPrinterClass *gtk_printer_cups_parent_class;
40 static GType gtk_printer_cups_type = 0;
41
42 static void gtk_printer_cups_set_property (GObject      *object,
43                                            guint         prop_id,
44                                            const GValue *value,
45                                            GParamSpec   *pspec);
46 static void gtk_printer_cups_get_property (GObject      *object,
47                                            guint         prop_id,
48                                            GValue       *value,
49                                            GParamSpec   *pspec);
50
51 void 
52 gtk_printer_cups_register_type (GTypeModule *module)
53 {
54   const GTypeInfo object_info =
55   {
56     sizeof (GtkPrinterCupsClass),
57     (GBaseInitFunc) NULL,
58     (GBaseFinalizeFunc) NULL,
59     (GClassInitFunc) gtk_printer_cups_class_init,
60     NULL,           /* class_finalize */
61     NULL,           /* class_data */
62     sizeof (GtkPrinterCups),
63     0,              /* n_preallocs */
64     (GInstanceInitFunc) gtk_printer_cups_init,
65   };
66
67  gtk_printer_cups_type = g_type_module_register_type (module,
68                                                       GTK_TYPE_PRINTER,
69                                                       "GtkPrinterCups",
70                                                       &object_info, 0);
71 }
72
73 GType
74 gtk_printer_cups_get_type (void)
75 {
76   return gtk_printer_cups_type;
77 }
78
79 static void
80 gtk_printer_cups_class_init (GtkPrinterCupsClass *class)
81 {
82   GObjectClass *object_class = (GObjectClass *) class;
83
84   object_class->finalize = gtk_printer_cups_finalize;
85   object_class->set_property = gtk_printer_cups_set_property;
86   object_class->get_property = gtk_printer_cups_get_property;
87
88   gtk_printer_cups_parent_class = g_type_class_peek_parent (class);
89
90   g_object_class_install_property (G_OBJECT_CLASS (class),
91                                    PROP_PROFILE_TITLE,
92                                    g_param_spec_string ("profile-title",
93                                                         P_("Color Profile Title"),
94                                                         P_("The title of the color profile to use"),
95                                                         "",
96                                                         G_PARAM_READABLE));
97 }
98
99 static void
100 gtk_printer_cups_init (GtkPrinterCups *printer)
101 {
102   printer->device_uri = NULL;
103   printer->printer_uri = NULL;
104   printer->state = 0;
105   printer->hostname = NULL;
106   printer->port = 0;
107   printer->ppd_name = NULL;
108   printer->ppd_file = NULL;
109   printer->default_cover_before = NULL;
110   printer->default_cover_after = NULL;
111   printer->remote = FALSE;
112   printer->get_remote_ppd_poll = 0;
113   printer->get_remote_ppd_attempts = 0;
114   printer->remote_cups_connection_test = NULL;
115   printer->auth_info_required = NULL;
116   printer->default_number_up = 1;
117 #ifdef HAVE_CUPS_API_1_6
118   printer->avahi_browsed = FALSE;
119   printer->avahi_name = NULL;
120   printer->avahi_type = NULL;
121   printer->avahi_domain = NULL;
122 #endif
123   printer->ipp_version_major = 1;
124   printer->ipp_version_minor = 1;
125   printer->supports_copies = FALSE;
126   printer->supports_collate = FALSE;
127   printer->supports_number_up = FALSE;
128 }
129
130 static void
131 gtk_printer_cups_finalize (GObject *object)
132 {
133   GtkPrinterCups *printer;
134
135   g_return_if_fail (object != NULL);
136
137   printer = GTK_PRINTER_CUPS (object);
138
139   g_free (printer->device_uri);
140   g_free (printer->printer_uri);
141   g_free (printer->hostname);
142   g_free (printer->ppd_name);
143   g_free (printer->default_cover_before);
144   g_free (printer->default_cover_after);
145   g_strfreev (printer->auth_info_required);
146
147 #ifdef HAVE_COLORD
148   if (printer->colord_cancellable)
149     {
150       g_cancellable_cancel (printer->colord_cancellable);
151       g_object_unref (printer->colord_cancellable);
152     }
153   g_free (printer->colord_title);
154   g_free (printer->colord_qualifier);
155   if (printer->colord_client)
156     g_object_unref (printer->colord_client);
157   if (printer->colord_device)
158     g_object_unref (printer->colord_device);
159   if (printer->colord_profile)
160     g_object_unref (printer->colord_profile);
161 #endif
162
163 #ifdef HAVE_CUPS_API_1_6
164   g_free (printer->avahi_name);
165   g_free (printer->avahi_type);
166   g_free (printer->avahi_domain);
167 #endif
168
169   if (printer->ppd_file)
170     ppdClose (printer->ppd_file);
171
172   if (printer->get_remote_ppd_poll > 0)
173     g_source_remove (printer->get_remote_ppd_poll);
174   printer->get_remote_ppd_attempts = 0;
175
176   gtk_cups_connection_test_free (printer->remote_cups_connection_test);
177
178   G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object);
179 }
180
181 static void
182 gtk_printer_cups_set_property (GObject         *object,
183                                guint            prop_id,
184                                const GValue    *value,
185                                GParamSpec      *pspec)
186 {
187   switch (prop_id)
188     {
189     default:
190       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
191       break;
192     }
193 }
194
195 static void
196 gtk_printer_cups_get_property (GObject    *object,
197                                guint       prop_id,
198                                GValue     *value,
199                                GParamSpec *pspec)
200 {
201 #ifdef HAVE_COLORD
202   GtkPrinterCups *printer = GTK_PRINTER_CUPS (object);
203 #endif
204
205   switch (prop_id)
206     {
207     case PROP_PROFILE_TITLE:
208 #ifdef HAVE_COLORD
209       if (printer->colord_title)
210         g_value_set_string (value, printer->colord_title);
211       else
212         g_value_set_static_string (value, "");
213 #else
214       g_value_set_static_string (value, NULL);
215 #endif
216       break;
217     default:
218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219       break;
220     }
221 }
222
223 #ifdef HAVE_COLORD
224
225 static void
226 colord_update_ui_from_settings (GtkPrinterCups *printer)
227 {
228   const gchar *title = NULL;
229
230   /* not yet connected to colord */
231   if (printer->colord_client == NULL)
232     goto out;
233   if (!cd_client_get_connected (printer->colord_client))
234     goto out;
235
236   /* failed to get a colord device for the printer */
237   if (printer->colord_device == NULL)
238     {
239       /* TRANSLATORS: when we're running an old CUPS, and
240        * it hasn't registered the device with colord */
241       title = _("Color management unavailable");
242       goto out;
243     }
244
245   /* when colord prevents us from connecting (should not happen) */
246   if (!cd_device_get_connected (printer->colord_device))
247     goto out;
248
249   /* failed to get a colord device for the printer */
250   if (printer->colord_profile == NULL)
251     {
252       /* TRANSLATORS: when there is no color profile available */
253       title = _("No profile available");
254       goto out;
255     }
256
257   /* when colord prevents us from connecting (should not happen) */
258   if (!cd_profile_get_connected (printer->colord_profile))
259     goto out;
260   title = cd_profile_get_title (printer->colord_profile);
261   if (title == NULL)
262     {
263       /* TRANSLATORS: when the color profile has no title */
264       title = _("Unspecified profile");
265       goto out;
266     }
267
268 out:
269   /* SUCCESS! */
270   if (g_strcmp0 (title, printer->colord_title) != 0)
271     {
272       g_free (printer->colord_title);
273       printer->colord_title = g_strdup (title);
274       g_object_notify (G_OBJECT (printer), "profile-title");
275     }
276   return;
277 }
278
279 static void
280 colord_client_profile_connect_cb (GObject *source_object,
281                                   GAsyncResult *res,
282                                   gpointer user_data)
283 {
284   gboolean ret;
285   GError *error = NULL;
286   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
287
288   ret = cd_profile_connect_finish (CD_PROFILE (source_object),
289                                    res,
290                                    &error);
291   if (!ret)
292     {
293       g_warning ("failed to get properties from the profile: %s",
294                  error->message);
295       g_error_free (error);
296     }
297
298   /* update the UI */
299   colord_update_ui_from_settings (printer);
300
301   g_object_unref (printer);
302 }
303
304 static void
305 colord_client_device_get_profile_for_qualifiers_cb (GObject *source_object,
306                                                     GAsyncResult *res,
307                                                     gpointer user_data)
308 {
309   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
310   GError *error = NULL;
311
312   printer->colord_profile = cd_device_get_profile_for_qualifiers_finish (printer->colord_device,
313                                                                          res,
314                                                                          &error);
315   if (printer->colord_profile == NULL)
316     {
317       /* not having a profile for a qualifier is not a warning */
318       g_debug ("no profile for device %s: %s",
319                cd_device_get_id (printer->colord_device),
320                error->message);
321       g_error_free (error);
322       goto out;
323     }
324
325   /* get details about the profile */
326   cd_profile_connect (printer->colord_profile,
327                       printer->colord_cancellable,
328                       colord_client_profile_connect_cb,
329                       g_object_ref (printer));
330 out:
331   /* update the UI */
332   colord_update_ui_from_settings (printer);
333
334   g_object_unref (printer);
335 }
336
337 void
338 gtk_printer_cups_update_settings (GtkPrinterCups *printer,
339                                   GtkPrintSettings *settings,
340                                   GtkPrinterOptionSet *set)
341 {
342   gchar *qualifier = NULL;
343   gchar **qualifiers = NULL;
344   GtkPrinterOption *option;
345   const gchar *format[3];
346
347   /* nothing set yet */
348   if (printer->colord_device == NULL)
349     goto out;
350   if (!cd_device_get_connected (printer->colord_device))
351     goto out;
352
353   /* cupsICCQualifier1 */
354   option = gtk_printer_option_set_lookup (set, "cups-ColorSpace");
355   if (option == NULL)
356     option = gtk_printer_option_set_lookup (set, "cups-ColorModel");
357   if (option != NULL)
358     format[0] = option->value;
359   else
360     format[0] = "*";
361
362   /* cupsICCQualifier2 */
363   option = gtk_printer_option_set_lookup (set, "cups-OutputMode");
364   if (option != NULL)
365     format[1] = option->value;
366   else
367     format[1] = "*";
368
369   /* cupsICCQualifier3 */
370   option = gtk_printer_option_set_lookup (set, "cups-Resolution");
371   if (option != NULL)
372     format[2] = option->value;
373   else
374     format[2] = "*";
375
376   /* get profile for the device given the qualifier */
377   qualifier = g_strdup_printf ("%s.%s.%s,%s.%s.*,%s.*.*",
378                                format[0], format[1], format[2],
379                                format[0], format[1],
380                                format[0]);
381
382   /* only requery colord if the option that was changed would give
383    * us a different profile result */
384   if (g_strcmp0 (qualifier, printer->colord_qualifier) == 0)
385     goto out;
386
387   qualifiers = g_strsplit (qualifier, ",", -1);
388   cd_device_get_profile_for_qualifiers (printer->colord_device,
389                                         (const gchar **) qualifiers,
390                                         printer->colord_cancellable,
391                                         colord_client_device_get_profile_for_qualifiers_cb,
392                                         g_object_ref (printer));
393
394   /* save for the future */
395   g_free (printer->colord_qualifier);
396   printer->colord_qualifier = g_strdup (qualifier);
397
398   /* update the UI */
399   colord_update_ui_from_settings (printer);
400 out:
401   g_free (qualifier);
402   g_strfreev (qualifiers);
403 }
404
405 static void
406 colord_client_device_connect_cb (GObject *source_object,
407                                  GAsyncResult *res,
408                                  gpointer user_data)
409 {
410   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
411   gboolean ret;
412   GError *error = NULL;
413
414   /* get details about the device */
415   ret = cd_device_connect_finish (CD_DEVICE (source_object), res, &error);
416   if (!ret)
417     {
418       g_warning ("failed to get properties from the colord device: %s",
419                  error->message);
420       g_error_free (error);
421       goto out;
422     }
423 out:
424   /* update the UI */
425   colord_update_ui_from_settings (printer);
426
427   g_object_unref (printer);
428 }
429
430 static void
431 colord_client_find_device_cb (GObject *source_object,
432                               GAsyncResult *res,
433                               gpointer user_data)
434 {
435   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
436   GError *error = NULL;
437
438   /* get the new device */
439   printer->colord_device = cd_client_find_device_finish (printer->colord_client,
440                                                res,
441                                                &error);
442   if (printer->colord_device == NULL)
443     {
444       g_warning ("failed to get find a colord device: %s",
445                  error->message);
446       g_error_free (error);
447       goto out;
448     }
449
450   /* get details about the device */
451   g_cancellable_reset (printer->colord_cancellable);
452   cd_device_connect (printer->colord_device,
453                      printer->colord_cancellable,
454                      colord_client_device_connect_cb,
455                      g_object_ref (printer));
456 out:
457   /* update the UI */
458   colord_update_ui_from_settings (printer);
459
460   g_object_unref (printer);
461 }
462
463 static void
464 colord_update_device (GtkPrinterCups *printer)
465 {
466   gchar *colord_device_id = NULL;
467
468   /* not yet connected to the daemon */
469   if (!cd_client_get_connected (printer->colord_client))
470     goto out;
471
472   /* not yet assigned a printer */
473   if (printer->ppd_file == NULL)
474     goto out;
475
476   /* old cached profile no longer valid */
477   if (printer->colord_profile)
478     {
479       g_object_unref (printer->colord_profile);
480       printer->colord_profile = NULL;
481     }
482
483   /* old cached device no longer valid */
484   if (printer->colord_device)
485     {
486       g_object_unref (printer->colord_device);
487       printer->colord_device = NULL;
488     }
489
490   /* generate a known ID */
491   colord_device_id = g_strdup_printf ("cups-%s", gtk_printer_get_name (GTK_PRINTER (printer)));
492
493   g_cancellable_reset (printer->colord_cancellable);
494   cd_client_find_device (printer->colord_client,
495                          colord_device_id,
496                          printer->colord_cancellable,
497                          colord_client_find_device_cb,
498                          g_object_ref (printer));
499 out:
500   g_free (colord_device_id);
501
502   /* update the UI */
503   colord_update_ui_from_settings (printer);
504 }
505
506 static void
507 colord_client_connect_cb (GObject *source_object,
508                           GAsyncResult *res,
509                           gpointer user_data)
510 {
511   gboolean ret;
512   GError *error = NULL;
513   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
514
515   ret = cd_client_connect_finish (CD_CLIENT (source_object),
516                                   res, &error);
517   if (!ret)
518     {
519       g_warning ("failed to contact colord: %s", error->message);
520       g_error_free (error);
521     }
522
523   /* refresh the device */
524   colord_update_device (printer);
525
526   g_object_unref (printer);
527 }
528
529 static void
530 colord_printer_details_aquired_cb (GtkPrinterCups *printer,
531                                    gboolean success,
532                                    gpointer user_data)
533 {
534   /* refresh the device */
535   if (printer->colord_client)
536     colord_update_device (printer);
537 }
538 #endif
539
540 /**
541  * gtk_printer_cups_new:
542  *
543  * Creates a new #GtkPrinterCups.
544  *
545  * Return value: a new #GtkPrinterCups
546  *
547  * Since: 2.10
548  **/
549 GtkPrinterCups *
550 gtk_printer_cups_new (const char      *name,
551                       GtkPrintBackend *backend,
552                       gpointer         colord_client)
553 {
554   GObject *result;
555   gboolean accepts_pdf;
556   GtkPrinterCups *printer;
557
558 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
559   accepts_pdf = TRUE;
560 #else
561   accepts_pdf = FALSE;
562 #endif
563
564   result = g_object_new (GTK_TYPE_PRINTER_CUPS,
565                          "name", name,
566                          "backend", backend,
567                          "is-virtual", FALSE,
568                          "accepts-pdf", accepts_pdf,
569                          NULL);
570   printer = GTK_PRINTER_CUPS (result);
571
572 #ifdef HAVE_COLORD
573   /* connect to colord */
574   if (colord_client != NULL)
575     {
576       printer->colord_cancellable = g_cancellable_new ();
577       printer->colord_client = g_object_ref (CD_CLIENT (colord_client));
578       cd_client_connect (printer->colord_client,
579                          printer->colord_cancellable,
580                          colord_client_connect_cb,
581                          g_object_ref (printer));
582     }
583
584     /* update the device when we read the PPD */
585     g_signal_connect (printer, "details-acquired",
586                       G_CALLBACK (colord_printer_details_aquired_cb),
587                       printer);
588 #endif
589
590   /*
591    * IPP version 1.1 has to be supported
592    * by all implementations according to rfc 2911
593    */
594   printer->ipp_version_major = 1;
595   printer->ipp_version_minor = 1;
596
597   return printer;
598 }
599
600 ppd_file_t *
601 gtk_printer_cups_get_ppd (GtkPrinterCups *printer)
602 {
603   return printer->ppd_file;
604 }
605
606 const gchar *
607 gtk_printer_cups_get_ppd_name (GtkPrinterCups  *printer)
608 {
609   const gchar *result;
610
611   result = printer->ppd_name;
612
613   if (result == NULL)
614     result = gtk_printer_get_name (GTK_PRINTER (printer));
615
616   return result;
617 }