gtkprintoperation-unix.c 33.3 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3
 * gtkprintoperation-unix.c: Print Operation Details for Unix 
 *                           and Unix-like platforms
4 5 6 7 8 9 10 11 12 13 14 15 16
 * Copyright (C) 2006, Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25 26
 */

#include "config.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
27 28 29
#include <errno.h>
#include <stdlib.h>       
#include <fcntl.h>
30

31
#include <glib/gstdio.h>
32 33 34
#include "gtkprintoperation-private.h"
#include "gtkmessagedialog.h"

35 36
#include <cairo-pdf.h>
#include <cairo-ps.h>
37
#include "gtkprivate.h"
38 39 40 41 42
#include "gtkprintunixdialog.h"
#include "gtkpagesetupunixdialog.h"
#include "gtkprintbackend.h"
#include "gtkprinter.h"
#include "gtkprintjob.h"
43
#include "gtklabel.h"
44
#include "gtkintl.h"
45

46

Matthias Clasen's avatar
Matthias Clasen committed
47 48
typedef struct 
{
Matthias Clasen's avatar
Matthias Clasen committed
49
  GtkWindow *parent;        /* just in case we need to throw error dialogs */
Alexander Larsson's avatar
Alexander Larsson committed
50 51
  GMainLoop *loop;
  gboolean data_sent;
52

53
  /* Real printing (not preview) */
54 55 56 57 58
  GtkPrintJob *job;         /* the job we are sending to the printer */
  cairo_surface_t *surface;
  gulong job_status_changed_tag;

  
59 60
} GtkPrintOperationUnix;

Alexander Larsson's avatar
Alexander Larsson committed
61 62 63
typedef struct _PrinterFinder PrinterFinder;

static void printer_finder_free (PrinterFinder *finder);
Matthias Clasen's avatar
Matthias Clasen committed
64
static void find_printer        (const gchar   *printer,
Alexander Larsson's avatar
Alexander Larsson committed
65 66 67
				 GFunc          func,
				 gpointer       data);

68 69
static void
unix_start_page (GtkPrintOperation *op,
Matthias Clasen's avatar
Matthias Clasen committed
70 71
		 GtkPrintContext   *print_context,
		 GtkPageSetup      *page_setup)
72
{
73
  GtkPrintOperationUnix *op_unix;  
74 75
  GtkPaperSize *paper_size;
  cairo_surface_type_t type;
Matthias Clasen's avatar
Matthias Clasen committed
76
  gdouble w, h;
77

78 79
  op_unix = op->priv->platform_data;
  
80 81 82 83 84
  paper_size = gtk_page_setup_get_paper_size (page_setup);

  w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
  h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
  
85
  type = cairo_surface_get_type (op_unix->surface);
86

87 88 89 90
  if ((op->priv->manual_number_up < 2) ||
      (op->priv->page_position % op->priv->manual_number_up == 0))
    {
      if (type == CAIRO_SURFACE_TYPE_PS)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
        {
          cairo_ps_surface_set_size (op_unix->surface, w, h);
          cairo_ps_surface_dsc_begin_page_setup (op_unix->surface);
          switch (gtk_page_setup_get_orientation (page_setup))
            {
              case GTK_PAGE_ORIENTATION_PORTRAIT:
              case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
                cairo_ps_surface_dsc_comment (op_unix->surface, "%%PageOrientation: Portrait");
                break;

              case GTK_PAGE_ORIENTATION_LANDSCAPE:
              case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
                cairo_ps_surface_dsc_comment (op_unix->surface, "%%PageOrientation: Landscape");
                break;
            }
         }
107
      else if (type == CAIRO_SURFACE_TYPE_PDF)
108
        {
109 110 111 112 113
          if (!op->priv->manual_orientation)
            {
              w = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
              h = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
            }
114 115
          cairo_pdf_surface_set_size (op_unix->surface, w, h);
        }
116
    }
117 118 119 120
}

static void
unix_end_page (GtkPrintOperation *op,
Matthias Clasen's avatar
Matthias Clasen committed
121
	       GtkPrintContext   *print_context)
