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