~canonical-dx-team/ubuntu/maverick/gtk+2.0/menuproxy

« back to all changes in this revision

Viewing changes to modules/printbackends/cups/gtkprintbackendcups.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-04 12:24:25 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20070504122425-0m8midgzrp40y8w2
Tags: 2.10.12-1ubuntu1
* Sync with Debian
* New upstream version:
  Fixed bugs:
  - 379414 file chooser warnings when changing path in the entry
  - 418585 GtkFileChooserDefault sizing code is not DPI independent
  - 419568 Crash in search if start with special letter
  - 435062 build dies with icon cache validation
  - 379399 Segfault to call gtk_print_operation_run twice.
  - 387889 cups backend has problems when there are too many printers
  - 418531 invalid read to gtkicontheme.c gtk_icon_theme_lookup_icon...
  - 423916 crash in color scheme code
  - 424042 Segmentation fault while quickly pressing Alt+arrows
  - 415260 Protect against negative indices when setting values in G...
  - 419171 XGetVisualInfo() may not set nxvisuals
  - 128852 Gdk cursors don't look good on win32
  - 344657 Ctrl-H doesn't toggle "Show Hidden Files" setting
  - 345345 PrintOperation::paginate is not emitted for class handler
  - 347567 GtkPrintOperation::end-print is not emitted if it's cance...
  - 369112 gtk_ui_manager_add_ui should accept unnamed separator
  - 392015 Selected menu item invisible on Windows Vista
  - 399253 MS-Windows Theme Bottom Tab placement rendering glitches
  - 399425 gtk_input_dialog_fill_axes() adds child to gtkscrolledwin...
  - 403251 [patch] little memory leak in GtkPrintJob
  - 403267 [patch] memory leak in GtkPageSetupUnixDialog
  - 403470 MS-Windows Theme tab placement other than on top leaks a ...
  - 404506 Windows system fonts that have multi-byte font names cann...
  - 405089 Incorrect window placement for GtkEventBox private window
  - 405515 Minor leak in gtkfilesystemmodel.c
  - 405539 gdk_pixbuf_save() for PNG saver can return FALSE without ...
  - 415681 gdk_window_clear_area includes an extra line and column o...
  - 418219 GtkRecentChooser should apply filter before sorting and c...
  - 418403 Scroll to printer after selecting it from settings
  - 421985 _gtk_print_operation_platform_backend_launch_preview
  - 421990 gtk_print_job_get_surface
  - 421993 gtk_print_operation_init
  - 423064 Conditional jump or move depends on uninitialised value(s...
  - 423722 Fix printing header in gtk-demo
  - 424168 gtk_print_operation_run on async preview
  - 425655 Don't install gtk+-unix-print-2.0.pc on non-UNIX platforms
  - 425786 GDK segfaults if XineramaQueryScreens fails
  - 428665 Lpr Backend gets stuck in infinite loop during gtk_enumer...
  - 429902 GtkPrintOperation leaks cairo contextes
  - 431997 First delay of GdkPixbufAnimationIter is wrong
  - 433242 Inconsistent scroll arrow position calculations
  - 433972 Placing gtk.Expander inside a gtk.TextView() changes gtk....
  - 434261 _gtk_toolbar_elide_underscores incorrectly handles some s...
  - 383354 ctrl-L should make 'Location' entry disappear
  - 418673 gtk_recent_manager_add_item
  - 429732 gtk_accel_group_finalize accesses invalid memory
  - 435028 WM_CLIENT_LEADER is wrong on the leader_window
  - 431067 Background of the header window is not updated
  - 338843 add recent files support inside the ui manager
  - 148535 add drop shadow to menus, tooltips, etc. under Windows XP
* debian/control.in:
  - Conflicts on ubuntulooks (<= 0.9.11-1)
* debian/patches/15_default-fallback-icon-theme.patch:
  - patch from Debian, fallback on gnome icon theme

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GTK - The GIMP Toolkit
 
2
 * gtkprintbackendcups.h: Default implementation of GtkPrintBackend 
 
3
 * for the Common Unix Print System (CUPS)
 
4
 * Copyright (C) 2003, Red Hat, Inc.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the
 
18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include <unistd.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
#include <stdlib.h>
 
26
 
 
27
#include <config.h>
 
28
#include <cups/cups.h>
 
29
#include <cups/language.h>
 
30
#include <cups/http.h>
 
31
#include <cups/ipp.h>
 
32
#include <errno.h>
 
33
#include <cairo.h>
 
34
#include <cairo-pdf.h>
 
35
#include <cairo-ps.h>
 
36
 
 
37
#include <glib/gi18n-lib.h>
 
38
#include <gmodule.h>
 
39
 
 
40
#include <gtk/gtkprintoperation.h>
 
41
#include <gtk/gtkprintsettings.h>
 
42
#include <gtk/gtkprintbackend.h>
 
43
#include <gtk/gtkprinter.h>
 
44
#include <gtk/gtkprinter-private.h>
 
45
 
 
46
#include "gtkprintbackendcups.h"
 
47
#include "gtkprintercups.h"
 
48
 
 
49
#include "gtkcupsutils.h"
 
50
#include "gtkdebug.h"
 
51
 
 
52
 
 
53
typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
 
54
 
 
55
#define GTK_PRINT_BACKEND_CUPS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
 
56
#define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
 
57
#define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
 
58
 
 
59
#define _CUPS_MAX_ATTEMPTS 10 
 
60
#define _CUPS_MAX_CHUNK_SIZE 8192
 
61
 
 
62
/* define this to see warnings about ignored ppd options */
 
63
#undef PRINT_IGNORED_OPTIONS
 
64
 
 
65
#define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
 
66
#define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
 
67
 
 
68
static GType print_backend_cups_type = 0;
 
69
 
 
70
typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
 
71
                                                   GtkCupsResult   *result, 
 
72
                                                   gpointer         user_data);
 
73
 
 
74
typedef enum 
 
75
{
 
76
  DISPATCH_SETUP,
 
77
  DISPATCH_REQUEST,
 
78
  DISPATCH_SEND,
 
79
  DISPATCH_CHECK,
 
80
  DISPATCH_READ,
 
81
  DISPATCH_ERROR
 
82
} GtkPrintCupsDispatchState;
 
83
 
 
84
typedef struct 
 
85
{
 
86
  GSource source;
 
87
 
 
88
  http_t *http;
 
89
  GtkCupsRequest *request;
 
90
  GPollFD *data_poll;
 
91
  GtkPrintBackendCups *backend;
 
92
 
 
93
} GtkPrintCupsDispatchWatch;
 
94
 
 
95
struct _GtkPrintBackendCupsClass
 
96
{
 
97
  GtkPrintBackendClass parent_class;
 
98
};
 
99
 
 
100
struct _GtkPrintBackendCups
 
101
{
 
102
  GtkPrintBackend parent_instance;
 
103
 
 
104
  char *default_printer;
 
105
  
 
106
  guint list_printers_poll;
 
107
  guint list_printers_pending : 1;
 
108
  guint got_default_printer   : 1;
 
109
};
 
110
 
 
111
static GObjectClass *backend_parent_class;
 
112
 
 
113
static void                 gtk_print_backend_cups_class_init      (GtkPrintBackendCupsClass          *class);
 
114
static void                 gtk_print_backend_cups_init            (GtkPrintBackendCups               *impl);
 
115
static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
 
116
static void                 gtk_print_backend_cups_dispose         (GObject                           *object);
 
117
static void                 cups_get_printer_list                  (GtkPrintBackend                   *print_backend);
 
118
static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
 
119
                                                                    GtkCupsRequest                    *request,
 
120
                                                                    GtkPrintCupsResponseCallbackFunc   callback,
 
121
                                                                    gpointer                           user_data,
 
122
                                                                    GDestroyNotify                     notify);
 
123
static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
 
124
                                                                    GtkPrinterOptionSet               *options,
 
125
                                                                    GtkPrintSettings                  *settings);
 
126
static gboolean             cups_printer_mark_conflicts            (GtkPrinter                        *printer,
 
127
                                                                    GtkPrinterOptionSet               *options);
 
128
static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
 
129
                                                                    GtkPrintSettings                  *settings,
 
130
                                                                    GtkPageSetup                      *page_setup,
 
131
                                                                    GtkPrintCapabilities               capabilities);
 
132
static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
 
133
                                                                    GtkPrintJob                       *print_job,
 
134
                                                                    GtkPrintSettings                  *settings,
 
135
                                                                    GtkPageSetup                      *page_setup);
 
136
static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
 
137
static void                 cups_printer_request_details           (GtkPrinter                        *printer);
 
138
static void                 cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
 
139
static void                 cups_request_ppd                       (GtkPrinter                        *printer);
 
140
static void                 cups_printer_get_hard_margins          (GtkPrinter                        *printer,
 
141
                                                                    double                            *top,
 
142
                                                                    double                            *bottom,
 
143
                                                                    double                            *left,
 
144
                                                                    double                            *right);
 
145
static GtkPrintCapabilities cups_printer_get_capabilities          (GtkPrinter                        *printer);
 
146
static void                 set_option_from_settings               (GtkPrinterOption                  *option,
 
147
                                                                    GtkPrintSettings                  *setting);
 
148
static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
 
149
                                                                    GtkPrintJob                       *job,
 
150
                                                                    int                                job_id);
 
151
static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
 
152
static void                 gtk_print_backend_cups_print_stream    (GtkPrintBackend                   *backend,
 
153
                                                                    GtkPrintJob                       *job,
 
154
                                                                    GIOChannel                        *data_io,
 
155
                                                                    GtkPrintJobCompleteFunc            callback,
 
156
                                                                    gpointer                           user_data,
 
157
                                                                    GDestroyNotify                     dnotify);
 
158
static cairo_surface_t *    cups_printer_create_cairo_surface      (GtkPrinter                        *printer,
 
159
                                                                    GtkPrintSettings                  *settings,
 
160
                                                                    gdouble                            width,
 
161
                                                                    gdouble                            height,
 
162
                                                                    GIOChannel                        *cache_io);
 
163
 
 
164
 
 
165
static void
 
166
gtk_print_backend_cups_register_type (GTypeModule *module)
 
167
{
 
168
  static const GTypeInfo print_backend_cups_info =
 
169
  {
 
170
    sizeof (GtkPrintBackendCupsClass),
 
171
    NULL,               /* base_init */
 
172
    NULL,               /* base_finalize */
 
173
    (GClassInitFunc) gtk_print_backend_cups_class_init,
 
174
    NULL,               /* class_finalize */
 
175
    NULL,               /* class_data */
 
176
    sizeof (GtkPrintBackendCups),
 
177
    0,                  /* n_preallocs */
 
178
    (GInstanceInitFunc) gtk_print_backend_cups_init
 
179
  };
 
180
 
 
181
  print_backend_cups_type = g_type_module_register_type (module,
 
182
                                                         GTK_TYPE_PRINT_BACKEND,
 
183
                                                         "GtkPrintBackendCups",
 
184
                                                         &print_backend_cups_info, 0);
 
185
}
 
186
 
 
187
G_MODULE_EXPORT void 
 
188
pb_module_init (GTypeModule *module)
 
189
{
 
190
  GTK_NOTE (PRINTING,
 
191
            g_print ("CUPS Backend: Initializing the CUPS print backend module\n")); 
 
192
 
 
193
  gtk_print_backend_cups_register_type (module);
 
194
  gtk_printer_cups_register_type (module);
 
195
}
 
196
 
 
197
G_MODULE_EXPORT void 
 
198
pb_module_exit (void)
 
199
{
 
200
 
 
201
}
 
202
  
 
203
G_MODULE_EXPORT GtkPrintBackend * 
 
204
pb_module_create (void)
 
205
{
 
206
  return gtk_print_backend_cups_new ();
 
207
}
 
208
 
 
209
/*
 
210
 * GtkPrintBackendCups
 
211
 */
 
212
GType
 
213
gtk_print_backend_cups_get_type (void)
 
214
{
 
215
  return print_backend_cups_type;
 
216
}
 
217
 
 
218
/**
 
219
 * gtk_print_backend_cups_new:
 
220
 *
 
221
 * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
 
222
 * implements the #GtkPrintBackend interface with direct access to
 
223
 * the filesystem using Unix/Linux API calls
 
224
 *
 
225
 * Return value: the new #GtkPrintBackendCups object
 
226
 */
 
227
GtkPrintBackend *
 
228
gtk_print_backend_cups_new (void)
 