122 123 124
{
  cairo_t *cr;

125
  cr = gtk_print_context_get_cairo_context (print_context);
126 127 128 129 130

  if ((op->priv->manual_number_up < 2) ||
      ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
      (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
    cairo_show_page (cr);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
}

static void
op_unix_free (GtkPrintOperationUnix *op_unix)
{
  if (op_unix->job)
    {
      g_signal_handler_disconnect (op_unix->job,
				   op_unix->job_status_changed_tag);
      g_object_unref (op_unix->job);
    }

  g_free (op_unix);
}

Matthias Clasen's avatar
Matthias Clasen committed
146
static gchar *
147
shell_command_substitute_file (const gchar *cmd,
148 149 150 151
			       const gchar *pdf_filename,
			       const gchar *settings_filename,
                               gboolean    *pdf_filename_replaced,
                               gboolean    *settings_filename_replaced)
152
{
Matthias Clasen's avatar
Matthias Clasen committed
153
  const gchar *inptr, *start;
154 155 156
  GString *final;

  g_return_val_if_fail (cmd != NULL, NULL);
157 158
  g_return_val_if_fail (pdf_filename != NULL, NULL);
  g_return_val_if_fail (settings_filename != NULL, NULL);
159 160 161

  final = g_string_new (NULL);

162 163
  *pdf_filename_replaced = FALSE;
  *settings_filename_replaced = FALSE;
164

165
  start = inptr = cmd;
166 167 168 169 170 171 172
  while ((inptr = strchr (inptr, '%')) != NULL) 
    {
      g_string_append_len (final, start, inptr - start);
      inptr++;
      switch (*inptr) 
        {
          case 'f':
173 174 175 176 177 178 179
            g_string_append (final, pdf_filename);
            *pdf_filename_replaced = TRUE;
            break;

          case 's':
            g_string_append (final, settings_filename);
            *settings_filename_replaced = TRUE;
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
            break;

          case '%':
            g_string_append_c (final, '%');
            break;

          default:
            g_string_append_c (final, '%');
            if (*inptr)
              g_string_append_c (final, *inptr);
            break;
        }
      if (*inptr)
        inptr++;
      start = inptr;
    }
  g_string_append (final, start);

198
  return g_string_free (final, FALSE);
199 200 201 202
}

void
_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
203
						      cairo_surface_t   *surface,
Matthias Clasen's avatar
Matthias Clasen committed
204 205
						      GtkWindow         *parent,
						      const gchar       *filename)
206
{
Matthias Clasen's avatar
Matthias Clasen committed
207
  GAppInfo *appinfo;
208
  GdkAppLaunchContext *context;
209 210 211
  gchar *cmd;
  gchar *preview_cmd;
  GtkSettings *settings;
212
  GtkPrintSettings *print_settings = NULL;
213 214 215 216
  GtkPageSetup *page_setup;
  GKeyFile *key_file = NULL;
  gchar *data = NULL;
  gsize data_len;
217
  gchar *settings_filename = NULL;
218
  gchar *quoted_filename;
219
  gchar *quoted_settings_filename;
220 221
  gboolean filename_used = FALSE;
  gboolean settings_used = FALSE;
222 223
  GdkScreen *screen;
  GError *error = NULL;
224
  gint fd;
225
  gboolean retval;
226

227
  cairo_surface_destroy (surface);
228
 
229 230 231 232 233
  if (parent)
    screen = gtk_window_get_screen (parent);
  else
    screen = gdk_screen_get_default ();

234 235 236
  fd = g_file_open_tmp ("settingsXXXXXX.ini", &settings_filename, &error);
  if (fd < 0) 
    goto out;
237

238 239
  key_file = g_key_file_new ();
  
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  print_settings = gtk_print_settings_copy (gtk_print_operation_get_print_settings (op));

  if (print_settings != NULL)
    {
      gtk_print_settings_set_reverse (print_settings, FALSE);
      gtk_print_settings_set_page_set (print_settings, GTK_PAGE_SET_ALL);
      gtk_print_settings_set_scale (print_settings, 1.0);
      gtk_print_settings_set_number_up (print_settings, 1);
      gtk_print_settings_set_number_up_layout (print_settings, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);

      /*  These removals are neccessary because cups-* settings have higher priority
       *  than normal settings.
       */
      gtk_print_settings_unset (print_settings, "cups-reverse");
      gtk_print_settings_unset (print_settings, "cups-page-set");
      gtk_print_settings_unset (print_settings, "cups-scale");
      gtk_print_settings_unset (print_settings, "cups-number-up");
      gtk_print_settings_unset (print_settings, "cups-number-up-layout");

      gtk_print_settings_to_key_file (print_settings, key_file, NULL);
      g_object_unref (print_settings);
    }
262 263 264

  page_setup = gtk_print_context_get_page_setup (op->priv->print_context);
  gtk_page_setup_to_key_file (page_setup, key_file, NULL);
265

266 267
  g_key_file_set_string (key_file, "Print Job", "title", op->priv->job_name);

268 269 270 271 272
  data = g_key_file_to_data (key_file, &data_len, &error);
  if (!data)
    goto out;

  retval = g_file_set_contents (settings_filename, data, data_len, &error);
273
  if (!retval)
274 275 276
    goto out;

  settings = gtk_settings_get_for_screen (screen);
277 278 279
  g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);

  quoted_filename = g_shell_quote (filename);
280 281
  quoted_settings_filename = g_shell_quote (settings_filename);
  cmd = shell_command_substitute_file (preview_cmd, quoted_filename, quoted_settings_filename, &filename_used, &settings_used);
Matthias Clasen's avatar
Matthias Clasen committed
282 283 284 285 286

  appinfo = g_app_info_create_from_commandline (cmd,
                                                "Print Preview",
                                                G_APP_INFO_CREATE_NONE,
                                                &error);
287

288 289 290 291 292
  g_free (preview_cmd);
  g_free (quoted_filename);
  g_free (quoted_settings_filename);
  g_free (cmd);

Matthias Clasen's avatar
Matthias Clasen committed
293
  if (error != NULL)
294 295
    goto out;

Matthias Clasen's avatar
Matthias Clasen committed
296
  context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
297 298
  gdk_app_launch_context_set_screen (context, screen);
  g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
299

Matthias Clasen's avatar
Matthias Clasen committed
300 301
  g_object_unref (context);
  g_object_unref (appinfo);
302

303 304 305 306 307 308 309 310 311 312 313 314 315
  if (error != NULL)
    {
      gchar* uri;

      g_warning ("%s %s", _("Error launching preview"), error->message);

      g_error_free (error);
      error = NULL;
      uri = g_filename_to_uri (filename, NULL, NULL);
      gtk_show_uri (screen, uri, GDK_CURRENT_TIME, &error);
      g_free (uri);
    }

316 317 318
 out:
  if (error != NULL)
    {
319 320 321 322
      if (op->priv->error == NULL)
        op->priv->error = error;
      else
        g_error_free (error);
323

Matthias Clasen's avatar
Matthias Clasen committed
324
      filename_used = FALSE;
325
      settings_used = FALSE;
Matthias Clasen's avatar
Matthias Clasen committed
326
   }
327

328 329 330 331 332 333
  if (!filename_used)
    g_unlink (filename);

  if (!settings_used)
    g_unlink (settings_filename);

334 335
  if (fd > 0)
    close (fd);
Matthias Clasen's avatar
Matthias Clasen committed
336

337 338 339
  if (key_file)
    g_key_file_free (key_file);
  g_free (data);
340
  g_free (settings_filename);
341 342
}

