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