229
{
 
230
  GTK_NOTE (PRINTING,
 
231
            g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
 
232
 
 
233
  return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
 
234
}
 
235
 
 
236
static void
 
237
gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
 
238
{
 
239
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
240
  GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
 
241
 
 
242
  backend_parent_class = g_type_class_peek_parent (class);
 
243
 
 
244
  gobject_class->finalize = gtk_print_backend_cups_finalize;
 
245
  gobject_class->dispose = gtk_print_backend_cups_dispose;
 
246
 
 
247
  backend_class->request_printer_list = cups_get_printer_list; 
 
248
  backend_class->print_stream = gtk_print_backend_cups_print_stream;
 
249
  backend_class->printer_request_details = cups_printer_request_details;
 
250
  backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
 
251
  backend_class->printer_get_options = cups_printer_get_options;
 
252
  backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
 
253
  backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
 
254
  backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
 
255
  backend_class->printer_list_papers = cups_printer_list_papers;
 
256
  backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
 
257
  backend_class->printer_get_capabilities = cups_printer_get_capabilities;
 
258
}
 
259
 
 
260
static cairo_status_t
 
261
_cairo_write_to_cups (void                *closure,
 
262
                      const unsigned char *data,
 
263
                      unsigned int         length)
 
264
{
 
265
  GIOChannel *io = (GIOChannel *)closure;
 
266
  gsize written;
 
267
  GError *error;
 
268
 
 
269
  error = NULL;
 
270
 
 
271
  GTK_NOTE (PRINTING,
 
272
            g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length));
 
273
 
 
274
  while (length > 0) 
 
275
    {
 
276
      g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
 
277
 
 
278
      if (error != NULL)
 
279
        {
 
280
          GTK_NOTE (PRINTING,
 
281
                    g_print ("CUPS Backend: Error writing to temp file, %s\n", 
 
282
                             error->message));
 
283
 
 
284
          g_error_free (error);
 
285
          return CAIRO_STATUS_WRITE_ERROR;
 
286
        }    
 
287
 
 
288
      GTK_NOTE (PRINTING,
 
289
                g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
 
290
 
 
291
      data += written;
 
292
      length -= written;
 
293
    }
 
294
 
 
295
  return CAIRO_STATUS_SUCCESS;
 
296
}
 
297
 
 
298
static cairo_surface_t *
 
299
cups_printer_create_cairo_surface (GtkPrinter       *printer,
 
300
                                   GtkPrintSettings *settings,
 
301
                                   gdouble           width, 
 
302
                                   gdouble           height,
 
303
                                   GIOChannel       *cache_io)
 
304
{
 
305
  cairo_surface_t *surface; 
 
306
 
 
307
  /* TODO: check if it is a ps or pdf printer */
 
308
  
 
309
  surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
 
310
 
 
311
  /* TODO: DPI from settings object? */
 
312
  cairo_surface_set_fallback_resolution (surface, 300, 300);
 
313
 
 
314
  return surface;
 
315
}
 
316
 
 
317
typedef struct {
 
318
  GtkPrintJobCompleteFunc callback;
 
319
  GtkPrintJob *job;
 
320
  gpointer user_data;
 
321
  GDestroyNotify dnotify;
 
322
} CupsPrintStreamData;
 
323
 
 
324
static void
 
325
cups_free_print_stream_data (CupsPrintStreamData *data)
 
326
{
 
327
  GTK_NOTE (PRINTING,
 
328
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
329
 
 
330
  if (data->dnotify)
 
331
    data->dnotify (data->user_data);
 
332
  g_object_unref (data->job);
 
333
  g_free (data);
 
334
}
 
335
 
 
336
static void
 
337
cups_print_cb (GtkPrintBackendCups *print_backend,
 
338
               GtkCupsResult       *result,
 
339
               gpointer             user_data)
 
340
{
 
341
  GError *error = NULL;
 
342
  CupsPrintStreamData *ps = user_data;
 
343
 
 
344
  GTK_NOTE (PRINTING,
 
345
            g_print ("CUPS Backend: %s\n", G_STRFUNC)); 
 
346
 
 
347
  if (gtk_cups_result_is_error (result))
 
348
    error = g_error_new_literal (gtk_print_error_quark (),
 
349
                                 GTK_PRINT_ERROR_INTERNAL_ERROR,
 
350
                                 gtk_cups_result_get_error_string (result));
 
351
 
 
352
  if (ps->callback)
 
353
    ps->callback (ps->job, ps->user_data, error);
 
354
 
 
355
  if (error == NULL)
 
356
    {
 
357
      int job_id = 0;
 
358
      ipp_attribute_t *attr;            /* IPP job-id attribute */
 
359
      ipp_t *response = gtk_cups_result_get_response (result);
 
360
 
 
361
      if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
 
362
        job_id = attr->values[0].integer;
 
363
 
 
364
      if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
 
365
        gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
 
366
      else
 
367
        {
 
368
          gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
 
369
          cups_begin_polling_info (print_backend, ps->job, job_id);
 
370
        }
 
371
    } 
 
372
  else
 
373
    gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
 
374
 
 
375
  
 
376
  if (error)
 
377
    g_error_free (error);
 
378
  
 
379
}
 
380
 
 
381
static void
 
382
add_cups_options (const gchar *key,
 
383
                  const gchar *value,
 
384
                  gpointer     user_data)
 
385
{
 
386
  GtkCupsRequest *request = user_data;
 
387
 
 
388
  if (!g_str_has_prefix (key, "cups-"))
 
389
    return;
 
390
 
 
391
  if (strcmp (value, "gtk-ignore-value") == 0)
 
392
    return;
 
393
  
 
394
  key = key + strlen ("cups-");
 
395
 
 
396
  gtk_cups_request_encode_option (request, key, value);
 
397
}
 
398
 
 
399
static void
 
400
gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
 
401
                                     GtkPrintJob             *job,
 
402
                                     GIOChannel              *data_io,
 
403
                                     GtkPrintJobCompleteFunc  callback,
 
404
                                     gpointer                 user_data,
 
405
                                     GDestroyNotify           dnotify)
 
406
{
 
407
  GtkPrinterCups *cups_printer;
 
408
  CupsPrintStreamData *ps;
 
409
  GtkCupsRequest *request;
 
410
  GtkPrintSettings *settings;
 
411
  const gchar *title;
 
412
 
 
413
  GTK_NOTE (PRINTING,
 
414
            g_print ("CUPS Backend: %s\n", G_STRFUNC));   
 
415
 
 
416
  cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
 
417
  settings = gtk_print_job_get_settings (job);
 
418
 
 
419
  request = gtk_cups_request_new (NULL,
 
420
                                  GTK_CUPS_POST,
 
421
                                  IPP_PRINT_JOB,
 
422
                                  data_io,
 
423
                                  NULL,
 
424
                                  cups_printer->device_uri);
 
425
 
 
426
  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
 
427
                                   NULL, cups_printer->printer_uri);
 
428
 
 
429
  title = gtk_print_job_get_title (job);
 
430
  if (title)
 
431
    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
 
432
                                     title);
 
433
 
 
434
  gtk_print_settings_foreach (settings, add_cups_options, request);
 
435
  
 
436
  ps = g_new0 (CupsPrintStreamData, 1);
 
437
  ps->callback = callback;
 
438
  ps->user_data = user_data;
 
439
  ps->dnotify = dnotify;
 
440
  ps->job = g_object_ref (job);
 
441
 
 
442
  cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
 
443
                        request,
 
444
                        (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
 
445
                        ps,
 
446
                        (GDestroyNotify)cups_free_print_stream_data);
 
447
}
 
448
 
 
449
 
 
450
static void
 
451
gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
 
452
{
 
453
  backend_cups->list_printers_poll = FALSE;  
 
454
  backend_cups->got_default_printer = FALSE;  
 
455
  backend_cups->list_printers_pending = FALSE;
 
456
 
 
457
  cups_request_default_printer (backend_cups);
 
458
}
 
459
 
 
460
static void
 
461
gtk_print_backend_cups_finalize (GObject *object)
 
462
{
 
463
  GtkPrintBackendCups *backend_cups;
 
464
  
 
465
  GTK_NOTE (PRINTING,
 
466
            g_print ("CUPS Backend: finalizing CUPS backend module\n"));
 
467
 
 
468
  backend_cups = GTK_PRINT_BACKEND_CUPS (object);
 
469
 
 
470
  g_free (backend_cups->default_printer);
 
471
  backend_cups->default_printer = NULL;
 
472
  
 
473
  backend_parent_class->finalize (object);
 
474
}
 
475
 
 
476
static void
 
477
gtk_print_backend_cups_dispose (GObject *object)
 
478
{
 
479
  GtkPrintBackendCups *backend_cups;
 
480
 
 
481
  GTK_NOTE (PRINTING,
 
482
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
483
 
 
484
  backend_cups = GTK_PRINT_BACKEND_CUPS (object);
 
485
 
 
486
  if (backend_cups->list_printers_poll > 0)
 
487
    g_source_remove (backend_cups->list_printers_poll);
 
488
  backend_cups->list_printers_poll = 0;
 
489
  
 
490
  backend_parent_class->dispose (object);
 
491
}
 
492
 
 
493
 
 
494
static gboolean
 
495
cups_dispatch_watch_check (GSource *source)
 
496
{
 
497
  GtkPrintCupsDispatchWatch *dispatch;
 
498
  GtkCupsPollState poll_state;
 
499
  gboolean result;
 
500
 
 
501
  GTK_NOTE (PRINTING,
 
502
            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source)); 
 
503
 
 
504
  dispatch = (GtkPrintCupsDispatchWatch *) source;
 
505
 
 
506
  poll_state = gtk_cups_request_get_poll_state (dispatch->request);
 
507
 
 
508
  if (dispatch->request->http != NULL)
 
509
    {
 
510
      if (dispatch->data_poll == NULL)
 
511
        {
 
512
          dispatch->data_poll = g_new0 (GPollFD, 1);
 
513
          g_source_add_poll (source, dispatch->data_poll);
 
514
        }
 
515
      else
 
516
        {
 
517
          if (poll_state == GTK_CUPS_HTTP_READ)
 
518
            dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
 
519
          else if (poll_state == GTK_CUPS_HTTP_WRITE)
 
520
            dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
 
521
          else
 
522
            dispatch->data_poll->events = 0;
 
523
        }
 
524
 
 
525
#ifdef HAVE_CUPS_API_1_2
 
526
      dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
 
527
#else
 
528
      dispatch->data_poll->fd = dispatch->request->http->fd;
 
529
#endif
 
530
    }
 
531
    
 
532
  if (poll_state != GTK_CUPS_HTTP_IDLE)  
 
533
    if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
 
534
       return FALSE;
 
535
  
 
536
  result = gtk_cups_request_read_write (dispatch->request);
 
537
  if (result && dispatch->data_poll != NULL)
 
538
    {
 
539
      g_source_remove_poll (source, dispatch->data_poll);
 
540
      g_free (dispatch->data_poll);
 
541
      dispatch->data_poll = NULL;
 
542
    }
 
543
  
 
544
  return result;
 
545
}
 
546
 
 
547
static gboolean
 
548
cups_dispatch_watch_prepare (GSource *source,
 
549
                             gint    *timeout_)
 