343
static void
344 345 346
unix_finish_send  (GtkPrintJob  *job,
                   gpointer      user_data, 
                   const GError *error)
347
{
348 349
  GtkPrintOperation *op = (GtkPrintOperation *) user_data;
  GtkPrintOperationUnix *op_unix = op->priv->platform_data;
350

351 352
  if (error != NULL && op->priv->error == NULL)
    op->priv->error = g_error_copy (error);
Alexander Larsson's avatar
Alexander Larsson committed
353 354

  op_unix->data_sent = TRUE;
355

Alexander Larsson's avatar
Alexander Larsson committed
356 357
  if (op_unix->loop)
    g_main_loop_quit (op_unix->loop);
358 359

  g_object_unref (op);
360 361 362
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
363
unix_end_run (GtkPrintOperation *op,
364 365
	      gboolean           wait,
	      gboolean           cancelled)
366 367
{
  GtkPrintOperationUnix *op_unix = op->priv->platform_data;
Alexander Larsson's avatar
Alexander Larsson committed
368

369 370
  cairo_surface_finish (op_unix->surface);
  
371 372 373
  if (cancelled)
    return;

Alexander Larsson's avatar
Alexander Larsson committed
374 375 376
  if (wait)
    op_unix->loop = g_main_loop_new (NULL, FALSE);
  
377
  /* TODO: Check for error */
378
  if (op_unix->job != NULL)
379 380 381 382 383 384
    {
      g_object_ref (op);
      gtk_print_job_send (op_unix->job,
                          unix_finish_send, 
                          op, NULL);
    }
Alexander Larsson's avatar
Alexander Larsson committed
385 386 387

  if (wait)
    {
388
      g_object_ref (op);
Alexander Larsson's avatar
Alexander Larsson committed
389 390
      if (!op_unix->data_sent)
	{
391
	  gdk_threads_leave ();  
Alexander Larsson's avatar
Alexander Larsson committed
392
	  g_main_loop_run (op_unix->loop);
393
	  gdk_threads_enter ();  
Alexander Larsson's avatar
Alexander Larsson committed
394 395
	}
      g_main_loop_unref (op_unix->loop);
396 397
      op_unix->loop = NULL;
      g_object_unref (op);
Alexander Larsson's avatar
Alexander Larsson committed
398
    }
399 400 401
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
402 403
job_status_changed_cb (GtkPrintJob       *job, 
		       GtkPrintOperation *op)
404 405 406 407
{
  _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
}

408

409
static void
410 411 412
print_setup_changed_cb (GtkPrintUnixDialog *print_dialog, 
                        GParamSpec         *pspec,
                        gpointer            user_data)
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
{
  GtkPageSetup             *page_setup;
  GtkPrintSettings         *print_settings;
  GtkPrintOperation        *op = user_data;
  GtkPrintOperationPrivate *priv = op->priv;

  page_setup = gtk_print_unix_dialog_get_page_setup (print_dialog);
  print_settings = gtk_print_unix_dialog_get_settings (print_dialog);

  g_signal_emit_by_name (op,
                         "update-custom-widget",
                         priv->custom_widget,
                         page_setup,
                         print_settings);
}

429 430 431
static GtkWidget *
get_print_dialog (GtkPrintOperation *op,
                  GtkWindow         *parent)
432
{
433
  GtkPrintOperationPrivate *priv = op->priv;
434
  GtkWidget *pd, *label;
Matthias Clasen's avatar
Matthias Clasen committed
435
  const gchar *custom_tab_label;
436 437 438

  pd = gtk_print_unix_dialog_new (NULL, parent);

439 440 441 442 443
  gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (pd),
						 GTK_PRINT_CAPABILITY_PAGE_SET |
						 GTK_PRINT_CAPABILITY_COPIES |
						 GTK_PRINT_CAPABILITY_COLLATE |
						 GTK_PRINT_CAPABILITY_REVERSE |
444
						 GTK_PRINT_CAPABILITY_SCALE |
445 446 447
						 GTK_PRINT_CAPABILITY_PREVIEW |
						 GTK_PRINT_CAPABILITY_NUMBER_UP |
						 GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT);
448

449
  if (priv->print_settings)
450
    gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
451
					priv->print_settings);
452

453
  if (priv->default_page_setup)
454 455
    gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
                                          priv->default_page_setup);
456

457 458 459
  gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (pd),
                                              priv->embed_page_setup);

460 461 462
  gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (pd), 
                                          priv->current_page);

