]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkprintercups.c
printing: Increase reference count for user data
[~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 }
117
118 static void
119 gtk_printer_cups_finalize (GObject *object)
120 {
121   GtkPrinterCups *printer;
122
123   g_return_if_fail (object != NULL);
124
125   printer = GTK_PRINTER_CUPS (object);
126
127   g_free (printer->device_uri);
128   g_free (printer->printer_uri);
129   g_free (printer->hostname);
130   g_free (printer->ppd_name);
131   g_free (printer->default_cover_before);
132   g_free (printer->default_cover_after);
133   g_strfreev (printer->auth_info_required);
134
135 #ifdef HAVE_COLORD
136   g_cancellable_cancel (printer->colord_cancellable);
137   g_object_unref (printer->colord_cancellable);
138   g_free (printer->colord_title);
139   g_free (printer->colord_qualifier);
140   if (printer->colord_client)
141     g_object_unref (printer->colord_client);
142   if (printer->colord_device)
143     g_object_unref (printer->colord_device);
144   if (printer->colord_profile)
145     g_object_unref (printer->colord_profile);
146 #endif
147
148   if (printer->ppd_file)
149     ppdClose (printer->ppd_file);
150
151   if (printer->get_remote_ppd_poll > 0)
152     g_source_remove (printer->get_remote_ppd_poll);
153   printer->get_remote_ppd_attempts = 0;
154
155   gtk_cups_connection_test_free (printer->remote_cups_connection_test);
156
157   G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object);
158 }
159
160 static void
161 gtk_printer_cups_set_property (GObject         *object,
162                                guint            prop_id,
163                                const GValue    *value,
164                                GParamSpec      *pspec)
165 {
166   switch (prop_id)
167     {
168     default:
169       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
170       break;
171     }
172 }
173
174 static void
175 gtk_printer_cups_get_property (GObject    *object,
176                                guint       prop_id,
177                                GValue     *value,
178                                GParamSpec *pspec)
179 {
180 #ifdef HAVE_COLORD
181   GtkPrinterCups *printer = GTK_PRINTER_CUPS (object);
182 #endif
183
184   switch (prop_id)
185     {
186     case PROP_PROFILE_TITLE:
187 #ifdef HAVE_COLORD
188       if (printer->colord_title)
189         g_value_set_string (value, printer->colord_title);
190       else
191         g_value_set_static_string (value, "");
192 #else
193       g_value_set_static_string (value, NULL);
194 #endif
195       break;
196     default:
197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198       break;
199     }
200 }
201
202 #ifdef HAVE_COLORD
203
204 static void
205 colord_update_ui_from_settings (GtkPrinterCups *printer)
206 {
207   const gchar *title = NULL;
208
209   /* not yet connected to colord */
210   if (printer->colord_client == NULL)
211     goto out;
212   if (!cd_client_get_connected (printer->colord_client))
213     goto out;
214
215   /* failed to get a colord device for the printer */
216   if (printer->colord_device == NULL)
217     {
218       /* TRANSLATORS: when we're running an old CUPS, and
219        * it hasn't registered the device with colord */
220       title = _("Color management unavailable");
221       goto out;
222     }
223
224   /* when colord prevents us from connecting (should not happen) */
225   if (!cd_device_get_connected (printer->colord_device))
226     goto out;
227
228   /* failed to get a colord device for the printer */
229   if (printer->colord_profile == NULL)
230     {
231       /* TRANSLATORS: when there is no color profile available */
232       title = _("No profile available");
233       goto out;
234     }
235
236   /* when colord prevents us from connecting (should not happen) */
237   if (!cd_profile_get_connected (printer->colord_profile))
238     goto out;
239   title = cd_profile_get_title (printer->colord_profile);
240   if (title == NULL)
241     {
242       /* TRANSLATORS: when the color profile has no title */
243       title = _("Unspecified profile");
244       goto out;
245     }
246
247 out:
248   /* SUCCESS! */
249   if (g_strcmp0 (title, printer->colord_title) != 0)
250     {
251       g_free (printer->colord_title);
252       printer->colord_title = g_strdup (title);
253       g_object_notify (G_OBJECT (printer), "profile-title");
254     }
255   return;
256 }
257
258 static void
259 colord_client_profile_connect_cb (GObject *source_object,
260                                   GAsyncResult *res,
261                                   gpointer user_data)
262 {
263   gboolean ret;
264   GError *error = NULL;
265   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
266
267   ret = cd_profile_connect_finish (CD_PROFILE (source_object),
268                                    res,
269                                    &error);
270   if (!ret)
271     {
272       g_warning ("failed to get properties from the profile: %s",
273                  error->message);
274       g_error_free (error);
275     }
276
277   /* update the UI */
278   colord_update_ui_from_settings (printer);
279
280   g_object_unref (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                       g_object_ref (printer));
309 out:
310   /* update the UI */
311   colord_update_ui_from_settings (printer);
312
313   g_object_unref (printer);
314 }
315
316 void
317 gtk_printer_cups_update_settings (GtkPrinterCups *printer,
318                                   GtkPrintSettings *settings,
319                                   GtkPrinterOptionSet *set)
320 {
321   gchar *qualifier = NULL;
322   gchar **qualifiers = NULL;
323   GtkPrinterOption *option;
324   const gchar *format[3];
325
326   /* nothing set yet */
327   if (printer->colord_device == NULL)
328     goto out;
329   if (!cd_device_get_connected (printer->colord_device))
330     goto out;
331
332   /* cupsICCQualifier1 */
333   option = gtk_printer_option_set_lookup (set, "cups-ColorSpace");
334   if (option == NULL)
335     option = gtk_printer_option_set_lookup (set, "cups-ColorModel");
336   if (option != NULL)
337     format[0] = option->value;
338   else
339     format[0] = "*";
340
341   /* cupsICCQualifier2 */
342   option = gtk_printer_option_set_lookup (set, "cups-OutputMode");
343   if (option != NULL)
344     format[1] = option->value;
345   else
346     format[1] = "*";
347
348   /* cupsICCQualifier3 */
349   option = gtk_printer_option_set_lookup (set, "cups-Resolution");
350   if (option != NULL)
351     format[2] = option->value;
352   else
353     format[2] = "*";
354
355   /* get profile for the device given the qualifier */
356   qualifier = g_strdup_printf ("%s.%s.%s,%s.%s.*,%s.*.*",
357                                format[0], format[1], format[2],
358                                format[0], format[1],
359                                format[0]);
360
361   /* only requery colord if the option that was changed would give
362    * us a different profile result */
363   if (g_strcmp0 (qualifier, printer->colord_qualifier) == 0)
364     goto out;
365
366   qualifiers = g_strsplit (qualifier, ",", -1);
367   cd_device_get_profile_for_qualifiers (printer->colord_device,
368                                         (const gchar **) qualifiers,
369                                         printer->colord_cancellable,
370                                         colord_client_device_get_profile_for_qualifiers_cb,
371                                         g_object_ref (printer));
372
373   /* save for the future */
374   g_free (printer->colord_qualifier);
375   printer->colord_qualifier = g_strdup (qualifier);
376
377   /* update the UI */
378   colord_update_ui_from_settings (printer);
379 out:
380   g_free (qualifier);
381   g_strfreev (qualifiers);
382 }
383
384 static void
385 colord_client_device_connect_cb (GObject *source_object,
386                                  GAsyncResult *res,
387                                  gpointer user_data)
388 {
389   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
390   gboolean ret;
391   GError *error = NULL;
392
393   /* get details about the device */
394   ret = cd_device_connect_finish (CD_DEVICE (source_object), res, &error);
395   if (!ret)
396     {
397       g_warning ("failed to get properties from the colord device: %s",
398                  error->message);
399       g_error_free (error);
400       goto out;
401     }
402 out:
403   /* update the UI */
404   colord_update_ui_from_settings (printer);
405
406   g_object_unref (printer);
407 }
408
409 static void
410 colord_client_find_device_cb (GObject *source_object,
411                               GAsyncResult *res,
412                               gpointer user_data)
413 {
414   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
415   GError *error = NULL;
416
417   /* get the new device */
418   printer->colord_device = cd_client_find_device_finish (printer->colord_client,
419                                                res,
420                                                &error);
421   if (printer->colord_device == NULL)
422     {
423       g_warning ("failed to get find a colord device: %s",
424                  error->message);
425       g_error_free (error);
426       goto out;
427     }
428
429   /* get details about the device */
430   g_cancellable_reset (printer->colord_cancellable);
431   cd_device_connect (printer->colord_device,
432                      printer->colord_cancellable,
433                      colord_client_device_connect_cb,
434                      g_object_ref (printer));
435 out:
436   /* update the UI */
437   colord_update_ui_from_settings (printer);
438
439   g_object_unref (printer);
440 }
441
442 static void
443 colord_update_device (GtkPrinterCups *printer)
444 {
445   gchar *colord_device_id = NULL;
446
447   /* not yet connected to the daemon */
448   if (!cd_client_get_connected (printer->colord_client))
449     goto out;
450
451   /* not yet assigned a printer */
452   if (printer->ppd_file == NULL)
453     goto out;
454
455   /* old cached profile no longer valid */
456   if (printer->colord_profile)
457     {
458       g_object_unref (printer->colord_profile);
459       printer->colord_profile = NULL;
460     }
461
462   /* old cached device no longer valid */
463   if (printer->colord_device)
464     {
465       g_object_unref (printer->colord_device);
466       printer->colord_device = NULL;
467     }
468
469   /* generate a known ID */
470   colord_device_id = g_strdup_printf ("cups-%s", gtk_printer_get_name (GTK_PRINTER (printer)));
471
472   g_cancellable_reset (printer->colord_cancellable);
473   cd_client_find_device (printer->colord_client,
474                          colord_device_id,
475                          printer->colord_cancellable,
476                          colord_client_find_device_cb,
477                          g_object_ref (printer));
478 out:
479   g_free (colord_device_id);
480
481   /* update the UI */
482   colord_update_ui_from_settings (printer);
483 }
484
485 static void
486 colord_client_connect_cb (GObject *source_object,
487                           GAsyncResult *res,
488                           gpointer user_data)
489 {
490   gboolean ret;
491   GError *error = NULL;
492   GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data);
493
494   ret = cd_client_connect_finish (CD_CLIENT (source_object),
495                                   res, &error);
496   if (!ret)
497     {
498       g_warning ("failed to contact colord: %s", error->message);
499       g_error_free (error);
500     }
501
502   /* refresh the device */
503   colord_update_device (printer);
504
505   g_object_unref (printer);
506 }
507 #endif
508
509 /**
510  * gtk_printer_cups_new:
511  *
512  * Creates a new #GtkPrinterCups.
513  *
514  * Return value: a new #GtkPrinterCups
515  *
516  * Since: 2.10
517  **/
518 GtkPrinterCups *
519 gtk_printer_cups_new (const char      *name,
520                       GtkPrintBackend *backend,
521                       gpointer         colord_client)
522 {
523   GObject *result;
524   gboolean accepts_pdf;
525   GtkPrinterCups *printer;
526
527 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
528   accepts_pdf = TRUE;
529 #else
530   accepts_pdf = FALSE;
531 #endif
532
533   result = g_object_new (GTK_TYPE_PRINTER_CUPS,
534                          "name", name,
535                          "backend", backend,
536                          "is-virtual", FALSE,
537                          "accepts-pdf", accepts_pdf,
538                          NULL);
539   printer = GTK_PRINTER_CUPS (result);
540
541 #ifdef HAVE_COLORD
542   /* connect to colord */
543   if (colord_client != NULL)
544     {
545       printer->colord_cancellable = g_cancellable_new ();
546       printer->colord_client = g_object_ref (CD_CLIENT (colord_client));
547       cd_client_connect (printer->colord_client,
548                          printer->colord_cancellable,
549                          colord_client_connect_cb,
550                          g_object_ref (printer));
551     }
552 #endif
553   return printer;
554 }
555
556 ppd_file_t *
557 gtk_printer_cups_get_ppd (GtkPrinterCups *printer)
558 {
559   return printer->ppd_file;
560 }
561
562 const gchar *
563 gtk_printer_cups_get_ppd_name (GtkPrinterCups  *printer)
564 {
565   const gchar *result;
566
567   result = printer->ppd_name;
568
569   if (result == NULL)
570     result = gtk_printer_get_name (GTK_PRINTER (printer));
571
572   return result;
573 }