550
{
 
551
  GtkPrintCupsDispatchWatch *dispatch;
 
552
 
 
553
  dispatch = (GtkPrintCupsDispatchWatch *) source;
 
554
 
 
555
  GTK_NOTE (PRINTING,
 
556
            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
557
 
 
558
  *timeout_ = -1;
 
559
  
 
560
  return gtk_cups_request_read_write (dispatch->request);
 
561
}
 
562
 
 
563
static gboolean
 
564
cups_dispatch_watch_dispatch (GSource     *source,
 
565
                              GSourceFunc  callback,
 
566
                              gpointer     user_data)
 
567
{
 
568
  GtkPrintCupsDispatchWatch *dispatch;
 
569
  GtkPrintCupsResponseCallbackFunc ep_callback;  
 
570
  GtkCupsResult *result;
 
571
  
 
572
  g_assert (callback != NULL);
 
573
 
 
574
  ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
 
575
  
 
576
  dispatch = (GtkPrintCupsDispatchWatch *) source;
 
577
 
 
578
  result = gtk_cups_request_get_result (dispatch->request);
 
579
 
 
580
  GTK_NOTE (PRINTING,
 
581
            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
582
 
 
583
  if (gtk_cups_result_is_error (result))
 
584
    {
 
585
      GTK_NOTE (PRINTING, 
 
586
                g_print("Error result: %s (type %i, status %i, code %i)\n", 
 
587
                        gtk_cups_result_get_error_string (result),
 
588
                        gtk_cups_result_get_error_type (result),
 
589
                        gtk_cups_result_get_error_status (result),
 
590
                        gtk_cups_result_get_error_code (result)));
 
591
     }
 
592
 
 
593
  ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
 
594
    
 
595
  return FALSE;
 
596
}
 
597
 
 
598
static void
 
599
cups_dispatch_watch_finalize (GSource *source)
 
600
{
 
601
  GtkPrintCupsDispatchWatch *dispatch;
 
602
 
 
603
  GTK_NOTE (PRINTING,
 
604
            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
605
 
 
606
  dispatch = (GtkPrintCupsDispatchWatch *) source;
 
607
 
 
608
  gtk_cups_request_free (dispatch->request);
 
609
 
 
610
  if (dispatch->backend)
 
611
    {
 
612
      /* We need to unref this at idle time, because it might be the
 
613
       * last reference to this module causing the code to be
 
614
       * unloaded (including this particular function!)
 
615
       * Update: Doing this at idle caused a deadlock taking the
 
616
       * mainloop context lock while being in a GSource callout for
 
617
       * multithreaded apps. So, for now we just disable unloading
 
618
       * of print backends. See _gtk_print_backend_create for the
 
619
       * disabling.
 
620
       */
 
621
      g_object_unref (dispatch->backend);
 
622
      dispatch->backend = NULL;
 
623
    }
 
624
 
 
625
  if (dispatch->data_poll != NULL)
 
626
    g_free (dispatch->data_poll);
 
627
}
 
628
 
 
629
static GSourceFuncs _cups_dispatch_watch_funcs = {
 
630
  cups_dispatch_watch_prepare,
 
631
  cups_dispatch_watch_check,
 
632
  cups_dispatch_watch_dispatch,
 
633
  cups_dispatch_watch_finalize
 
634
};
 
635
 
 
636
 
 
637
static void
 
638
cups_request_execute (GtkPrintBackendCups              *print_backend,
 
639
                      GtkCupsRequest                   *request,
 
640
                      GtkPrintCupsResponseCallbackFunc  callback,
 
641
                      gpointer                          user_data,
 
642
                      GDestroyNotify                    notify)
 
643
{
 
644
  GtkPrintCupsDispatchWatch *dispatch;
 
645
 
 
646
  dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, 
 
647
                                                         sizeof (GtkPrintCupsDispatchWatch));
 
648
 
 
649
  GTK_NOTE (PRINTING,
 
650
            g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
 
651
 
 
652
  dispatch->request = request;
 
653
  dispatch->backend = g_object_ref (print_backend);
 
654
  dispatch->data_poll = NULL;
 
655
 
 
656
  g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
 
657
 
 
658
  g_source_attach ((GSource *) dispatch, NULL);
 
659
  g_source_unref ((GSource *) dispatch);
 
660
}
 
661
 
 
662
#if 0
 
663
static void
 
664
cups_request_printer_info_cb (GtkPrintBackendCups *backend,
 
665
                              GtkCupsResult       *result,
 
666
                              gpointer             user_data)
 
667
{
 
668
  ipp_attribute_t *attr;
 
669
  ipp_t *response;
 
670
  gchar *printer_name;
 
671
  GtkPrinterCups *cups_printer;
 
672
  GtkPrinter *printer;
 
673
  gchar *loc;
 
674
  gchar *desc;
 
675
  gchar *state_msg;
 
676
  int job_count;
 
677
  gboolean status_changed;  
 
678
 
 
679
  g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
 
680
 
 
681
  printer_name = (gchar *)user_data;
 
682
  printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
 
683
                                            printer_name);
 
684
 
 
685
  GTK_NOTE (PRINTING,
 
686
            g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
 
687
 
 
688
  if (!printer)
 
689
    {
 
690
      GTK_NOTE (PRINTING,
 
691
            g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
 
692
      return;
 
693
    }
 
694
 
 
695
  cups_printer = GTK_PRINTER_CUPS (printer);
 
696
  
 
697
  if (gtk_cups_result_is_error (result))
 
698
    {
 
699
      if (gtk_printer_is_new (printer))
 
700
        {
 
701
          gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
 
702
                                            printer);
 
703
          return;
 
704
        }
 
705
      else
 
706
        return; /* TODO: mark as inactive printer */
 
707
    }
 
708
 
 
709
  response = gtk_cups_result_get_response (result);
 
710
 
 
711
  /* TODO: determine printer type and use correct icon */
 
712
  gtk_printer_set_icon_name (printer, "gtk-print");
 
713
 
 
714
  state_msg = "";
 
715
  loc = "";
 
716
  desc = "";
 
717
  job_count = 0;
 
718
  for (attr = response->attrs; attr != NULL; attr = attr->next) 
 
719
    {
 
720
      if (!attr->name)
 
721
        continue;
 
722
 
 
723
      _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
 
724
      _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
 
725
      _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
 
726
      _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
 
727
      _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
 
728
    }
 
729
 
 
730
  status_changed = gtk_printer_set_job_count (printer, job_count);
 
731
  
 
732
  status_changed |= gtk_printer_set_location (printer, loc);
 
733
  status_changed |= gtk_printer_set_description (printer, desc);
 
734
  status_changed |= gtk_printer_set_state_message (printer, state_msg);
 
735
 
 
736
  if (status_changed)
 
737
    g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
 
738
                           "printer-status-changed", printer); 
 
739
}
 
740
 
 
741
static void
 
742
cups_request_printer_info (GtkPrintBackendCups *print_backend,
 
743
                           const gchar         *printer_name)
 
744
{
 
745
  GtkCupsRequest *request;
 
746
  gchar *printer_uri;
 
747
  static const char * const pattrs[] =  /* Attributes we're interested in */
 
748
    {
 
749
      "printer-location",
 
750
      "printer-info",
 
751
      "printer-state-message",
 
752
      "printer-state",
 
753
      "queued-job-count"
 
754
    };
 
755
 
 
756
  request = gtk_cups_request_new (NULL,
 
757
                                  GTK_CUPS_POST,
 
758
                                  IPP_GET_PRINTER_ATTRIBUTES,
 
759
                                  NULL,
 
760
                                  NULL,
 
761
                                  NULL);
 
762
 
 
763
  printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
 
764
                                  printer_name);
 
765
  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
 
766
                                   "printer-uri", NULL, printer_uri);
 
767
 
 
768
  GTK_NOTE (PRINTING,
 
769
            g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
 
770
 
 
771
  g_free (printer_uri);
 
772
 
 
773
  gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 
774
                                    "requested-attributes", G_N_ELEMENTS (pattrs),
 
775
                                    NULL, pattrs);
 
776
 
 
777
  cups_request_execute (print_backend,
 
778
                        request,
 
779
                        (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
 
780
                        g_strdup (printer_name),
 
781
                        (GDestroyNotify) g_free);
 
782
}
 
783
#endif
 
784
 
 
785
typedef struct {
 
786
  GtkPrintBackendCups *print_backend;
 
787
  GtkPrintJob *job;
 
788
  int job_id;
 
789
  int counter;
 
790
} CupsJobPollData;
 
791
 
 
792
static void
 
793
job_object_died (gpointer  user_data,
 
794
                 GObject  *where_the_object_was)
 
795
{
 
796
  CupsJobPollData *data = user_data;
 
797
  data->job = NULL;
 
798
}
 
799
 
 
800
static void
 
801
cups_job_poll_data_free (CupsJobPollData *data)
 
802
{
 
803
  if (data->job)
 
804
    g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
 
805
    
 
806
  g_free (data);
 
807
}
 
808
 
 
809
static void
 
810
cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
 
811
                          GtkCupsResult       *result,
 
812
                          gpointer             user_data)
 
813
{
 
814
  CupsJobPollData *data = user_data;
 
815
  ipp_attribute_t *attr;
 
816
  ipp_t *response;
 
817
  int state;
 
818
  gboolean done;
 
819
 
 
820
  if (data->job == NULL)
 
821
    {
 
822
      cups_job_poll_data_free (data);
 
823
      return;
 
824
    }
 
825
 
 
826
  data->counter++;
 
827
  
 
828
  response = gtk_cups_result_get_response (result);
 
829
 
 
830
  state = 0;
 
831
  for (attr = response->attrs; attr != NULL; attr = attr->next) 
 
832
    {
 
833
      if (!attr->name)
 
834
        continue;
 
835
      
 
836
      _CUPS_MAP_ATTR_INT (attr, state, "job-state");
 
837
    }
 
838
  
 
839
  done = FALSE;
 
840
  switch (state)
 
841
    {
 
842
    case IPP_JOB_PENDING:
 
843
    case IPP_JOB_HELD:
 
844
    case IPP_JOB_STOPPED:
 
845
      gtk_print_job_set_status (data->job,
 
846
                                GTK_PRINT_STATUS_PENDING);
 
847
      break;
 
848
    case IPP_JOB_PROCESSING:
 
849
      gtk_print_job_set_status (data->job,
 
850
                                GTK_PRINT_STATUS_PRINTING);
 
851
      break;
 
852
    default:
 
853
    case IPP_JOB_CANCELLED:
 
854
    case IPP_JOB_ABORTED:
 
855
      gtk_print_job_set_status (data->job,
 
856
                                GTK_PRINT_STATUS_FINISHED_ABORTED);
 
857
      done = TRUE;
 
858
      break;
 
859
    case 0:
 
860
    case IPP_JOB_COMPLETED:
 
861
      gtk_print_job_set_status (data->job,
 
862
                                GTK_PRINT_STATUS_FINISHED);
 
863
      done = TRUE;
 
864
      break;
 
865
    }
 
866
 
 
867
  if (!done && data->job != NULL)
 
868
    {
 
869
      guint32 timeout;
 
870
 
 
871
      if (data->counter < 5)
 
872
        timeout = 100;
 
873
      else if (data->counter < 10)
 
874
        timeout = 500;
 
875
      else
 
876
        timeout = 1000;
 
877
      
 
878
      g_timeout_add (timeout, cups_job_info_poll_timeout, data);
 
879
    }
 
880
  else
 
881
    cups_job_poll_data_free (data);    
 
882
}
 
883
 
 
884
static void
 
885
cups_request_job_info (CupsJobPollData *data)
 
886
{
 
887
  GtkCupsRequest *request;
 
888
  gchar *printer_uri;
 
889
 
 
890
  request = gtk_cups_request_new (NULL,
 
891
                                  GTK_CUPS_POST,
 
892
                                  IPP_GET_JOB_ATTRIBUTES,
 
893
                                  NULL,
 
894
                                  NULL,
 
895
                                  NULL);
 
896
 
 
897
  printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
 
898
  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
 
899
                                   "job-uri", NULL, printer_uri);
 
900
  g_free (printer_uri);
 
901
 
 
902
  cups_request_execute (data->print_backend,
 
903
                        request,
 
904
                        (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
 
905
                        data,
 
906
                        NULL);
 
907
}
 
908
 
 
909
static gboolean
 
910
cups_job_info_poll_timeout (gpointer user_data)
 
911
{
 
912
  CupsJobPollData *data = user_data;
 
913
  
 
914
  if (data->job == NULL)
 
915
    cups_job_poll_data_free (data);
 
916
  else
 
917
    cups_request_job_info (data);
 
918
  
 
919
  return FALSE;
 
920
}
 
921
 
 
922
static void
 
923
cups_begin_polling_info (GtkPrintBackendCups *print_backend,
 
924
                         GtkPrintJob         *job,
 
925
                         gint                 job_id)
 
926
{
 
927
  CupsJobPollData *data;
 
928
 
 
929
  data = g_new0 (CupsJobPollData, 1);
 
930
 
 
931
  data->print_backend = print_backend;
 
932
  data->job = job;
 
933
  data->job_id = job_id;
 
934
  data->counter = 0;
 
935
 
 
936
  g_object_weak_ref (G_OBJECT (job), job_object_died, data);
 
937
 
 
938
  cups_request_job_info (data);
 
939
}
 
940
 
 
941
static void
 
942
mark_printer_inactive (GtkPrinter      *printer, 
 
943
                       GtkPrintBackend *backend)
 
944
{
 
945
  gtk_printer_set_is_active (printer, FALSE);
 
946
  g_signal_emit_by_name (backend, "printer-removed", printer);
 
947
}
 
948
 
 
949
static gint
 
950
find_printer (GtkPrinter  *printer, 
 
951
              const gchar *find_name)
 
952
{
 
953
  const gchar *printer_name;
 
954
 
 
955
  printer_name = gtk_printer_get_name (printer);
 
956
  return g_ascii_strcasecmp (printer_name, find_name);
 
957
}
 
958
 
 
959
static void
 
960
cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
 
961
                              GtkCupsResult       *result,
 
962
                              gpointer             user_data)
 