463 464 465 466 467 468
  gtk_print_unix_dialog_set_support_selection (GTK_PRINT_UNIX_DIALOG (pd),
                                               priv->support_selection);

  gtk_print_unix_dialog_set_has_selection (GTK_PRINT_UNIX_DIALOG (pd),
                                           priv->has_selection);

469
  g_signal_emit_by_name (op, "create-custom-widget",
Matthias Clasen's avatar
Matthias Clasen committed
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
			 &priv->custom_widget);

  if (priv->custom_widget) 
    {
      custom_tab_label = priv->custom_tab_label;
      
      if (custom_tab_label == NULL)
	{
	  custom_tab_label = g_get_application_name ();
	  if (custom_tab_label == NULL)
	    custom_tab_label = _("Application");
	}

      label = gtk_label_new (custom_tab_label);
      
      gtk_print_unix_dialog_add_custom_tab (GTK_PRINT_UNIX_DIALOG (pd),
Matthias Clasen's avatar
Matthias Clasen committed
486
					    priv->custom_widget, label);
487

488 489
      g_signal_connect (pd, "notify::selected-printer", (GCallback) print_setup_changed_cb, op);
      g_signal_connect (pd, "notify::page-setup", (GCallback) print_setup_changed_cb, op);
Matthias Clasen's avatar
Matthias Clasen committed
490
    }
491
  
492 493
  return pd;
}
494
  
Matthias Clasen's avatar
Matthias Clasen committed
495 496
typedef struct 
{
497 498
  GtkPrintOperation           *op;
  gboolean                     do_print;
499
  gboolean                     do_preview;
500 501 502
  GtkPrintOperationResult      result;
  GtkPrintOperationPrintFunc   print_cb;
  GDestroyNotify               destroy;
Alexander Larsson's avatar
Alexander Larsson committed
503 504
  GtkWindow                   *parent;
  GMainLoop                   *loop;
505 506 507 508 509 510 511 512 513 514 515 516
} PrintResponseData;

static void
print_response_data_free (gpointer data)
{
  PrintResponseData *rdata = data;

  g_object_unref (rdata->op);
  g_free (rdata);
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
517
finish_print (PrintResponseData *rdata,
Matthias Clasen's avatar
Matthias Clasen committed
518 519
	      GtkPrinter        *printer,
	      GtkPageSetup      *page_setup,
520 521
	      GtkPrintSettings  *settings,
	      gboolean           page_setup_set)
522 523
{
  GtkPrintOperation *op = rdata->op;
524
  GtkPrintOperationPrivate *priv = op->priv;
Matthias Clasen's avatar
Matthias Clasen committed
525
  GtkPrintJob *job;
526
  gdouble top, bottom, left, right;
Alexander Larsson's avatar
Alexander Larsson committed
527 528
  
  if (rdata->do_print)
529 530
    {
      gtk_print_operation_set_print_settings (op, settings);
531
      priv->print_context = _gtk_print_context_new (op);
532

533 534
      if (gtk_print_settings_get_number_up (settings) < 2)
        {
535
	  if (printer && gtk_printer_get_hard_margins (printer, &top, &bottom, &left, &right))
536 537 538 539 540 541 542 543 544 545
	    _gtk_print_context_set_hard_margins (priv->print_context, top, bottom, left, right);
	}
      else
        {
	  /* Pages do not have any unprintable area when printing n-up as each page on the
	   * sheet has been scaled down and translated to a position within the printable
	   * area of the sheet.
	   */
	  _gtk_print_context_set_hard_margins (priv->print_context, 0, 0, 0, 0);
	}
546

547 548 549
      if (page_setup != NULL &&
          (gtk_print_operation_get_default_page_setup (op) == NULL ||
           page_setup_set))
550 551
        gtk_print_operation_set_default_page_setup (op, page_setup);

552
      _gtk_print_context_set_page_setup (priv->print_context, page_setup);
553

554
      if (!rdata->do_preview)
555
        {
556 557 558
	  GtkPrintOperationUnix *op_unix;
	  cairo_t *cr;
	  
559
	  op_unix = g_new0 (GtkPrintOperationUnix, 1);
560 561 562 563 564 565 566 567
	  priv->platform_data = op_unix;
	  priv->free_platform_data = (GDestroyNotify) op_unix_free;
	  op_unix->parent = rdata->parent;
	  
	  priv->start_page = unix_start_page;
	  priv->end_page = unix_end_page;
	  priv->end_run = unix_end_run;
	  
Matthias Clasen's avatar
Matthias Clasen committed
568 569 570
	  job = gtk_print_job_new (priv->job_name, printer, settings, page_setup);
          op_unix->job = job;
          gtk_print_job_set_track_print_status (job, priv->track_print_status);
571
	  
572
	  op_unix->surface = gtk_print_job_get_surface (job, &priv->error);
Matthias Clasen's avatar
Matthias Clasen committed
573 574
	  if (op_unix->surface == NULL) 
            {
575
	      rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
Matthias Clasen's avatar
Matthias Clasen committed
576 577 578
	      rdata->do_print = FALSE;
	      goto out;
            }
579 580
	  
	  cr = cairo_create (op_unix->surface);
Matthias Clasen's avatar
Matthias Clasen committed
581
	  gtk_print_context_set_cairo_context (priv->print_context, cr, 72, 72);
582 583
	  cairo_destroy (cr);

Matthias Clasen's avatar
Matthias Clasen committed
584
          _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
585 586
	  
          op_unix->job_status_changed_tag =
Matthias Clasen's avatar
Matthias Clasen committed
587
	    g_signal_connect (job, "status-changed",
588 589
			      G_CALLBACK (job_status_changed_cb), op);
	  
590 591 592 593 594 595 596 597 598 599
          priv->print_pages = gtk_print_job_get_pages (job);
          priv->page_ranges = gtk_print_job_get_page_ranges (job, &priv->num_page_ranges);
          priv->manual_num_copies = gtk_print_job_get_num_copies (job);
          priv->manual_collation = gtk_print_job_get_collate (job);
          priv->manual_reverse = gtk_print_job_get_reverse (job);
          priv->manual_page_set = gtk_print_job_get_page_set (job);
          priv->manual_scale = gtk_print_job_get_scale (job);
          priv->manual_orientation = gtk_print_job_get_rotate (job);
          priv->manual_number_up = gtk_print_job_get_n_up (job);
          priv->manual_number_up_layout = gtk_print_job_get_n_up_layout (job);
600
        }
601
    } 
602
 out:
603
  if (rdata->print_cb)
604
    rdata->print_cb (op, rdata->parent, rdata->do_print, rdata->result); 
605 606 607 608 609

  if (rdata->destroy)
    rdata->destroy (rdata);
}

610
static void 
Alexander Larsson's avatar
Alexander Larsson committed
611 612 613 614 615 616 617 618 619
handle_print_response (GtkWidget *dialog,
		       gint       response,
		       gpointer   data)
{
  GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog);
  PrintResponseData *rdata = data;
  GtkPrintSettings *settings = NULL;
  GtkPageSetup *page_setup = NULL;
  GtkPrinter *printer = NULL;
620
  gboolean page_setup_set = FALSE;
Alexander Larsson's avatar
Alexander Larsson committed
621 622 623 624

  if (response == GTK_RESPONSE_OK)
    {
      printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
625 626 627

      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
      rdata->do_preview = FALSE;
628 629 630 631 632 633
      if (printer != NULL)
	rdata->do_print = TRUE;
    } 
  else if (response == GTK_RESPONSE_APPLY)
    {
      /* print preview */
634 635
      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
      rdata->do_preview = TRUE;
Alexander Larsson's avatar
Alexander Larsson committed
636
      rdata->do_print = TRUE;
637 638

      rdata->op->priv->action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
639
    }
Alexander Larsson's avatar
Alexander Larsson committed
640

641 642
  if (rdata->do_print)
    {
Alexander Larsson's avatar
Alexander Larsson committed
643 644
      settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
      page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
645
      page_setup_set = gtk_print_unix_dialog_get_page_setup_set (GTK_PRINT_UNIX_DIALOG (pd));
646 647 648 649 650

      /* Set new print settings now so that custom-widget options
       * can be added to the settings in the callback
       */
      gtk_print_operation_set_print_settings (rdata->op, settings);
651
      g_signal_emit_by_name (rdata->op, "custom-widget-apply", rdata->op->priv->custom_widget);
652 653
    }
  
654
  finish_print (rdata, printer, page_setup, settings, page_setup_set);
Alexander Larsson's avatar
Alexander Larsson committed
655 656 657

  if (settings)
    g_object_unref (settings);
658
    
Alexander Larsson's avatar
Alexander Larsson committed
659
  gtk_widget_destroy (GTK_WIDGET (pd));
660
 
Alexander Larsson's avatar
Alexander Larsson committed
661 662 663 664
}


static void
Matthias Clasen's avatar
Matthias Clasen committed
665
found_printer (GtkPrinter        *printer,
Alexander Larsson's avatar
Alexander Larsson committed
666 667 668 669 670 671 672 673 674 675
	       PrintResponseData *rdata)
{
  GtkPrintOperation *op = rdata->op;
  GtkPrintOperationPrivate *priv = op->priv;
  GtkPrintSettings *settings = NULL;
  GtkPageSetup *page_setup = NULL;
  
  if (rdata->loop)
    g_main_loop_quit (rdata->loop);

Matthias Clasen's avatar
Matthias Clasen committed
676 677
  if (printer != NULL) 
    {
678
      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
Alexander Larsson's avatar
Alexander Larsson committed
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695

      rdata->do_print = TRUE;

      if (priv->print_settings)
	settings = gtk_print_settings_copy (priv->print_settings);
      else
	settings = gtk_print_settings_new ();

      gtk_print_settings_set_printer (settings,
				      gtk_printer_get_name (printer));
      
      if (priv->default_page_setup)
	page_setup = gtk_page_setup_copy (priv->default_page_setup);
      else
	page_setup = gtk_page_setup_new ();
  }
  
696
  finish_print (rdata, printer, page_setup, settings, FALSE);
Alexander Larsson's avatar
Alexander Larsson committed
697 698 699 700 701 702 703 704

  if (settings)
    g_object_unref (settings);
  
  if (page_setup)
    g_object_unref (page_setup);
}

705 706
void
_gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
707
							gboolean                    show_dialog,