963
{
 
964
  GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
 
965
  ipp_attribute_t *attr;
 
966
  ipp_t *response;
 
967
  gboolean list_has_changed;
 
968
  GList *removed_printer_checklist;
 
969
 
 
970
  list_has_changed = FALSE;
 
971
 
 
972
  GTK_NOTE (PRINTING,
 
973
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
974
 
 
975
  cups_backend->list_printers_pending = FALSE;
 
976
 
 
977
  if (gtk_cups_result_is_error (result))
 
978
    {
 
979
      GTK_NOTE (PRINTING, 
 
980
                g_warning ("CUPS Backend: Error getting printer list: %s", 
 
981
                           gtk_cups_result_get_error_string (result)));
 
982
 
 
983
      goto done;
 
984
    }
 
985
  
 
986
  /* Gather the names of the printers in the current queue
 
987
   * so we may check to see if they were removed 
 
988
   */
 
989
  removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
 
990
                                                                  
 
991
  response = gtk_cups_result_get_response (result);
 
992
 
 
993
  for (attr = response->attrs; attr != NULL; attr = attr->next)
 
994
    {
 
995
      GtkPrinter *printer;
 
996
      const gchar *printer_name = NULL;
 
997
      const gchar *printer_uri = NULL;
 
998
      const gchar *member_uris = NULL;
 
999
      const gchar *location = NULL;
 
1000
      const gchar *description = NULL;
 
1001
      const gchar *state_msg = NULL;
 
1002
      gint state = 0;
 
1003
      gint job_count = 0;
 
1004
      gboolean status_changed = FALSE;
 
1005
      GList *node;
 
1006
      
 
1007
      /* Skip leading attributes until we hit a printer...
 
1008
       */
 
1009
      while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
 
1010
        attr = attr->next;
 
1011
 
 
1012
      if (attr == NULL)
 
1013
        break;
 
1014
 
 
1015
      while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
 
1016
      {
 
1017
        if (!strcmp (attr->name, "printer-name") &&
 
1018
            attr->value_tag == IPP_TAG_NAME)
 
1019
          printer_name = attr->values[0].string.text;
 
1020
        else if (!strcmp (attr->name, "printer-uri-supported") &&
 
1021
                 attr->value_tag == IPP_TAG_URI)
 
1022
          printer_uri = attr->values[0].string.text;
 
1023
        else if (!strcmp (attr->name, "member-uris") &&
 
1024
                 attr->value_tag == IPP_TAG_URI)
 
1025
          member_uris = attr->values[0].string.text;
 
1026
        else if (strcmp (attr->name, "printer-location") == 0)
 
1027
          location = attr->values[0].string.text;
 
1028
        else if (strcmp (attr->name, "printer-info") == 0)
 
1029
          description = attr->values[0].string.text;
 
1030
        else if (strcmp (attr->name, "printer-state-message") == 0)
 
1031
          state_msg = attr->values[0].string.text;
 
1032
        else if (strcmp (attr->name, "printer-state") == 0)
 
1033
          state = attr->values[0].integer;
 
1034
        else if (strcmp (attr->name, "queued-job-count") == 0)
 
1035
          job_count = attr->values[0].integer;
 
1036
        else
 
1037
          {
 
1038
            GTK_NOTE (PRINTING,
 
1039
                      g_print ("CUPS Backend: Attribute %s ignored", attr->name));
 
1040
          }
 
1041
 
 
1042
        attr = attr->next;
 
1043
      }
 
1044
 
 
1045
      if (printer_name == NULL ||
 
1046
          (printer_uri == NULL && member_uris == NULL))
 
1047
      {
 
1048
        if (attr == NULL)
 
1049
          break;
 
1050
        else
 
1051
          continue;
 
1052
      }
 
1053
   
 
1054
      /* remove name from checklist if it was found */
 
1055
      node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
 
1056
      removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
 
1057
 
 
1058
      printer = gtk_print_backend_find_printer (backend, printer_name);
 
1059
      if (!printer)
 
1060
        {
 
1061
          GtkPrinterCups *cups_printer;
 
1062
          char uri[HTTP_MAX_URI];       /* Printer URI */
 
1063
          char method[HTTP_MAX_URI];    /* Method/scheme name */
 
1064
          char username[HTTP_MAX_URI];  /* Username:password */
 
1065
          char hostname[HTTP_MAX_URI];  /* Hostname */
 
1066
          char resource[HTTP_MAX_URI];  /* Resource name */
 
1067
          int  port;                    /* Port number */
 
1068
          
 
1069
          list_has_changed = TRUE;
 
1070
          cups_printer = gtk_printer_cups_new (printer_name, backend);
 
1071
 
 
1072
          cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
 
1073
 
 
1074
          /* Check to see if we are looking at a class */
 
1075
          if (member_uris)
 
1076
            {
 
1077
              cups_printer->printer_uri = g_strdup (member_uris);
 
1078
              /* TODO if member_uris is a class we need to recursivly find a printer */
 
1079
              GTK_NOTE (PRINTING,
 
1080
                        g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
 
1081
            }
 
1082
          else
 
1083
            {
 
1084
              cups_printer->printer_uri = g_strdup (printer_uri);
 
1085
              GTK_NOTE (PRINTING,
 
1086
                        g_print ("CUPS Backend: Found printer %s\n", printer_uri));
 
1087
            }
 
1088
 
 
1089
#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
 
1090
          httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, 
 
1091
                           method, sizeof (method), 
 
1092
                           username, sizeof (username),
 
1093
                           hostname, sizeof (hostname),
 
1094
                           &port, 
 
1095
                           resource, sizeof (resource));
 
1096
 
 
1097
#else
 
1098
          httpSeparate (cups_printer->printer_uri, 
 
1099
                        method, 
 
1100
                        username, 
 
1101
                        hostname,
 
1102
                        &port, 
 
1103
                        resource);
 
1104
#endif
 
1105
 
 
1106
          if (!strncmp (resource, "/printers/", 10))
 
1107
            {
 
1108
              cups_printer->ppd_name = g_strdup (resource + 10);
 
1109
              GTK_NOTE (PRINTING,
 
1110
                        g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, printer_name));
 
1111
            }
 
1112
 
 
1113
          gethostname (uri, sizeof(uri));
 
1114
          if (strcasecmp (uri, hostname) == 0)
 
1115
            strcpy (hostname, "localhost");
 
1116
 
 
1117
          cups_printer->hostname = g_strdup (hostname);
 
1118
          cups_printer->port = port;
 
1119
          
 
1120
          printer = GTK_PRINTER (cups_printer);
 
1121
          
 
1122
          if (cups_backend->default_printer != NULL &&
 
1123
              strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
 
1124
            gtk_printer_set_is_default (printer, TRUE);
 
1125
 
 
1126
          
 
1127
          gtk_print_backend_add_printer (backend, printer);
 
1128
        }
 
1129
      else
 
1130
        g_object_ref (printer);
 
1131
 
 
1132
      if (!gtk_printer_is_active (printer))
 
1133
        {
 
1134
          gtk_printer_set_is_active (printer, TRUE);
 
1135
          gtk_printer_set_is_new (printer, TRUE);
 
1136
          list_has_changed = TRUE;
 
1137
        }
 
1138
 
 
1139
      if (gtk_printer_is_new (printer))
 
1140
        {
 
1141
          g_signal_emit_by_name (backend, "printer-added", printer);
 
1142
 
 
1143
          gtk_printer_set_is_new (printer, FALSE);
 
1144
        }
 
1145
 
 
1146
#if 0
 
1147
      /* Getting printer info with separate requests overwhelms cups
 
1148
       * when the printer list has more than a handful of printers.
 
1149
       */
 
1150
      cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
 
1151
#endif
 
1152
 
 
1153
      GTK_PRINTER_CUPS (printer)->state = state;
 
1154
      status_changed = gtk_printer_set_job_count (printer, job_count);
 
1155
      status_changed |= gtk_printer_set_location (printer, location);
 
1156
      status_changed |= gtk_printer_set_description (printer, description);
 
1157
      status_changed |= gtk_printer_set_state_message (printer, state_msg);
 
1158
 
 
1159
      if (status_changed)
 
1160
        g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
 
1161
                               "printer-status-changed", printer);
 
1162
 
 
1163
      /* The ref is held by GtkPrintBackend, in add_printer() */
 
1164
      g_object_unref (printer);
 
1165
 
 
1166
      
 
1167
      if (attr == NULL)
 
1168
        break;
 
1169
    }
 
1170
 
 
1171
  /* look at the removed printers checklist and mark any printer
 
1172
     as inactive if it is in the list, emitting a printer_removed signal */
 
1173
  if (removed_printer_checklist != NULL)
 
1174
    {
 
1175
      g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
 
1176
      g_list_free (removed_printer_checklist);
 
1177
      list_has_changed = TRUE;
 
1178
    }
 
1179
  
 
1180
 done:
 
1181
 
 
1182
  if (list_has_changed)
 
1183
    g_signal_emit_by_name (backend, "printer-list-changed");
 
1184
  
 
1185
  gtk_print_backend_set_list_done (backend);
 
1186
}
 
1187
 
 
1188
static gboolean
 
1189
cups_request_printer_list (GtkPrintBackendCups *cups_backend)
 
1190
{
 
1191
  GtkCupsRequest *request;
 
1192
  static const char * const pattrs[] =  /* Attributes we're interested in */
 
1193
    {
 
1194
      "printer-name",
 
1195
      "printer-uri-supported",
 
1196
      "member-uris",
 
1197
      "printer-location",
 
1198
      "printer-info",
 
1199
      "printer-state-message",
 
1200
      "printer-state",
 
1201
      "queued-job-count"
 
1202
    };
 
1203
 
 
1204
  if (cups_backend->list_printers_pending ||
 
1205
      !cups_backend->got_default_printer)
 
1206
    return TRUE;
 
1207
 
 
1208
  cups_backend->list_printers_pending = TRUE;
 
1209
 
 
1210
  request = gtk_cups_request_new (NULL,
 
1211
                                  GTK_CUPS_POST,
 
1212
                                  CUPS_GET_PRINTERS,
 
1213
                                  NULL,
 
1214
                                  NULL,
 
1215
                                  NULL);
 
1216
 
 
1217
  gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 
1218
                                    "requested-attributes", G_N_ELEMENTS (pattrs),
 
1219
                                    NULL, pattrs);
 
1220
 
 
1221
  cups_request_execute (cups_backend,
 
1222
                        request,
 
1223
                        (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
 
1224
                        request,
 
1225
                        NULL);
 
1226
 
 
1227
  return TRUE;
 
1228
}
 
1229
 
 
1230
static void
 
1231
cups_get_printer_list (GtkPrintBackend *backend)
 
1232
{
 
1233
  GtkPrintBackendCups *cups_backend;
 
1234
 
 
1235
  cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
 
1236
  if (cups_backend->list_printers_poll == 0)
 
1237
    {
 
1238
      cups_request_printer_list (cups_backend);
 
1239
      cups_backend->list_printers_poll = g_timeout_add (3000,
 
1240
                                                        (GSourceFunc) cups_request_printer_list,
 
1241
                                                        backend);
 
1242
    }
 
1243
}
 
1244
 
 
1245
typedef struct {
 
1246
  GtkPrinterCups *printer;
 
1247
  GIOChannel *ppd_io;
 
1248
  http_t *http;
 
1249
} GetPPDData;
 
1250
 
 
1251
static void
 
1252
get_ppd_data_free (GetPPDData *data)
 
1253
{
 
1254
  GTK_NOTE (PRINTING,
 
1255
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
1256
  httpClose (data->http);
 
1257
  g_io_channel_unref (data->ppd_io);
 
1258
  g_object_unref (data->printer);
 
1259
  g_free (data);
 
1260
}
 
1261
 
 
1262
static void
 
1263
cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
 
1264
                     GtkCupsResult       *result,
 
1265
                     GetPPDData          *data)
 