708 709 710 711 712
                                                        GtkWindow                  *parent,
							GtkPrintOperationPrintFunc  print_cb)
{
  GtkWidget *pd;
  PrintResponseData *rdata;
Matthias Clasen's avatar
Matthias Clasen committed
713
  const gchar *printer_name;
714 715 716 717

  rdata = g_new (PrintResponseData, 1);
  rdata->op = g_object_ref (op);
  rdata->do_print = FALSE;
718
  rdata->do_preview = FALSE;
719 720
  rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
  rdata->print_cb = print_cb;
Alexander Larsson's avatar
Alexander Larsson committed
721 722
  rdata->parent = parent;
  rdata->loop = NULL;
723
  rdata->destroy = print_response_data_free;
724
  
725
  if (show_dialog)
Alexander Larsson's avatar
Alexander Larsson committed
726 727 728
    {
      pd = get_print_dialog (op, parent);
      gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
729

Alexander Larsson's avatar
Alexander Larsson committed
730 731 732 733 734 735 736 737 738 739 740
      g_signal_connect (pd, "response", 
			G_CALLBACK (handle_print_response), rdata);
      
      gtk_window_present (GTK_WINDOW (pd));
    }
  else
    {
      printer_name = NULL;
      if (op->priv->print_settings)
	printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
      
Matthias Clasen's avatar
Matthias Clasen committed
741
      find_printer (printer_name, (GFunc) found_printer, rdata);
Alexander Larsson's avatar
Alexander Larsson committed
742
    }
743 744
}

Matthias Clasen's avatar
Matthias Clasen committed
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
static cairo_status_t
write_preview (void                *closure,
               const unsigned char *data,
               unsigned int         length)
{
  gint fd = GPOINTER_TO_INT (closure);
  gssize written;
  
  while (length > 0) 
    {
      written = write (fd, data, length);

      if (written == -1)
	{
	  if (errno == EAGAIN || errno == EINTR)
	    continue;
	  
	  return CAIRO_STATUS_WRITE_ERROR;
	}    

      data += written;
      length -= written;
    }

  return CAIRO_STATUS_SUCCESS;
}

static void
close_preview (void *data)
{
  gint fd = GPOINTER_TO_INT (data);

  close (fd);
}

780 781
cairo_surface_t *
_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
Matthias Clasen's avatar
Matthias Clasen committed
782 783 784
							      GtkPageSetup      *page_setup,
							      gdouble           *dpi_x,
							      gdouble           *dpi_y,
785
							      gchar            **target)
786
{
Matthias Clasen's avatar
Matthias Clasen committed
787 788
  gchar *filename;
  gint fd;
789
  GtkPaperSize *paper_size;
Matthias Clasen's avatar
Matthias Clasen committed
790
  gdouble w, h;
Matthias Clasen's avatar
Matthias Clasen committed
791 792
  cairo_surface_t *surface;
  static cairo_user_data_key_t key;
793
  
Matthias Clasen's avatar
Matthias Clasen committed
794 795
  filename = g_build_filename (g_get_tmp_dir (), "previewXXXXXX.pdf", NULL);
  fd = g_mkstemp (filename);
796 797 798 799 800 801 802

  if (fd < 0)
    {
      g_free (filename);
      return NULL;
    }

Matthias Clasen's avatar
Matthias Clasen committed
803
  *target = filename;
804
  
805 806 807 808 809
  paper_size = gtk_page_setup_get_paper_size (page_setup);
  w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
  h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
    
  *dpi_x = *dpi_y = 72;
810
  surface = cairo_pdf_surface_create_for_stream (write_preview, GINT_TO_POINTER (fd), w, h);
Matthias Clasen's avatar
Matthias Clasen committed
811 812 813 814
 
  cairo_surface_set_user_data (surface, &key, GINT_TO_POINTER (fd), close_preview);

  return surface;
815 816 817 818
}

void
_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
819 820
							  cairo_surface_t   *surface,
							  cairo_t           *cr)
821 822 823 824 825
{
}

void
_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
826 827
							cairo_surface_t   *surface,
							cairo_t           *cr)
828 829
{
  cairo_show_page (cr);
830 831 832 833
}

void
_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
Matthias Clasen's avatar
Matthias Clasen committed
834 835
							      GtkPageSetup      *page_setup,
							      cairo_surface_t   *surface)
836
{
Matthias Clasen's avatar
Matthias Clasen committed
837
  gdouble w, h;
838
  
839 840
  w = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
  h = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
841 842 843 844
  cairo_pdf_surface_set_size (surface, w, h);
}


845 846
GtkPrintOperationResult
_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
847
						  gboolean           show_dialog,
848
						  GtkWindow         *parent,
849
						  gboolean          *do_print)
850 851 852 853
 {
  GtkWidget *pd;
  PrintResponseData rdata;
  gint response;  
Matthias Clasen's avatar
Matthias Clasen committed
854
  const gchar *printer_name;
855 856 857
   
  rdata.op = op;
  rdata.do_print = FALSE;
858
  rdata.do_preview = FALSE;
859 860 861
  rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
  rdata.print_cb = NULL;
  rdata.destroy = NULL;
Alexander Larsson's avatar
Alexander Larsson committed
862 863
  rdata.parent = parent;
  rdata.loop = NULL;
864

865
  if (show_dialog)
Alexander Larsson's avatar
Alexander Larsson committed
866 867
    {
      pd = get_print_dialog (op, parent);
868

Alexander Larsson's avatar
Alexander Larsson committed
869 870 871 872 873 874 875 876 877 878 879 880
      response = gtk_dialog_run (GTK_DIALOG (pd));
      handle_print_response (pd, response, &rdata);
    }
  else
    {
      printer_name = NULL;
      if (op->priv->print_settings)
	printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
      
      rdata.loop = g_main_loop_new (NULL, FALSE);
      find_printer (printer_name,
		    (GFunc) found_printer, &rdata);
881

882
      gdk_threads_leave ();  
Alexander Larsson's avatar
Alexander Larsson committed
883
      g_main_loop_run (rdata.loop);
884
      gdk_threads_enter ();  
885

Alexander Larsson's avatar
Alexander Larsson committed
886
      g_main_loop_unref (rdata.loop);
887
      rdata.loop = NULL;
Alexander Larsson's avatar
Alexander Larsson committed
888
    }
889

Alexander Larsson's avatar
Alexander Larsson committed
890 891
  *do_print = rdata.do_print;
  
892 893 894 895
  return rdata.result;
}


Matthias Clasen's avatar
Matthias Clasen committed
896 897
typedef struct 
{
898 899 900 901
  GtkPageSetup         *page_setup;
  GtkPageSetupDoneFunc  done_cb;
  gpointer              data;
  GDestroyNotify        destroy;
902 903 904 905 906 907 908
} PageSetupResponseData;

static void
page_setup_data_free (gpointer data)
{
  PageSetupResponseData *rdata = data;

Matthias Clasen's avatar
Matthias Clasen committed
909 910 911
  if (rdata->page_setup)
    g_object_unref (rdata->page_setup);

912 913 914 915 916 917 918 919 920 921
  g_free (rdata);
}

static void
handle_page_setup_response (GtkWidget *dialog,
			    gint       response,
			    gpointer   data)
{
  GtkPageSetupUnixDialog *psd;
  PageSetupResponseData *rdata = data;
922

923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
  psd = GTK_PAGE_SETUP_UNIX_DIALOG (dialog);
  if (response == GTK_RESPONSE_OK)
    rdata->page_setup = gtk_page_setup_unix_dialog_get_page_setup (psd);

  gtk_widget_destroy (dialog);

  if (rdata->done_cb)
    rdata->done_cb (rdata->page_setup, rdata->data);

  if (rdata->destroy)
    rdata->destroy (rdata);
}

static GtkWidget *
get_page_setup_dialog (GtkWindow        *parent,
		       GtkPageSetup     *page_setup,
		       GtkPrintSettings *settings)
{
  GtkWidget *dialog;

  dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
  if (page_setup)
    gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
					       page_setup);
  gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
						 settings);

  return dialog;
951 952
}

953 954
/**
 * gtk_print_run_page_setup_dialog:
955 956
 * @parent: (allow-none): transient parent
 * @page_setup: (allow-none): an existing #GtkPageSetup
957
 * @settings: a #GtkPrintSettings
958 959 960
 *
 * Runs a page setup dialog, letting the user modify the values from
 * @page_setup. If the user cancels the dialog, the returned #GtkPageSetup
961 962 963 964 965 966
 * is identical to the passed in @page_setup, otherwise it contains the 
 * modifications done in the dialog.
 *
 * Note that this function may use a recursive mainloop to show the page
 * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is 
 * a problem.
967
 * 
968
 * Return value: (transfer full): a new #GtkPageSetup
969 970 971
 *
 * Since: 2.10
 */
972 973 974 975 976 977
GtkPageSetup *
gtk_print_run_page_setup_dialog (GtkWindow        *parent,
				 GtkPageSetup     *page_setup,
				 GtkPrintSettings *settings)
{
  GtkWidget *dialog;
978 979
  gint response;
  PageSetupResponseData rdata;  
980
  
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
  rdata.page_setup = NULL;
  rdata.done_cb = NULL;
  rdata.data = NULL;
  rdata.destroy = NULL;

  dialog = get_page_setup_dialog (parent, page_setup, settings);
  response = gtk_dialog_run (GTK_DIALOG (dialog));
  handle_page_setup_response (dialog, response, &rdata);
 
  if (rdata.page_setup)
    return rdata.page_setup;
  else if (page_setup)
    return gtk_page_setup_copy (page_setup);
  else
    return gtk_page_setup_new ();
996 997
}

998 999
/**
 * gtk_print_run_page_setup_dialog_async:
1000 1001
 * @parent: (allow-none): transient parent, or %NULL
 * @page_setup: (allow-none): an existing #GtkPageSetup, or %NULL
1002
 * @settings: a #GtkPrintSettings
1003 1004
 * @done_cb: (scope async): a function to call when the user saves
 *           the modified page setup
1005 1006
 * @data: user data to pass to @done_cb
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1007
 * Runs a page setup dialog, letting the user modify the values from @page_setup. 
1008
 *
Matthias Clasen's avatar
Matthias Clasen committed
1009 1010 1011
 * In contrast to gtk_print_run_page_setup_dialog(), this function  returns after 
 * showing the page setup dialog on platforms that support this, and calls @done_cb 
 * from a signal handler for the ::response signal of the dialog.
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
 *
 * Since: 2.10
 */
void
gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
				       GtkPageSetup         *page_setup,
				       GtkPrintSettings     *settings,
				       GtkPageSetupDoneFunc  done_cb,
				       gpointer              data)
{
  GtkWidget *dialog;
  PageSetupResponseData *rdata;
  
  dialog = get_page_setup_dialog (parent, page_setup, settings);
  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
  
  rdata = g_new (PageSetupResponseData, 1);
  rdata->page_setup = NULL;
  rdata->done_cb = done_cb;
  rdata->data = data;
  rdata->destroy = page_setup_data_free;

  g_signal_connect (dialog, "response",
		    G_CALLBACK (handle_page_setup_response), rdata);
 
  gtk_window_present (GTK_WINDOW (dialog));
 }