1266
{
 
1267
  ipp_t *response;
 
1268
  GtkPrinter *printer;
 
1269
 
 
1270
  GTK_NOTE (PRINTING,
 
1271
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
1272
 
 
1273
  printer = GTK_PRINTER (data->printer);
 
1274
  GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
 
1275
 
 
1276
  if (gtk_cups_result_is_error (result))
 
1277
    {
 
1278
      gboolean success = FALSE;
 
1279
 
 
1280
      /* if we get a 404 then it is just a raw printer without a ppd
 
1281
         and not an error */
 
1282
      if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
 
1283
          (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
 
1284
        {
 
1285
          gtk_printer_set_has_details (printer, TRUE);
 
1286
          success = TRUE;
 
1287
        } 
 
1288
        
 
1289
      g_signal_emit_by_name (printer, "details-acquired", success);
 
1290
      return;
 
1291
    }
 
1292
 
 
1293
  response = gtk_cups_result_get_response (result);
 
1294
 
 
1295
  /* let ppdOpenFd take over the ownership of the open file */
 
1296
  g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
 
1297
  data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
 
1298
  
 
1299
  gtk_printer_set_has_details (printer, TRUE);
 
1300
  g_signal_emit_by_name (printer, "details-acquired", TRUE);
 
1301
}
 
1302
 
 
1303
static void
 
1304
cups_request_ppd (GtkPrinter *printer)
 
1305
{
 
1306
  GError *error;
 
1307
  GtkPrintBackend *print_backend;
 
1308
  GtkPrinterCups *cups_printer;
 
1309
  GtkCupsRequest *request;
 
1310
  char *ppd_filename;
 
1311
  gchar *resource;
 
1312
  http_t *http;
 
1313
  GetPPDData *data;
 
1314
  int fd;
 
1315
 
 
1316
  cups_printer = GTK_PRINTER_CUPS (printer);
 
1317
 
 
1318
  error = NULL;
 
1319
 
 
1320
  GTK_NOTE (PRINTING,
 
1321
            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
1322
 
 
1323
  http = httpConnectEncrypt (cups_printer->hostname, 
 
1324
                             cups_printer->port,
 
1325
                             cupsEncryption ());
 
1326
  
 
1327
  data = g_new0 (GetPPDData, 1);
 
1328
 
 
1329
  fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
 
1330
                        &ppd_filename, 
 
1331
                        &error);
 
1332
 
 
1333
#ifdef G_ENABLE_DEBUG 
 
1334
  /* If we are debugging printing don't delete the tmp files */
 
1335
  if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
 
1336
    unlink (ppd_filename);
 
1337
#else
 
1338
  unlink (ppd_filename);
 
1339
#endif /* G_ENABLE_DEBUG */
 
1340
 
 
1341
  if (error != NULL)
 
1342
    {
 
1343
      GTK_NOTE (PRINTING, 
 
1344
                g_warning ("CUPS Backend: Failed to create temp file, %s\n", 
 
1345
                           error->message));
 
1346
      g_error_free (error);
 
1347
      httpClose (http);
 
1348
      g_free (ppd_filename);
 
1349
      g_free (data);
 
1350
 
 
1351
      g_signal_emit_by_name (printer, "details-acquired", FALSE);
 
1352
      return;
 
1353
    }
 
1354
    
 
1355
  data->http = http;
 
1356
  fchmod (fd, S_IRUSR | S_IWUSR);
 
1357
  data->ppd_io = g_io_channel_unix_new (fd);
 
1358
  g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
 
1359
  g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
 
1360
 
 
1361
  data->printer = g_object_ref (printer);
 
1362
 
 
1363
  resource = g_strdup_printf ("/printers/%s.ppd", 
 
1364
                              gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
 
1365
 
 
1366
  request = gtk_cups_request_new (data->http,
 
1367
                                  GTK_CUPS_GET,
 
1368
                                  0,
 
1369
                                  data->ppd_io,
 
1370
                                  cups_printer->hostname,
 
1371
                                  resource);
 
1372
 
 
1373
  GTK_NOTE (PRINTING,
 
1374
            g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
 
1375
 
 
1376
  g_free (resource);
 
1377
  g_free (ppd_filename);
 
1378
 
 
1379
  cups_printer->reading_ppd = TRUE;
 
1380
 
 
1381
  print_backend = gtk_printer_get_backend (printer);
 
1382
 
 
1383
  cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
 
1384
                        request,
 
1385
                        (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
 
1386
                        data,
 
1387
                        (GDestroyNotify)get_ppd_data_free);
 
1388
}
 
1389
 
 
1390
 
 
1391
static void
 
1392
cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
 
1393
                                 GtkCupsResult       *result,
 
1394
                                 gpointer             user_data)
 
1395
{
 
1396
  ipp_t *response;
 
1397
  ipp_attribute_t *attr;
 
1398
 
 
1399
  response = gtk_cups_result_get_response (result);
 
1400
  
 
1401
  if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
 
1402
    print_backend->default_printer = g_strdup (attr->values[0].string.text);
 
1403
 
 
1404
  print_backend->got_default_printer = TRUE;
 
1405
 
 
1406
  /* Make sure to kick off get_printers if we are polling it, 
 
1407
   * as we could have blocked this reading the default printer 
 
1408
   */
 
1409
  if (print_backend->list_printers_poll != 0)
 
1410
    cups_request_printer_list (print_backend);
 
1411
}
 
1412
 
 
1413
static void
 
1414
cups_request_default_printer (GtkPrintBackendCups *print_backend)
 
1415
{
 
1416
  GtkCupsRequest *request;
 
1417
  const char *str;
 
1418
 
 
1419
  if ((str = g_getenv ("LPDEST")) != NULL)
 
1420
    {
 
1421
      print_backend->default_printer = g_strdup (str);
 
1422
      print_backend->got_default_printer = TRUE;
 
1423
      return;
 
1424
    }
 
1425
  else if ((str = g_getenv ("PRINTER")) != NULL &&
 
1426
           strcmp (str, "lp") != 0)
 
1427
    {
 
1428
      print_backend->default_printer = g_strdup (str);
 
1429
      print_backend->got_default_printer = TRUE;
 
1430
      return;
 
1431
    }
 
1432
  
 
1433
  request = gtk_cups_request_new (NULL,
 
1434
                                  GTK_CUPS_POST,
 
1435
                                  CUPS_GET_DEFAULT,
 
1436
                                  NULL,
 
1437
                                  NULL,
 
1438
                                  NULL);
 
1439
  
 
1440
  cups_request_execute (print_backend,
 
1441
                        request,
 
1442
                        (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
 
1443
                        g_object_ref (print_backend),
 
1444
                        g_object_unref);
 
1445
}
 
1446
 
 
1447
static void
 
1448
cups_printer_request_details (GtkPrinter *printer)
 
1449
{
 
1450
  GtkPrinterCups *cups_printer;
 
1451
 
 
1452
  cups_printer = GTK_PRINTER_CUPS (printer);
 
1453
  if (!cups_printer->reading_ppd && 
 
1454
      gtk_printer_cups_get_ppd (cups_printer) == NULL)
 
1455
    cups_request_ppd (printer); 
 
1456
}
 
1457
 
 
1458
static char *
 
1459
ppd_text_to_utf8 (ppd_file_t *ppd_file, 
 
1460
                  const char *text)
 
1461
{
 
1462
  const char *encoding = NULL;
 
1463
  char *res;
 
1464
  
 
1465
  if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
 
1466
    {
 
1467
      return g_strdup (text);
 
1468
    }
 
1469
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
 
1470
    {
 
1471
      encoding = "ISO-8859-1";
 
1472
    }
 
1473
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
 
1474
    {
 
1475
      encoding = "ISO-8859-2";
 
1476
    }
 
1477
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
 
1478
    {
 
1479
      encoding = "ISO-8859-5";
 
1480
    }
 
1481
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
 
1482
    {
 
1483
      encoding = "SHIFT-JIS";
 
1484
    }
 
1485
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
 
1486
    {
 
1487
      encoding = "MACINTOSH";
 
1488
    }
 
1489
  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
 
1490
    {
 
1491
      encoding = "WINDOWS-1252";
 
1492
    }
 
1493
  else 
 
1494
    {
 
1495
      /* Fallback, try iso-8859-1... */
 
1496
      encoding = "ISO-8859-1";
 
1497
    }
 
1498
 
 
1499
  res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
 
1500
 
 
1501
  if (res == NULL)
 
1502
    {
 
1503
      GTK_NOTE (PRINTING,
 
1504
                g_warning ("CUPS Backend: Unable to convert PPD text\n"));
 
1505
      res = g_strdup ("???");
 
1506
    }
 
1507
  
 
1508
  return res;
 
1509
}
 
1510
 
 
1511
/* TODO: Add more translations for common settings here */
 
1512
 
 
1513
static const struct {
 
1514
  const char *keyword;
 
1515
  const char *translation;
 
1516
} cups_option_translations[] = {
 
1517
  { "Duplex", N_("Two Sided") },
 
1518
  { "MediaType", N_("Paper Type") },
 
1519
  { "InputSlot", N_("Paper Source") },
 
1520
  { "OutputBin", N_("Output Tray") },
 
1521
};
 
1522
 
 
1523
 
 
1524
static const struct {
 
1525
  const char *keyword;
 
1526
  const char *choice;
 
1527
  const char *translation;
 
1528
} cups_choice_translations[] = {
 
1529
  { "Duplex", "None", N_("One Sided") },
 
1530
  { "InputSlot", "Auto", N_("Auto Select") },
 
1531
  { "InputSlot", "AutoSelect", N_("Auto Select") },
 
1532
  { "InputSlot", "Default", N_("Printer Default") },
 
1533
  { "InputSlot", "None", N_("Printer Default") },
 
1534
  { "InputSlot", "PrinterDefault", N_("Printer Default") },
 
1535
  { "InputSlot", "Unspecified", N_("Auto Select") },
 
1536
};
 
1537
 
 
1538
static const struct {
 
1539
  const char *ppd_keyword;
 
1540
  const char *name;
 
1541
} option_names[] = {
 
1542
  {"Duplex", "gtk-duplex" },
 
1543
  {"MediaType", "gtk-paper-type"},
 
1544
  {"InputSlot", "gtk-paper-source"},
 
1545
  {"OutputBin", "gtk-output-tray"},
 
1546
};
 
1547
 
 
1548
/* keep sorted when changing */
 
1549
static const char *color_option_whitelist[] = {
 
1550
  "BRColorEnhancement",
 
1551
  "BRColorMatching",
 
1552
  "BRColorMatching",
 
1553
  "BRColorMode",
 
1554
  "BRGammaValue",
 
1555
  "BRImprovedGray",
 
1556
  "BlackSubstitution",
 
1557
  "ColorModel",
 
1558
  "HPCMYKInks",
 
1559
  "HPCSGraphics",
 
1560
  "HPCSImages",
 
1561
  "HPCSText",
 
1562
  "HPColorSmart",
 
1563
  "RPSBlackMode",
 
1564
  "RPSBlackOverPrint",
 
1565
  "Rcmyksimulation",
 
1566
};
 
1567
 
 
1568
/* keep sorted when changing */
 
1569
static const char *color_group_whitelist[] = {
 
1570
  "ColorPage",
 
1571
  "FPColorWise1",
 
1572
  "FPColorWise2",
 
1573
  "FPColorWise3",
 
1574
  "FPColorWise4",
 
1575
  "FPColorWise5",
 
1576
  "HPColorOptionsPanel",
 
1577
};
 
1578
  
 
1579
/* keep sorted when changing */
 
1580
static const char *image_quality_option_whitelist[] = {
 
1581
  "BRDocument",
 
1582
  "BRHalfTonePattern",
 
1583
  "BRNormalPrt",
 
1584
  "BRPrintQuality",
 
1585
  "BitsPerPixel",
 
1586
  "Darkness",
 
1587
  "Dithering",
 
1588
  "EconoMode",
 
1589
  "Economode",
 
1590
  "HPEconoMode",
 
1591
  "HPEdgeControl",
 
1592
  "HPGraphicsHalftone",
 
1593
  "HPHalftone",
 
1594
  "HPLJDensity",
 
1595
  "HPPhotoHalftone",
 
1596
  "OutputMode",
 
1597
  "REt",
 
1598
  "RPSBitsPerPixel",
 
1599
  "RPSDitherType",
 
1600
  "Resolution",
 
1601
  "ScreenLock",
 
1602
  "Smoothing",
 
1603
  "TonerSaveMode",
 
1604
  "UCRGCRForImage",
 
1605
};
 
1606
 
 
1607
/* keep sorted when changing */
 
1608
static const char *image_quality_group_whitelist[] = {
 
1609
  "FPImageQuality1",
 
1610
  "FPImageQuality2",
 
1611
  "FPImageQuality3",
 
1612
  "ImageQualityPage",
 
1613
};
 
1614
 
 
1615
/* keep sorted when changing */
 
1616
static const char * finishing_option_whitelist[] = {
 
1617
  "BindColor",
 
1618
  "BindEdge",
 
1619
  "BindType",
 
1620
  "BindWhen",
 
1621
  "Booklet",
 
1622
  "FoldType",
 
1623
  "FoldWhen",
 
1624
  "HPStaplerOptions",
 
1625
  "Jog",
 
1626
  "Slipsheet",
 
1627
  "Sorter",
 
1628
  "StapleLocation",
 
1629
  "StapleOrientation",
 
1630
  "StapleWhen",
 
1631
  "StapleX",
 
1632
  "StapleY",
 
1633
};
 
1634
 
 
1635
/* keep sorted when changing */
 
1636
static const char *finishing_group_whitelist[] = {
 
1637
  "FPFinishing1",
 
1638
  "FPFinishing2",
 
1639
  "FPFinishing3",
 
1640
  "FPFinishing4",
 
1641
  "FinishingPage",
 
1642
  "HPFinishingPanel",
 
1643
};
 
1644
 
 
1645
/* keep sorted when changing */
 
1646
static const char *cups_option_blacklist[] = {
 
1647
  "Collate",
 
1648
  "Copies", 
 
1649
  "OutputOrder",
 
1650
  "PageRegion",
 
1651
  "PageSize",
 
1652
};
 
1653
 
 
1654
static char *
 
1655
get_option_text (ppd_file_t   *ppd_file, 
 
1656
                 ppd_option_t *option)
 
1657
{
 
1658
  int i;
 
1659
  char *utf8;
 
1660
  
 
1661
  for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
 
1662
    {
 
1663
      if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
 
1664
        return g_strdup (_(cups_option_translations[i].translation));
 
1665
    }
 
1666
 
 
1667
  utf8 = ppd_text_to_utf8 (ppd_file, option->text);
 
1668
 
 
1669
  /* Some ppd files have spaces in the text before the colon */
 
1670
  g_strchomp (utf8);
 
1671
  
 
1672
  return utf8;
 
1673
}
 
1674
 
 
1675
static char *
 
1676
get_choice_text (ppd_file_t   *ppd_file, 
 
1677
                 ppd_choice_t *choice)
 
1678
{
 
1679
  int i;
 
1680
  ppd_option_t *option = choice->option;
 
1681
  const char *keyword = option->keyword;
 
1682
  
 
1683
  for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
 
1684
    {
 
1685
      if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
 
1686
          strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
 
1687
        return g_strdup (_(cups_choice_translations[i].translation));
 
1688
    }
 
1689
  return ppd_text_to_utf8 (ppd_file, choice->text);
 
1690
}
 
1691
 
 
1692
static gboolean
 
1693
group_has_option (ppd_group_t  *group, 
 
1694
                  ppd_option_t *option)
 
1695
{
 
1696
  int i;
 
1697
 
 
1698
  if (group == NULL)
 
1699
    return FALSE;
 
1700
  
 
1701
  if (group->num_options > 0 &&
 
1702
      option >= group->options && option < group->options + group->num_options)
 
1703
    return TRUE;
 
1704
  
 
1705
  for (i = 0; i < group->num_subgroups; i++)
 
1706
    {
 
1707
      if (group_has_option (&group->subgroups[i],option))
 
1708
        return TRUE;
 
1709
    }
 
1710
  return FALSE;
 
1711
}
 
1712
 
 
1713
static void
 
1714
set_option_off (GtkPrinterOption *option)
 
1715
{
 
1716
  /* Any of these will do, _set only applies the value
 
1717
   * if its allowed of the option */
 
1718
  gtk_printer_option_set (option, "False");
 
1719
  gtk_printer_option_set (option, "Off");
 
1720
  gtk_printer_option_set (option, "None");
 
1721
}
 
1722
 
 
1723
static gboolean
 
1724
value_is_off (const char *value)
 
1725
{
 
1726
  return  (strcasecmp (value, "None") == 0 ||
 
1727
           strcasecmp (value, "Off") == 0 ||
 
1728
           strcasecmp (value, "False") == 0);
 
1729
}
 
1730
 
 
1731
static char *
 
1732
ppd_group_name (ppd_group_t *group)
 
1733
{
 
1734
#if CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR == 1 && CUPS_VERSION_PATCH >= 18) 
 
1735
  return group->name;
 
1736
#else
 
1737
  return group->text;
 
1738
#endif
 
1739
}
 
1740
 
 
1741
static int
 
1742
available_choices (ppd_file_t     *ppd,
 
1743
                   ppd_option_t   *option,
 
1744
                   ppd_choice_t ***available,
 
1745
                   gboolean        keep_if_only_one_option)
 
1746
{
 
1747
  ppd_option_t *other_option;
 
1748
  int i, j;
 
1749
  gchar *conflicts;
 
1750
  ppd_const_t *constraint;
 
1751
  const char *choice, *other_choice;
 
1752
  ppd_option_t *option1, *option2;
 
1753
  ppd_group_t *installed_options;
 
1754
  int num_conflicts;
 
1755
  gboolean all_default;
 
1756
  int add_auto;
 
1757
 
 
1758
  if (available)
 
1759
    *available = NULL;
 
1760
 
 
1761
  conflicts = g_new0 (char, option->num_choices);
 
1762
 
 
1763
  installed_options = NULL;
 
1764
  for (i = 0; i < ppd->num_groups; i++)
 
1765
    {
 
1766
      char *name; 
 
1767
 
 
1768
      name = ppd_group_name (&ppd->groups[i]);
 
1769
      if (strcmp (name, "InstallableOptions") == 0)
 
1770
        {
 
1771
          installed_options = &ppd->groups[i];
 
1772
          break;
 
1773
        }
 
1774
    }
 
1775
 
 
1776
  for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
 
1777
    {
 
1778
      option1 = ppdFindOption (ppd, constraint->option1);
 
1779
      if (option1 == NULL)
 
1780
        continue;
 
1781
 
 
1782
      option2 = ppdFindOption (ppd, constraint->option2);
 
1783
      if (option2 == NULL)
 
1784
        continue;
 
1785
 
 
1786
      if (option == option1)
 
1787
        {
 
1788
          choice = constraint->choice1;
 
1789
          other_option = option2;
 
1790
          other_choice = constraint->choice2;
 
1791
        }
 
1792
      else if (option == option2)
 
1793
        {
 
1794
          choice = constraint->choice2;
 
1795
          other_option = option1;
 
1796
          other_choice = constraint->choice1;
 
1797
        }
 
1798
      else
 
1799
        continue;
 
1800
 
 
1801
      /* We only care of conflicts with installed_options and
 
1802
         PageSize */
 
1803
      if (!group_has_option (installed_options, other_option) &&
 
1804
          (strcmp (other_option->keyword, "PageSize") != 0))
 
1805
        continue;
 
1806
 
 
1807
      if (*other_choice == 0)
 
1808
        {
 
1809
          /* Conflict only if the installed option is not off */
 
1810
          if (value_is_off (other_option->defchoice))
 
1811
            continue;
 
1812
        }
 
1813
      /* Conflict if the installed option has the specified default */
 
1814
      else if (strcasecmp (other_choice, other_option->defchoice) != 0)
 
1815
        continue;
 
1816
 
 
1817
      if (*choice == 0)
 
1818
        {
 
1819
          /* Conflict with all non-off choices */
 
1820
          for (j = 0; j < option->num_choices; j++)
 
1821
            {
 
1822
              if (!value_is_off (option->choices[j].choice))
 
1823
                conflicts[j] = 1;
 
1824
            }
 
1825
        }
 
1826
      else
 
1827
        {
 
1828
          for (j = 0; j < option->num_choices; j++)
 
1829
            {
 
1830
              if (strcasecmp (option->choices[j].choice, choice) == 0)
 
1831
                conflicts[j] = 1;
 
1832
            }
 
1833
        }
 
1834
    }
 
1835
 
 
1836
  num_conflicts = 0;
 
1837
  all_default = TRUE;
 
1838
  for (j = 0; j < option->num_choices; j++)
 
1839
    {
 
1840
      if (conflicts[j])
 
1841
        num_conflicts++;
 
1842
      else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
 
1843
        all_default = FALSE;
 
1844
    }
 
1845
 
 
1846
  if ((all_default && !keep_if_only_one_option) ||
 
1847
      (num_conflicts == option->num_choices))
 
1848
    {
 
1849
      g_free (conflicts);
 
1850
 
 
1851
      return 0;
 
1852
    }
 
1853
 
 
1854
  /* Some ppds don't have a "use printer default" option for
 
1855
   * InputSlot. This means you always have to select a particular slot,
 
1856
   * and you can't auto-pick source based on the paper size. To support
 
1857
   * this we always add an auto option if there isn't one already. If
 
1858
   * the user chooses the generated option we don't send any InputSlot
 
1859
   * value when printing. The way we detect existing auto-cases is based
 
1860
   * on feedback from Michael Sweet of cups fame.
 
1861
   */
 
1862
  add_auto = 0;
 
1863
  if (strcmp (option->keyword, "InputSlot") == 0)
 
1864
    {
 
1865
      gboolean found_auto = FALSE;
 
1866
      for (j = 0; j < option->num_choices; j++)
 
1867
        {
 
1868
          if (!conflicts[j])
 
1869
            {
 
1870
              if (strcmp (option->choices[j].choice, "Auto") == 0 ||
 
1871
                  strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
 
1872
                  strcmp (option->choices[j].choice, "Default") == 0 ||
 
1873
                  strcmp (option->choices[j].choice, "None") == 0 ||
 
1874
                  strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
 
1875
                  strcmp (option->choices[j].choice, "Unspecified") == 0 ||
 
1876
                  option->choices[j].code == NULL ||
 
1877
                  option->choices[j].code[0] == 0)
 
1878
                {
 
1879
                  found_auto = TRUE;
 
1880
                  break;
 
1881
                }
 
1882
            }
 
1883
        }
 
1884
 
 
1885
      if (!found_auto)
 
1886
        add_auto = 1;
 
1887
    }
 
1888
  
 
1889
  if (available)
 
1890
    {
 
1891
      *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
 
1892
 
 
1893
      i = 0;
 
1894
      for (j = 0; j < option->num_choices; j++)
 
1895
        {
 
1896
          if (!conflicts[j])
 
1897
            (*available)[i++] = &option->choices[j];
 
1898
        }
 
1899
 
 
1900
      if (add_auto) 
 
1901
        (*available)[i++] = NULL;
 
1902
    }
 
1903
 
 
1904
  g_free (conflicts);
 
1905
  
 
1906
  return option->num_choices - num_conflicts + add_auto;
 
1907
}
 
1908
 
 
1909
static GtkPrinterOption *
 
1910
create_pickone_option (ppd_file_t   *ppd_file,
 
1911
                       ppd_option_t *ppd_option,
 
1912
                       const gchar  *gtk_name)
 
1913
{
 
1914
  GtkPrinterOption *option;
 
1915
  ppd_choice_t **available;
 
1916
  char *label;
 
1917
  int n_choices;
 
1918
  int i;
 
1919
#ifdef HAVE_CUPS_API_1_2
 
1920
  ppd_coption_t *coption;
 
1921
#endif
 
1922
 
 
1923
  g_assert (ppd_option->ui == PPD_UI_PICKONE);
 
1924
  
 
1925
  option = NULL;
 
1926
 
 
1927
  n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
 
1928
  if (n_choices > 0)
 
1929
    {
 
1930
      
 
1931
      /* right now only support one parameter per custom option 
 
1932
       * if more than one print warning and only offer the default choices
 
1933
       */
 
1934
 
 
1935
      label = get_option_text (ppd_file, ppd_option);
 
1936
 
 
1937
#ifdef HAVE_CUPS_API_1_2
 
1938
      coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
 
1939
 
 
1940
      if (coption)
 
1941
        {
 
1942
          ppd_cparam_t *cparam;
 
1943
 
 
1944
          cparam = ppdFirstCustomParam (coption);
 
1945
 
 
1946
          if (ppdNextCustomParam (coption) == NULL)
 
1947
            {
 
1948
              switch (cparam->type)
 
1949
                {
 
1950
                case PPD_CUSTOM_INT:
 
1951
                  option = gtk_printer_option_new (gtk_name, label,
 
1952
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
 
1953
                  break;
 
1954
                case PPD_CUSTOM_PASSCODE:
 
1955
                  option = gtk_printer_option_new (gtk_name, label,
 
1956
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
 
1957
                  break;
 
1958
                case PPD_CUSTOM_PASSWORD:
 
1959
                    option = gtk_printer_option_new (gtk_name, label,
 
1960
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
 
1961
                  break;
 
1962
               case PPD_CUSTOM_REAL:
 
1963
                    option = gtk_printer_option_new (gtk_name, label,
 
1964
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
 
1965
                  break;
 
1966
                case PPD_CUSTOM_STRING:
 
1967
                  option = gtk_printer_option_new (gtk_name, label,
 
1968
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
 
1969
                  break;
 
1970
#ifdef PRINT_IGNORED_OPTIONS
 
1971
                case PPD_CUSTOM_POINTS: 
 
1972
                  g_warning ("CUPS Backend: PPD Custom Points Option not supported");
 
1973
                  break;
 
1974
                case PPD_CUSTOM_CURVE:
 
1975
                  g_warning ("CUPS Backend: PPD Custom Curve Option not supported");
 
1976
                  break;
 
1977
                case PPD_CUSTOM_INVCURVE:       
 
1978
                  g_warning ("CUPS Backend: PPD Custom Inverse Curve Option not supported");
 
1979
                  break;
 
1980
#endif
 
1981
                default: 
 
1982
                  break;
 
1983
                }
 
1984
            }
 
1985
#ifdef PRINT_IGNORED_OPTIONS
 
1986
          else
 
1987
            g_warning ("CUPS Backend: Multi-parameter PPD Custom Option not supported");
 
1988
#endif
 
1989
        }
 
1990
#endif /* HAVE_CUPS_API_1_2 */
 
1991
 
 
1992
      if (!option)
 
1993
        option = gtk_printer_option_new (gtk_name, label,
 
1994
                                         GTK_PRINTER_OPTION_TYPE_PICKONE);
 
1995
      g_free (label);
 
1996
      
 
1997
      gtk_printer_option_allocate_choices (option, n_choices);
 
1998
      for (i = 0; i < n_choices; i++)
 
1999
        {
 
2000
          if (available[i] == NULL)
 
2001
            {
 
2002
              /* This was auto-added */
 
2003
              option->choices[i] = g_strdup ("gtk-ignore-value");
 
2004
              option->choices_display[i] = g_strdup (_("Printer Default"));
 
2005
            }
 
2006
          else
 
2007
            {
 
2008
              option->choices[i] = g_strdup (available[i]->choice);
 
2009
              option->choices_display[i] = get_choice_text (ppd_file, available[i]);
 
2010
            }
 
2011
        }
 
2012
      gtk_printer_option_set (option, ppd_option->defchoice);
 
2013
    }
 
2014
#ifdef PRINT_IGNORED_OPTIONS
 
2015
  else
 
2016
    g_warning ("CUPS Backend: Ignoring pickone %s\n", ppd_option->text);
 
2017
#endif
 
2018
  g_free (available);
 
2019
 
 
2020
  return option;
 
2021
}
 
2022
 
 
2023
static GtkPrinterOption *
 
2024
create_boolean_option (ppd_file_t   *ppd_file,
 
2025
                       ppd_option_t *ppd_option,
 
2026
                       const gchar  *gtk_name)
 
2027
{
 
2028
  GtkPrinterOption *option;
 
2029
  ppd_choice_t **available;
 
2030
  char *label;
 
2031
  int n_choices;
 
2032
 
 
2033
  g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
 
2034
  
 
2035
  option = NULL;
 
2036
 
 
2037
  n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
 
2038
  if (n_choices == 2)
 
2039
    {
 
2040
      label = get_option_text (ppd_file, ppd_option);
 
2041
      option = gtk_printer_option_new (gtk_name, label,
 
2042
                                       GTK_PRINTER_OPTION_TYPE_BOOLEAN);
 
2043
      g_free (label);
 
2044
      
 
2045
      gtk_printer_option_allocate_choices (option, 2);
 
2046
      option->choices[0] = g_strdup ("True");
 
2047
      option->choices_display[0] = g_strdup ("True");
 
2048
      option->choices[1] = g_strdup ("False");
 
2049
      option->choices_display[1] = g_strdup ("False");
 
2050
      
 
2051
      gtk_printer_option_set (option, ppd_option->defchoice);
 
2052
    }
 
2053
#ifdef PRINT_IGNORED_OPTIONS
 
2054
  else
 
2055
    g_warning ("CUPS Backend: Ignoring boolean %s\n", ppd_option->text);
 
2056
#endif
 
2057
  g_free (available);
 
2058
 
 
2059
  return option;
 
2060
}
 
2061
 
 
2062
static gchar *
 
2063
get_option_name (const gchar *keyword)
 
2064
{
 
2065
  int i;
 
2066
 
 
2067
  for (i = 0; i < G_N_ELEMENTS (option_names); i++)
 
2068
    if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
 
2069
      return g_strdup (option_names[i].name);
 
2070
 
 
2071
  return g_strdup_printf ("cups-%s", keyword);
 
2072
}
 
2073
 
 
2074
static int
 
2075
strptr_cmp (const void *a, 
 
2076
            const void *b)
 
2077
{
 
2078
  char **aa = (char **)a;
 
2079
  char **bb = (char **)b;
 
2080
  return strcmp (*aa, *bb);
 
2081
}
 
2082
 
 
2083
 
 
2084
static gboolean
 
2085
string_in_table (gchar       *str, 
 
2086
                 const gchar *table[], 
 
2087
                 gint         table_len)
 
2088
{
 
2089
  return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
 
2090
}
 
2091
 
 
2092
#define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
 
2093
 
 
2094
static void
 
2095
handle_option (GtkPrinterOptionSet *set,
 
2096
               ppd_file_t          *ppd_file,
 
2097
               ppd_option_t        *ppd_option,
 
2098
               ppd_group_t         *toplevel_group,
 
2099
               GtkPrintSettings    *settings)
 
2100
{
 
2101
  GtkPrinterOption *option;
 
2102
  char *name;
 
2103
 
 
2104
  if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
 
2105
    return;
 
2106
 
 
2107
  name = get_option_name (ppd_option->keyword);
 
2108
 
 
2109
  option = NULL;
 
2110
  if (ppd_option->ui == PPD_UI_PICKONE)
 
2111
    {
 
2112
      option = create_pickone_option (ppd_file, ppd_option, name);
 
2113
    }
 
2114
  else if (ppd_option->ui == PPD_UI_BOOLEAN)
 
2115
    {
 
2116
      option = create_boolean_option (ppd_file, ppd_option, name);
 
2117
    }
 
2118
#ifdef PRINT_IGNORED_OPTIONS
 
2119
  else
 
2120
    g_warning ("CUPS Backend: Ignoring pickmany setting %s\n", ppd_option->text);
 
2121
#endif  
 
2122
  
 
2123
  if (option)
 
2124
    {
 
2125
      char *name;
 
2126
 
 
2127
      name = ppd_group_name (toplevel_group);
 
2128
      if (STRING_IN_TABLE (name,
 
2129
                           color_group_whitelist) ||
 
2130
          STRING_IN_TABLE (ppd_option->keyword,
 
2131
                           color_option_whitelist))
 
2132
        {
 
2133
          option->group = g_strdup ("ColorPage");
 
2134
        }
 
2135
      else if (STRING_IN_TABLE (name,
 
2136
                                image_quality_group_whitelist) ||
 
2137
               STRING_IN_TABLE (ppd_option->keyword,
 
2138
                                image_quality_option_whitelist))
 
2139
        {
 
2140
          option->group = g_strdup ("ImageQualityPage");
 
2141
        }
 
2142
      else if (STRING_IN_TABLE (name,
 
2143
                                finishing_group_whitelist) ||
 
2144
               STRING_IN_TABLE (ppd_option->keyword,
 
2145
                                finishing_option_whitelist))
 
2146
        {
 
2147
          option->group = g_strdup ("FinishingPage");
 
2148
        }
 
2149
      else
 
2150
        {
 
2151
          option->group = g_strdup (toplevel_group->text);
 
2152
        }
 
2153
 
 
2154
      set_option_from_settings (option, settings);
 
2155
      
 
2156
      gtk_printer_option_set_add (set, option);
 
2157
    }
 
2158
  
 
2159
  g_free (name);
 
2160
}
 
2161
 
 
2162
static void
 
2163
handle_group (GtkPrinterOptionSet *set,
 
2164
              ppd_file_t          *ppd_file,
 
2165
              ppd_group_t         *group,
 
2166
              ppd_group_t         *toplevel_group,
 
2167
              GtkPrintSettings    *settings)
 
2168
{
 
2169
  gint i;
 
2170
  gchar *name;
 
2171
  
 
2172
  /* Ignore installable options */
 
2173
  name = ppd_group_name (toplevel_group);
 
2174
  if (strcmp (name, "InstallableOptions") == 0)
 
2175
    return;
 
2176
  
 
2177
  for (i = 0; i < group->num_options; i++)
 
2178
    handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
 
2179
 
 
2180
  for (i = 0; i < group->num_subgroups; i++)
 
2181
    handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
 
2182
 
 
2183
}
 
2184
 
 
2185
static GtkPrinterOptionSet *
 
2186
cups_printer_get_options (GtkPrinter           *printer,
 
2187
                          GtkPrintSettings     *settings,
 
2188
                          GtkPageSetup         *page_setup,
 
2189
                          GtkPrintCapabilities  capabilities)
 
2190
{
 
2191
  GtkPrinterOptionSet *set;
 
2192
  GtkPrinterOption *option;
 
2193
  ppd_file_t *ppd_file;
 
2194
  int i;
 
2195
  char *print_at[] = { "now", "at", "on-hold" };
 
2196
  char *n_up[] = {"1", "2", "4", "6", "9", "16" };
 
2197
  char *prio[] = {"100", "80", "50", "30" };
 
2198
  char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
 
2199
  char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
 
2200
  char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
 
2201
 
 
2202
 
 
2203
  set = gtk_printer_option_set_new ();
 
2204
 
 
2205
  /* Cups specific, non-ppd related settings */
 
2206
 
 
2207
  option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
 
2208
  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
 
2209
                                         n_up, n_up);
 
2210
  gtk_printer_option_set (option, "1");
 
2211
  set_option_from_settings (option, settings);
 
2212
  gtk_printer_option_set_add (set, option);
 
2213
  g_object_unref (option);
 
2214
 
 
2215
  for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
 
2216
    prio_display[i] = _(prio_display[i]);
 
2217
  
 
2218
  option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
 
2219
  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
 
2220
                                         prio, prio_display);
 
2221
  gtk_printer_option_set (option, "50");
 
2222
  set_option_from_settings (option, settings);
 
2223
  gtk_printer_option_set_add (set, option);
 
2224
  g_object_unref (option);
 
2225
 
 
2226
  option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
 
2227
  gtk_printer_option_set (option, "");
 
2228
  set_option_from_settings (option, settings);
 
2229
  gtk_printer_option_set_add (set, option);
 
2230
  g_object_unref (option);
 
2231
 
 
2232
  for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
 
2233
    cover_display[i] = _(cover_display[i]);
 
2234
  
 
2235
  option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
 
2236
  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
 
2237
                                         cover, cover_display);
 
2238
  gtk_printer_option_set (option, "none");
 
2239
  set_option_from_settings (option, settings);
 
2240
  gtk_printer_option_set_add (set, option);
 
2241
  g_object_unref (option);
 
2242
 
 
2243
  option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
 
2244
  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
 
2245
                                         cover, cover_display);
 
2246
  gtk_printer_option_set (option, "none");
 
2247
  set_option_from_settings (option, settings);
 
2248
  gtk_printer_option_set_add (set, option);
 
2249
  g_object_unref (option);
 
2250
 
 
2251
  option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
 
2252
  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
 
2253
                                         print_at, print_at);
 
2254
  gtk_printer_option_set (option, "now");
 
2255
  set_option_from_settings (option, settings);
 
2256
  gtk_printer_option_set_add (set, option);
 
2257
  g_object_unref (option);
 
2258
  
 
2259
  option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
 
2260
  gtk_printer_option_set (option, "");
 
2261
  set_option_from_settings (option, settings);
 
2262
  gtk_printer_option_set_add (set, option);
 
2263
  g_object_unref (option);
 
2264
  
 
2265
  /* Printer (ppd) specific settings */
 
2266
  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
 
2267
  if (ppd_file)
 
2268
    {
 
2269
      GtkPaperSize *paper_size;
 
2270
      ppd_option_t *option;
 
2271
      const gchar  *ppd_name;
 
2272
 
 
2273
      ppdMarkDefaults (ppd_file);
 
2274
 
 
2275
      paper_size = gtk_page_setup_get_paper_size (page_setup);
 
2276
 
 
2277
      option = ppdFindOption (ppd_file, "PageSize");
 
2278
      ppd_name = gtk_paper_size_get_ppd_name (paper_size);
 
2279
      
 
2280
      if (ppd_name)
 
2281
        strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
 
2282
      else
 
2283
        {
 
2284
          gchar *custom_name;
 
2285
 
 
2286
          custom_name = g_strdup_printf ("Custom.%2fx%.2f",
 
2287
                                         gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
 
2288
                                         gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
 
2289
          strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
 
2290
          g_free (custom_name);
 
2291
        }
 
2292
 
 
2293
      for (i = 0; i < ppd_file->num_groups; i++)
 
2294
        handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
 
2295
    }
 
2296
 
 
2297
  return set;
 
2298
}
 
2299
 
 
2300
 
 
2301
static void
 
2302
mark_option_from_set (GtkPrinterOptionSet *set,
 
2303
                      ppd_file_t          *ppd_file,
 
2304
                      ppd_option_t        *ppd_option)
 
2305
{
 
2306
  GtkPrinterOption *option;
 
2307
  char *name = get_option_name (ppd_option->keyword);
 
2308
 
 
2309
  option = gtk_printer_option_set_lookup (set, name);
 
2310
 
 
2311
  if (option)
 
2312
    ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
 
2313
  
 
2314
  g_free (name);
 
2315
}
 
2316
 
 
2317
 
 
2318
static void
 
2319
mark_group_from_set (GtkPrinterOptionSet *set,
 
2320
                     ppd_file_t          *ppd_file,
 
2321
                     ppd_group_t         *group)
 
2322
{
 
2323
  int i;
 
2324
 
 
2325
  for (i = 0; i < group->num_options; i++)
 
2326
    mark_option_from_set (set, ppd_file, &group->options[i]);
 
2327
 
 
2328
  for (i = 0; i < group->num_subgroups; i++)
 
2329
    mark_group_from_set (set, ppd_file, &group->subgroups[i]);
 
2330
}
 
2331
 
 
2332
static void
 
2333
set_conflicts_from_option (GtkPrinterOptionSet *set,
 
2334
                           ppd_file_t          *ppd_file,
 
2335
                           ppd_option_t        *ppd_option)
 
2336
{
 
2337
  GtkPrinterOption *option;
 
2338
  char *name;
 
2339
 
 
2340
  if (ppd_option->conflicted)
 
2341
    {
 
2342
      name = get_option_name (ppd_option->keyword);
 
2343
      option = gtk_printer_option_set_lookup (set, name);
 
2344
 
 
2345
      if (option)
 
2346
        gtk_printer_option_set_has_conflict (option, TRUE);
 
2347
#ifdef PRINT_IGNORED_OPTIONS
 
2348
      else
 
2349
        g_warning ("CUPS Backend: Ignoring conflict for option %s", ppd_option->keyword);
 
2350
#endif
 
2351
      
 
2352
      g_free (name);
 
2353
    }
 
2354
}
 
2355
 
 
2356
static void
 
2357
set_conflicts_from_group (GtkPrinterOptionSet *set,
 
2358
                          ppd_file_t          *ppd_file,
 
2359
                          ppd_group_t         *group)
 
2360
{
 
2361
  int i;
 
2362
 
 
2363
  for (i = 0; i < group->num_options; i++)
 
2364
    set_conflicts_from_option (set, ppd_file, &group->options[i]);
 
2365
 
 
2366
  for (i = 0; i < group->num_subgroups; i++)
 
2367
    set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
 
2368
}
 
2369
 
 
2370
static gboolean
 
2371
cups_printer_mark_conflicts (GtkPrinter          *printer,
 
2372
                             GtkPrinterOptionSet *options)
 
2373
{
 
2374
  ppd_file_t *ppd_file;
 
2375
  int num_conflicts;
 
2376
  int i;
 
2377
 
 
2378
  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
 
2379
 
 
2380
  if (ppd_file == NULL)
 
2381
    return FALSE;
 
2382
 
 
2383
  ppdMarkDefaults (ppd_file);
 
2384
 
 
2385
  for (i = 0; i < ppd_file->num_groups; i++)
 
2386
    mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
 
2387
 
 
2388
  num_conflicts = ppdConflicts (ppd_file);
 
2389
 
 
2390
  if (num_conflicts > 0)
 
2391
    {
 
2392
      for (i = 0; i < ppd_file->num_groups; i++)
 
2393
        set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
 
2394
    }
 
2395
 
 
2396
  return num_conflicts > 0;
 
2397
}
 
2398
 
 
2399
struct OptionData {
 
2400
  GtkPrinter *printer;
 
2401
  GtkPrinterOptionSet *options;
 
2402
  GtkPrintSettings *settings;
 
2403
  ppd_file_t *ppd_file;
 
2404
};
 
2405
 
 
2406
typedef struct {
 
2407
  const char *cups;
 
2408
  const char *standard;
 
2409
} NameMapping;
 
2410
 
 
2411
static void
 
2412
map_settings_to_option (GtkPrinterOption  *option,
 
2413
                        const NameMapping  table[],
 
2414
                        gint               n_elements,
 
2415
                        GtkPrintSettings  *settings,
 
2416
                        const gchar       *standard_name,
 
2417
                        const gchar       *cups_name)
 
2418
{
 
2419
  int i;
 
2420
  char *name;
 
2421
  const char *cups_value;
 
2422
  const char *standard_value;
 
2423
 
 
2424
  /* If the cups-specific setting is set, always use that */
 
2425
  name = g_strdup_printf ("cups-%s", cups_name);
 
2426
  cups_value = gtk_print_settings_get (settings, name);
 
2427
  g_free (name);
 
2428
  
 
2429
  if (cups_value != NULL) 
 
2430
    {
 
2431
      gtk_printer_option_set (option, cups_value);
 
2432
      return;
 
2433
    }
 
2434
 
 
2435
  /* Otherwise we try to convert from the general setting */
 
2436
  standard_value = gtk_print_settings_get (settings, standard_name);
 
2437
  if (standard_value == NULL)
 
2438
    return;
 
2439
 
 
2440
  for (i = 0; i < n_elements; i++)
 
2441
    {
 
2442
      if (table[i].cups == NULL && table[i].standard == NULL)
 
2443
        {
 
2444
          gtk_printer_option_set (option, standard_value);
 
2445
          break;
 
2446
        }
 
2447
      else if (table[i].cups == NULL &&
 
2448
               strcmp (table[i].standard, standard_value) == 0)
 
2449
        {
 
2450
          set_option_off (option);
 
2451
          break;
 
2452
        }
 
2453
      else if (strcmp (table[i].standard, standard_value) == 0)
 
2454
        {
 
2455
          gtk_printer_option_set (option, table[i].cups);
 
2456
          break;
 
2457
        }
 
2458
    }
 
2459
}
 
2460
 
 
2461
static void
 
2462
map_option_to_settings (const gchar       *value,
 
2463
                        const NameMapping  table[],
 
2464
                        gint               n_elements,
 
2465
                        GtkPrintSettings  *settings,
 
2466
                        const gchar       *standard_name,
 
2467
                        const gchar       *cups_name)
 
2468
{
 
2469
  int i;
 
2470
  char *name;
 
2471
 
 
2472
  for (i = 0; i < n_elements; i++)
 
2473
    {
 
2474
      if (table[i].cups == NULL && table[i].standard == NULL)
 
2475
        {
 
2476
          gtk_print_settings_set (settings,
 
2477
                                  standard_name,
 
2478
                                  value);
 
2479
          break;
 
2480
        }
 
2481
      else if (table[i].cups == NULL && table[i].standard != NULL)
 
2482
        {
 
2483
          if (value_is_off (value))
 
2484
            {
 
2485
              gtk_print_settings_set (settings,
 
2486
                                      standard_name,
 
2487
                                      table[i].standard);
 
2488
              break;
 
2489
            }
 
2490
        }
 
2491
      else if (strcmp (table[i].cups, value) == 0)
 
2492
        {
 
2493
          gtk_print_settings_set (settings,
 
2494
                                  standard_name,
 
2495
                                  table[i].standard);
 
2496
          break;
 
2497
        }
 
2498
    }
 
2499
 
 
2500
  /* Always set the corresponding cups-specific setting */
 
2501
  name = g_strdup_printf ("cups-%s", cups_name);
 
2502
  gtk_print_settings_set (settings, name, value);
 
2503
  g_free (name);
 
2504
}
 
2505
 
 
2506
 
 
2507
static const NameMapping paper_source_map[] = {
 
2508
  { "Lower", "lower"},
 
2509
  { "Middle", "middle"},
 
2510
  { "Upper", "upper"},
 
2511
  { "Rear", "rear"},
 
2512
  { "Envelope", "envelope"},
 
2513
  { "Cassette", "cassette"},
 
2514
  { "LargeCapacity", "large-capacity"},
 
2515
  { "AnySmallFormat", "small-format"},
 
2516
  { "AnyLargeFormat", "large-format"},
 
2517
  { NULL, NULL}
 
2518
};
 
2519
 
 
2520
static const NameMapping output_tray_map[] = {
 
2521
  { "Upper", "upper"},
 
2522
  { "Lower", "lower"},
 
2523
  { "Rear", "rear"},
 
2524
  { NULL, NULL}
 
2525
};
 
2526
 
 
2527
static const NameMapping duplex_map[] = {
 
2528
  { "DuplexTumble", "vertical" },
 
2529
  { "DuplexNoTumble", "horizontal" },
 
2530
  { NULL, "simplex" }
 
2531
};
 
2532
 
 
2533
static const NameMapping output_mode_map[] = {
 
2534
  { "Standard", "normal" },
 
2535
  { "Normal", "normal" },
 
2536
  { "Draft", "draft" },
 
2537
  { "Fast", "draft" },
 
2538
};
 
2539
 
 
2540
static const NameMapping media_type_map[] = {
 
2541
  { "Transparency", "transparency"},
 
2542
  { "Standard", "stationery"},
 
2543
  { NULL, NULL}
 
2544
};
 
2545
 
 
2546
static const NameMapping all_map[] = {
 
2547
  { NULL, NULL}
 
2548
};
 
2549
 
 
2550
 
 
2551
static void
 
2552
set_option_from_settings (GtkPrinterOption *option,
 
2553
                          GtkPrintSettings *settings)
 
2554
{
 
2555
  const char *cups_value;
 
2556
  char *value;
 
2557
  
 
2558
  if (settings == NULL)
 
2559
    return;
 
2560
 
 
2561
  if (strcmp (option->name, "gtk-paper-source") == 0)
 
2562
    map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
 
2563
                             settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
 
2564
  else if (strcmp (option->name, "gtk-output-tray") == 0)
 
2565
    map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
 
2566
                            settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
 
2567
  else if (strcmp (option->name, "gtk-duplex") == 0)
 
2568
    map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
 
2569
                            settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
 
2570
  else if (strcmp (option->name, "cups-OutputMode") == 0)
 
2571
    map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
 
2572
                            settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
 
2573
  else if (strcmp (option->name, "cups-Resolution") == 0)
 
2574
    {
 
2575
      cups_value = gtk_print_settings_get (settings, option->name);
 
2576
      if (cups_value)
 
2577
        gtk_printer_option_set (option, cups_value);
 
2578
      else
 
2579
        {
 
2580
          int res = gtk_print_settings_get_resolution (settings);
 
2581
          if (res != 0)
 
2582
            {
 
2583
              value = g_strdup_printf ("%ddpi", res);
 
2584
              gtk_printer_option_set (option, value);
 
2585
              g_free (value);
 
2586
            }
 
2587
        }
 
2588
    }
 
2589
  else if (strcmp (option->name, "gtk-paper-type") == 0)
 
2590
    map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
 
2591
                            settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
 
2592
  else if (strcmp (option->name, "gtk-n-up") == 0)
 
2593
    {
 
2594
      map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
 
2595
                              settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
 
2596
    }
 
2597
  else if (strcmp (option->name, "gtk-billing-info") == 0)
 
2598
    {
 
2599
      cups_value = gtk_print_settings_get (settings, "cups-job-billing");
 
2600
      if (cups_value)
 
2601
        gtk_printer_option_set (option, cups_value);
 
2602
    } 
 
2603
  else if (strcmp (option->name, "gtk-job-prio") == 0)
 
2604
    {
 
2605
      cups_value = gtk_print_settings_get (settings, "cups-job-priority");
 
2606
      if (cups_value)
 
2607
        gtk_printer_option_set (option, cups_value);
 
2608
    } 
 
2609
  else if (strcmp (option->name, "gtk-cover-before") == 0)
 
2610
    {
 
2611
      cups_value = gtk_print_settings_get (settings, "cover-before");
 
2612
      if (cups_value)
 
2613
        gtk_printer_option_set (option, cups_value);
 
2614
    } 
 
2615
  else if (strcmp (option->name, "gtk-cover-after") == 0)
 
2616
    {
 
2617
      cups_value = gtk_print_settings_get (settings, "cover-after");
 
2618
      if (cups_value)
 
2619
        gtk_printer_option_set (option, cups_value);
 
2620
    } 
 
2621
  else if (strcmp (option->name, "gtk-print-time") == 0)
 
2622
    {
 
2623
      cups_value = gtk_print_settings_get (settings, "print-at");
 
2624
      if (cups_value)
 
2625
        gtk_printer_option_set (option, cups_value);
 
2626
    } 
 
2627
  else if (strcmp (option->name, "gtk-print-time-text") == 0)
 
2628
    {
 
2629
      cups_value = gtk_print_settings_get (settings, "print-at-time");
 
2630
      if (cups_value)
 
2631
        gtk_printer_option_set (option, cups_value);
 
2632
    } 
 
2633
  else if (g_str_has_prefix (option->name, "cups-"))
 
2634
    {
 
2635
      cups_value = gtk_print_settings_get (settings, option->name);
 
2636
      if (cups_value)
 
2637
        gtk_printer_option_set (option, cups_value);
 
2638
    } 
 
2639
}
 
2640
 
 
2641
static void
 
2642
foreach_option_get_settings (GtkPrinterOption *option,
 
2643
                             gpointer          user_data)
 
2644
{
 
2645
  struct OptionData *data = user_data;
 
2646
  GtkPrintSettings *settings = data->settings;
 
2647
  const char *value;
 
2648
 
 
2649
  value = option->value;
 
2650
 
 
2651
  if (strcmp (option->name, "gtk-paper-source") == 0)
 
2652
    map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
 
2653
                            settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
 
2654
  else if (strcmp (option->name, "gtk-output-tray") == 0)
 
2655
    map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
 
2656
                            settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
 
2657
  else if (strcmp (option->name, "gtk-duplex") == 0)
 
2658
    map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
 
2659
                            settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
 
2660
  else if (strcmp (option->name, "cups-OutputMode") == 0)
 
2661
    map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
 
2662
                            settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
 
2663
  else if (strcmp (option->name, "cups-Resolution") == 0)
 
2664
    {
 
2665
      int res = atoi (value);
 
2666
      /* TODO: What if resolution is on XXXxYYYdpi form? */
 
2667
      if (res != 0)
 
2668
        gtk_print_settings_set_resolution (settings, res);
 
2669
      gtk_print_settings_set (settings, option->name, value);
 
2670
    }
 
2671
  else if (strcmp (option->name, "gtk-paper-type") == 0)
 
2672
    map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
 
2673
                            settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
 
2674
  else if (strcmp (option->name, "gtk-n-up") == 0)
 
2675
    map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
 
2676
                            settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
 
2677
  else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
 
2678
    gtk_print_settings_set (settings, "cups-job-billing", value);
 
2679
  else if (strcmp (option->name, "gtk-job-prio") == 0)
 
2680
    gtk_print_settings_set (settings, "cups-job-priority", value);
 
2681
  else if (strcmp (option->name, "gtk-cover-before") == 0)
 
2682
    gtk_print_settings_set (settings, "cover-before", value);
 
2683
  else if (strcmp (option->name, "gtk-cover-after") == 0)
 
2684
    gtk_print_settings_set (settings, "cover-after", value);
 
2685
  else if (strcmp (option->name, "gtk-print-time") == 0)
 
2686
    gtk_print_settings_set (settings, "print-at", value);
 
2687
  else if (strcmp (option->name, "gtk-print-time-text") == 0)
 
2688
    gtk_print_settings_set (settings, "print-at-time", value);
 
2689
  else if (g_str_has_prefix (option->name, "cups-"))
 
2690
    gtk_print_settings_set (settings, option->name, value);
 
2691
}
 
2692
 
 
2693
static void
 
2694
cups_printer_get_settings_from_options (GtkPrinter          *printer,
 
2695
                                        GtkPrinterOptionSet *options,
 
2696
                                        GtkPrintSettings    *settings)
 
2697
{
 
2698
  struct OptionData data;
 
2699
  const char *print_at, *print_at_time;
 
2700
 
 
2701
  data.printer = printer;
 
2702
  data.options = options;
 
2703
  data.settings = settings;
 
2704
  data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
 
2705
 
 
2706
  if (data.ppd_file != NULL)
 
2707
    {
 
2708
      GtkPrinterOption *cover_before, *cover_after;
 
2709
      
 
2710
      gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
 
2711
 
 
2712
      cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
 
2713
      cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
 
2714
      if (cover_before && cover_after)
 
2715
        {
 
2716
          char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
 
2717
          gtk_print_settings_set (settings, "cups-job-sheets", value);
 
2718
          g_free (value);
 
2719
        }
 
2720
 
 
2721
      print_at = gtk_print_settings_get (settings, "print-at");
 
2722
      print_at_time = gtk_print_settings_get (settings, "print-at-time");
 
2723
      if (strcmp (print_at, "at") == 0)
 
2724
        gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
 
2725
      else if (strcmp (print_at, "on-hold") == 0)
 
2726
        gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
 
2727
    }
 
2728
}
 
2729
 
 
2730
static void
 
2731
cups_printer_prepare_for_print (GtkPrinter       *printer,
 
2732
                                GtkPrintJob      *print_job,
 
2733
                                GtkPrintSettings *settings,
 
2734
                                GtkPageSetup     *page_setup)
 
2735
{
 
2736
  GtkPageSet page_set;
 
2737
  GtkPaperSize *paper_size;
 
2738
  const char *ppd_paper_name;
 
2739
  double scale;
 
2740
 
 
2741
  print_job->print_pages = gtk_print_settings_get_print_pages (settings);
 
2742
  print_job->page_ranges = NULL;
 
2743
  print_job->num_page_ranges = 0;
 
2744
  
 
2745
  if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
 
2746
    print_job->page_ranges =
 
2747
      gtk_print_settings_get_page_ranges (settings,
 
2748
                                          &print_job->num_page_ranges);
 
2749
  
 
2750
  if (gtk_print_settings_get_collate (settings))
 
2751
    gtk_print_settings_set (settings, "cups-Collate", "True");
 
2752
  print_job->collate = FALSE;
 
2753
 
 
2754
  if (gtk_print_settings_get_reverse (settings))
 
2755
    gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
 
2756
  print_job->reverse = FALSE;
 
2757
 
 
2758
  if (gtk_print_settings_get_n_copies (settings) > 1)
 
2759
    gtk_print_settings_set_int (settings, "cups-copies",
 
2760
                                gtk_print_settings_get_n_copies (settings));
 
2761
  print_job->num_copies = 1;
 
2762
 
 
2763
  scale = gtk_print_settings_get_scale (settings);
 
2764
  print_job->scale = 1.0;
 
2765
  if (scale != 100.0)
 
2766
    print_job->scale = scale/100.0;
 
2767
 
 
2768
  page_set = gtk_print_settings_get_page_set (settings);
 
2769
  if (page_set == GTK_PAGE_SET_EVEN)
 
2770
    gtk_print_settings_set (settings, "cups-page-set", "even");
 
2771
  else if (page_set == GTK_PAGE_SET_ODD)
 
2772
    gtk_print_settings_set (settings, "cups-page-set", "odd");
 
2773
  print_job->page_set = GTK_PAGE_SET_ALL;
 
2774
 
 
2775
  paper_size = gtk_page_setup_get_paper_size (page_setup);
 
2776
  ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
 
2777
  if (ppd_paper_name != NULL)
 
2778
    gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
 
2779
  else
 
2780
    {
 
2781
      char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
 
2782
                                           gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
 
2783
                                           gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
 
2784
      gtk_print_settings_set (settings, "cups-PageSize", custom_name);
 
2785
      g_free (custom_name);
 
2786
    }
 
2787
 
 
2788
  print_job->rotate_to_orientation = TRUE;
 
2789
}
 
2790
 
 
2791
static GList *
 
2792
cups_printer_list_papers (GtkPrinter *printer)
 
2793
{
 
2794
  ppd_file_t *ppd_file;
 
2795
  ppd_size_t *size;
 
2796
  char *display_name;
 
2797
  GtkPageSetup *page_setup;
 
2798
  GtkPaperSize *paper_size;
 
2799
  ppd_option_t *option;
 
2800
  ppd_choice_t *choice;
 
2801
  GList *l;
 
2802
  int i;
 
2803
 
 
2804
  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
 
2805
  if (ppd_file == NULL)
 
2806
    return NULL;
 
2807
 
 
2808
  l = NULL;
 
2809
  
 
2810
  for (i = 0; i < ppd_file->num_sizes; i++)
 
2811
    {
 
2812
      size = &ppd_file->sizes[i];
 
2813
 
 
2814
      display_name = NULL;
 
2815
      option = ppdFindOption (ppd_file, "PageSize");
 
2816
      if (option)
 
2817
        {
 
2818
          choice = ppdFindChoice (option, size->name);
 
2819
          if (choice)
 
2820
            display_name = ppd_text_to_utf8 (ppd_file, choice->text);
 
2821
        }
 
2822
      if (display_name == NULL)
 
2823
        display_name = g_strdup (size->name);
 
2824
 
 
2825
      page_setup = gtk_page_setup_new ();
 
2826
      paper_size = gtk_paper_size_new_from_ppd (size->name,
 
2827
                                                display_name,
 
2828
                                                size->width,
 
2829
                                                size->length);
 
2830
      gtk_page_setup_set_paper_size (page_setup, paper_size);
 
2831
      gtk_paper_size_free (paper_size);
 
2832
 
 
2833
      gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
 
2834
      gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
 
2835
      gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
 
2836
      gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
 
2837
        
 
2838
      g_free (display_name);
 
2839
 
 
2840
      l = g_list_prepend (l, page_setup);
 
2841
    }
 
2842
 
 
2843
  return g_list_reverse (l);
 
2844
}
 
2845
 
 
2846
static void
 
2847
cups_printer_get_hard_margins (GtkPrinter *printer,
 
2848
                               gdouble    *top,
 
2849
                               gdouble    *bottom,
 
2850
                               gdouble    *left,
 
2851
                               gdouble    *right)
 
2852
{
 
2853
  ppd_file_t *ppd_file;
 
2854
 
 
2855
  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
 
2856
  if (ppd_file == NULL)
 
2857
    return;
 
2858
 
 
2859
  *left = ppd_file->custom_margins[0];
 
2860
  *bottom = ppd_file->custom_margins[1];
 
2861
  *right = ppd_file->custom_margins[2];
 
2862
  *top = ppd_file->custom_margins[3];
 
2863
}
 
2864
 
 
2865
static GtkPrintCapabilities
 
2866
cups_printer_get_capabilities (GtkPrinter *printer)
 
2867
{
 
2868
  return
 
2869
    GTK_PRINT_CAPABILITY_COPIES |
 
2870
    GTK_PRINT_CAPABILITY_COLLATE |
 
2871
    GTK_PRINT_CAPABILITY_REVERSE;
 
2872
}