Matthias Clasen's avatar
Matthias Clasen committed
1040 1041
struct _PrinterFinder 
{
Alexander Larsson's avatar
Alexander Larsson committed
1042 1043 1044
  gboolean found_printer;
  GFunc func;
  gpointer data;
Matthias Clasen's avatar
Matthias Clasen committed
1045
  gchar *printer_name;
Alexander Larsson's avatar
Alexander Larsson committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
  GList *backends;
  guint timeout_tag;
  GtkPrinter *printer;
  GtkPrinter *default_printer;
  GtkPrinter *first_printer;
};

static gboolean
find_printer_idle (gpointer data)
{
  PrinterFinder *finder = data;
  GtkPrinter *printer;

  if (finder->printer != NULL)
    printer = finder->printer;
  else if (finder->default_printer != NULL)
    printer = finder->default_printer;
  else if (finder->first_printer != NULL)
    printer = finder->first_printer;
  else
    printer = NULL;

  finder->func (printer, finder->data);
  
  printer_finder_free (finder);

1072
  return G_SOURCE_REMOVE;
Alexander Larsson's avatar
Alexander Larsson committed
1073 1074 1075 1076 1077 1078 1079
}

static void
printer_added_cb (GtkPrintBackend *backend, 
                  GtkPrinter      *printer, 
		  PrinterFinder   *finder)
{
1080 1081 1082 1083 1084
  if (finder->found_printer)
    return;

  /* FIXME this skips "Print to PDF" - is this intentional ? */
  if (gtk_printer_is_virtual (printer))
Alexander Larsson's avatar
Alexander Larsson committed
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    return;

  if (finder->printer_name != NULL &&
      strcmp (gtk_printer_get_name (printer), finder->printer_name) == 0)
    {
      finder->printer = g_object_ref (printer);
      finder->found_printer = TRUE;
    }
  else if (finder->default_printer == NULL &&
	   gtk_printer_is_default (printer))
    {
      finder->default_printer = g_object_ref (printer);
      if (finder->printer_name == NULL)
	finder->found_printer = TRUE;
    }
  else
    if (finder->first_printer == NULL)
      finder->first_printer = g_object_ref (printer);
  
  if (finder->found_printer)
    g_idle_add (find_printer_idle, finder);
}

static void
printer_list_done_cb (GtkPrintBackend *backend, 
		      PrinterFinder   *finder)
{
  finder->backends = g_list_remove (finder->backends, backend);
  
  g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
  g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
  
  gtk_print_backend_destroy (backend);
  g_object_unref (backend);

  if (finder->backends == NULL && !finder->found_printer)
    g_idle_add (find_printer_idle, finder);
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
1125
find_printer_init (PrinterFinder   *finder,
Alexander Larsson's avatar
Alexander Larsson committed
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
		   GtkPrintBackend *backend)
{
  GList *list;
  GList *node;

  list = gtk_print_backend_get_printer_list (backend);

  node = list;
  while (node != NULL)
    {
      printer_added_cb (backend, node->data, finder);
      node = node->next;

      if (finder->found_printer)
	break;
    }

  g_list_free (list);

  if (gtk_print_backend_printer_list_is_done (backend))
    {
      finder->backends = g_list_remove (finder->backends, backend);
      gtk_print_backend_destroy (backend);
      g_object_unref (backend);
    }
  else
    {
Matthias Clasen's avatar
Matthias Clasen committed
1153
      g_signal_connect (backend, "printer-added", 
Alexander Larsson's avatar
Alexander Larsson committed
1154 1155
			(GCallback) printer_added_cb, 
			finder);
Matthias Clasen's avatar
Matthias Clasen committed
1156
      g_signal_connect (backend, "printer-list-done", 
Alexander Larsson's avatar
Alexander Larsson committed
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
			(GCallback) printer_list_done_cb, 
			finder);
    }

}

static void
printer_finder_free (PrinterFinder *finder)
{
  GList *l;
  
  g_free (finder->printer_name);
  
  if (finder->printer)
    g_object_unref (finder->printer);
  
  if (finder->default_printer)
    g_object_unref (finder->default_printer);
  
  if (finder->first_printer)
    g_object_unref (finder->first_printer);

  for (l = finder->backends; l != NULL; l = l->next)
    {
      GtkPrintBackend *backend = l->data;
      g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
      g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
      gtk_print_backend_destroy (backend);
      g_object_unref (backend);
    }
  
  g_list_free (finder->backends);
  
  g_free (finder);
}

static void 
Matthias Clasen's avatar
Matthias Clasen committed
1194 1195 1196
find_printer (const gchar *printer,
	      GFunc        func,
	      gpointer     data)
Alexander Larsson's avatar
Alexander Larsson committed
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
{
  GList *node, *next;
  PrinterFinder *finder;

  finder = g_new0 (PrinterFinder, 1);

  finder->printer_name = g_strdup (printer);
  finder->func = func;
  finder->data = data;
  
  finder->backends = NULL;
  if (g_module_supported ())
    finder->backends = gtk_print_backend_load_modules ();

  for (node = finder->backends; !finder->found_printer && node != NULL; node = next)
    {
      next = node->next;
      find_printer_init (finder, GTK_PRINT_BACKEND (node->data));
    }

  if (finder->backends == NULL && !finder->found_printer)
    g_idle_add (find_printer_idle, finder);
}