gtkprintbackend.c 25.5 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10 11 12 13 14 15
 * gtkprintbackend.h: Abstract printer backend interfaces
 * Copyright (C) 2003, 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
16
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 18 19 20 21 22 23 24 25
 */

#include "config.h"
#include <string.h>

#include <gmodule.h>

#include "gtkintl.h"
#include "gtkmodules.h"
26
#include "gtkmodulesprivate.h"
27
#include "gtkmarshalers.h"
28 29 30
#include "gtkprivate.h"
#include "gtkprintbackend.h"

Alexander Larsson's avatar
Alexander Larsson committed
31

32 33 34 35 36 37 38 39 40
static void gtk_print_backend_dispose      (GObject      *object);
static void gtk_print_backend_set_property (GObject      *object,
                                            guint         prop_id,
                                            const GValue *value,
                                            GParamSpec   *pspec);
static void gtk_print_backend_get_property (GObject      *object,
                                            guint         prop_id,
                                            GValue       *value,
                                            GParamSpec   *pspec);
Alexander Larsson's avatar
Alexander Larsson committed
41 42 43 44 45 46

struct _GtkPrintBackendPrivate
{
  GHashTable *printers;
  guint printer_list_requested : 1;
  guint printer_list_done : 1;
47
  GtkPrintBackendStatus status;
48 49
  char **auth_info_required;
  char **auth_info;
50
  gboolean store_auth_info;
Alexander Larsson's avatar
Alexander Larsson committed
51 52 53 54 55 56 57 58
};

enum {
  PRINTER_LIST_CHANGED,
  PRINTER_LIST_DONE,
  PRINTER_ADDED,
  PRINTER_REMOVED,
  PRINTER_STATUS_CHANGED,
59
  REQUEST_PASSWORD,
Alexander Larsson's avatar
Alexander Larsson committed
60 61 62 63 64
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

65 66 67 68 69 70
enum 
{ 
  PROP_ZERO,
  PROP_STATUS
};

Alexander Larsson's avatar
Alexander Larsson committed
71
static GObjectClass *backend_parent_class;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

GQuark
gtk_print_backend_error_quark (void)
{
  static GQuark quark = 0;
  if (quark == 0)
    quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
  return quark;
}

/*****************************************
 *     GtkPrintBackendModule modules     *
 *****************************************/

typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;

struct _GtkPrintBackendModule
{
  GTypeModule parent_instance;
  
  GModule *library;

  void             (*init)     (GTypeModule    *module);
  void             (*exit)     (void);
  GtkPrintBackend* (*create)   (void);

  gchar *path;
};

struct _GtkPrintBackendModuleClass
{
  GTypeModuleClass parent_class;
};

107 108
GType _gtk_print_backend_module_get_type (void);

Matthias Clasen's avatar
Matthias Clasen committed
109
G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
110 111 112 113 114 115 116 117 118 119 120 121 122 123
#define GTK_TYPE_PRINT_BACKEND_MODULE      (_gtk_print_backend_module_get_type ())
#define GTK_PRINT_BACKEND_MODULE(module)   (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))

static GSList *loaded_backends;

static gboolean
gtk_print_backend_module_load (GTypeModule *module)
{
  GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module); 
  gpointer initp, exitp, createp;
 
  pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
  if (!pb_module->library)
    {
124
      g_warning ("%s", g_module_error());
125 126 127 128 129 130 131 132 133 134 135
      return FALSE;
    }
  
  /* extract symbols from the lib */
  if (!g_module_symbol (pb_module->library, "pb_module_init",
			&initp) ||
      !g_module_symbol (pb_module->library, "pb_module_exit", 
			&exitp) ||
      !g_module_symbol (pb_module->library, "pb_module_create", 
			&createp))
    {
136
      g_warning ("%s", g_module_error());
137 138 139 140 141 142 143 144 145
      g_module_close (pb_module->library);
      
      return FALSE;
    }

  pb_module->init = initp;
  pb_module->exit = exitp;
  pb_module->create = createp;

Johan Dahlin's avatar
Johan Dahlin committed
146
  /* call the printbackend's init function to let it */
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  /* setup anything it needs to set up. */
  pb_module->init (module);

  return TRUE;
}

static void
gtk_print_backend_module_unload (GTypeModule *module)
{
  GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
  
  pb_module->exit();

  g_module_close (pb_module->library);
  pb_module->library = NULL;

  pb_module->init = NULL;
  pb_module->exit = NULL;
  pb_module->create = NULL;
}

/* This only will ever be called if an error occurs during
 * initialization
 */
static void
gtk_print_backend_module_finalize (GObject *object)
{
  GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);

  g_free (module->path);

  G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
}

static void
_gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
{
  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Alexander Larsson's avatar
Alexander Larsson committed
186

187 188 189 190 191 192
  module_class->load = gtk_print_backend_module_load;
  module_class->unload = gtk_print_backend_module_unload;

  gobject_class->finalize = gtk_print_backend_module_finalize;
}

193 194 195 196 197 198 199
static void 
gtk_print_backend_set_property (GObject      *object,
                                guint         prop_id,
                                const GValue *value,
                                GParamSpec   *pspec)
{
  GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
200
  GtkPrintBackendPrivate *priv = backend->priv;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

  switch (prop_id)
    {
    case PROP_STATUS:
      priv->status = g_value_get_int (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void 
gtk_print_backend_get_property (GObject    *object,
                                guint       prop_id,
                                GValue     *value,
                                GParamSpec *pspec)
{
  GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
220
  GtkPrintBackendPrivate *priv = backend->priv;
221 222 223 224 225 226 227 228 229 230 231 232

  switch (prop_id)
    {
    case PROP_STATUS:
      g_value_set_int (value, priv->status);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
static void
_gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
{
}

static GtkPrintBackend *
_gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
{
  GtkPrintBackend *pb;
  
  if (g_type_module_use (G_TYPE_MODULE (pb_module)))
    {
      pb = pb_module->create ();
      g_type_module_unuse (G_TYPE_MODULE (pb_module));
      return pb;
    }
  return NULL;
}

252
static GtkPrintBackend *
Matthias Clasen's avatar
Matthias Clasen committed
253
_gtk_print_backend_create (const gchar *backend_name)
254 255
{
  GSList *l;
Matthias Clasen's avatar
Matthias Clasen committed
256 257
  gchar *module_path;
  gchar *full_name;
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
  GtkPrintBackendModule *pb_module;
  GtkPrintBackend *pb;

  for (l = loaded_backends; l != NULL; l = l->next)
    {
      pb_module = l->data;
      
      if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
	return _gtk_print_backend_module_create (pb_module);
    }

  pb = NULL;
  if (g_module_supported ())
    {
      full_name = g_strconcat ("printbackend-", backend_name, NULL);
      module_path = _gtk_find_module (full_name, "printbackends");
      g_free (full_name);

      if (module_path)
	{
	  pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);

	  g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
	  pb_module->path = g_strdup (module_path);

	  loaded_backends = g_slist_prepend (loaded_backends,
		   		             pb_module);

	  pb = _gtk_print_backend_module_create (pb_module);
287 288

	  /* Increase use-count so that we don't unload print backends.
Matthias Clasen's avatar
Matthias Clasen committed
289 290 291
	   * There is a problem with module unloading in the cups module,
	   * see cups_dispatch_watch_finalize for details. 
	   */
292
	  g_type_module_use (G_TYPE_MODULE (pb_module));
293 294 295 296 297 298 299 300
	}
      
      g_free (module_path);
    }

  return pb;
}

301
/**
302
 * gtk_print_backend_load_modules:
303
 *
304
 * Returns: (element-type GtkPrintBackend) (transfer container):
305
 */
306
GList *
Matthias Clasen's avatar
Matthias Clasen committed
307
gtk_print_backend_load_modules (void)
308 309 310 311 312 313 314 315 316 317 318
{
  GList *result;
  GtkPrintBackend *backend;
  gchar *setting;
  gchar **backends;
  gint i;
  GtkSettings *settings;

  result = NULL;

  settings = gtk_settings_get_default ();
319 320 321 322
  if (settings)
    g_object_get (settings, "gtk-print-backends", &setting, NULL);
  else
    setting = g_strdup (GTK_PRINT_BACKENDS);
323 324 325 326 327

  backends = g_strsplit (setting, ",", -1);

  for (i = 0; backends[i]; i++)
    {
328
      backend = _gtk_print_backend_create (g_strstrip (backends[i]));
329 330 331 332 333 334 335 336 337 338 339 340 341
      if (backend)
        result = g_list_append (result, backend);
    }

  g_strfreev (backends);
  g_free (setting);

  return result;
}

/*****************************************
 *             GtkPrintBackend           *
 *****************************************/
Alexander Larsson's avatar
Alexander Larsson committed
342

343
G_DEFINE_TYPE_WITH_PRIVATE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
Alexander Larsson's avatar
Alexander Larsson committed
344

345 346 347
static void                 fallback_printer_request_details       (GtkPrinter          *printer);
static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
								    GtkPrinterOptionSet *options);
348 349 350 351 352
static gboolean             fallback_printer_get_hard_margins      (GtkPrinter          *printer,
                                                                    gdouble             *top,
                                                                    gdouble             *bottom,
                                                                    gdouble             *left,
                                                                    gdouble             *right);
353 354 355
static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
356
static void                 request_password                       (GtkPrintBackend     *backend,
357 358 359 360
                                                                    gpointer             auth_info_required,
                                                                    gpointer             auth_info_default,
                                                                    gpointer             auth_info_display,
                                                                    gpointer             auth_info_visible,
361 362
                                                                    const gchar         *prompt,
                                                                    gboolean             can_store_auth_info);
363
  
Alexander Larsson's avatar
Alexander Larsson committed
364 365
static void
gtk_print_backend_class_init (GtkPrintBackendClass *class)
366
{
Alexander Larsson's avatar
Alexander Larsson committed
367 368
  GObjectClass *object_class;
  object_class = (GObjectClass *) class;
369

Alexander Larsson's avatar
Alexander Larsson committed
370 371 372
  backend_parent_class = g_type_class_peek_parent (class);
  
  object_class->dispose = gtk_print_backend_dispose;
373 374
  object_class->set_property = gtk_print_backend_set_property;
  object_class->get_property = gtk_print_backend_get_property;
Alexander Larsson's avatar
Alexander Larsson committed
375

376 377 378 379
  class->printer_request_details = fallback_printer_request_details;
  class->printer_mark_conflicts = fallback_printer_mark_conflicts;
  class->printer_get_hard_margins = fallback_printer_get_hard_margins;
  class->printer_list_papers = fallback_printer_list_papers;
380
  class->printer_get_default_page_size = fallback_printer_get_default_page_size;
381
  class->printer_get_capabilities = fallback_printer_get_capabilities;
382
  class->request_password = request_password;
383
  
384 385 386 387 388 389 390 391 392
  g_object_class_install_property (object_class, 
                                   PROP_STATUS,
                                   g_param_spec_int ("status",
                                                     "Status",
                                                     "The status of the print backend",
                                                     GTK_PRINT_BACKEND_STATUS_UNKNOWN,
                                                     GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
                                                     GTK_PRINT_BACKEND_STATUS_UNKNOWN,
                                                     GTK_PARAM_READWRITE)); 
Alexander Larsson's avatar
Alexander Larsson committed
393 394
  
  signals[PRINTER_LIST_CHANGED] =
Matthias Clasen's avatar
Matthias Clasen committed
395
    g_signal_new (I_("printer-list-changed"),
Alexander Larsson's avatar
Alexander Larsson committed
396 397 398 399 400 401 402
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
  signals[PRINTER_LIST_DONE] =
Matthias Clasen's avatar
Matthias Clasen committed
403
    g_signal_new (I_("printer-list-done"),
Alexander Larsson's avatar
Alexander Larsson committed
404 405 406 407 408 409 410
		    G_TYPE_FROM_CLASS (class),
		    G_SIGNAL_RUN_LAST,
		    G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
		    NULL, NULL,
		    g_cclosure_marshal_VOID__VOID,
		    G_TYPE_NONE, 0);
  signals[PRINTER_ADDED] =
Matthias Clasen's avatar
Matthias Clasen committed
411
    g_signal_new (I_("printer-added"),
Alexander Larsson's avatar
Alexander Larsson committed
412 413 414 415 416 417 418
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
  signals[PRINTER_REMOVED] =
Matthias Clasen's avatar
Matthias Clasen committed
419
    g_signal_new (I_("printer-removed"),
Alexander Larsson's avatar
Alexander Larsson committed
420 421 422 423 424 425 426
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
  signals[PRINTER_STATUS_CHANGED] =
Matthias Clasen's avatar
Matthias Clasen committed
427
    g_signal_new (I_("printer-status-changed"),
Alexander Larsson's avatar
Alexander Larsson committed
428 429 430 431 432 433
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
434 435 436 437 438
  signals[REQUEST_PASSWORD] =
    g_signal_new (I_("request-password"),
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
439 440 441
		  NULL, NULL, NULL,
		  G_TYPE_NONE, 6, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
		  G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
Alexander Larsson's avatar
Alexander Larsson committed
442 443 444 445 446 447 448
}

static void
gtk_print_backend_init (GtkPrintBackend *backend)
{
  GtkPrintBackendPrivate *priv;

449
  priv = backend->priv = gtk_print_backend_get_instance_private (backend);
Alexander Larsson's avatar
Alexander Larsson committed
450 451 452 453

  priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
					  (GDestroyNotify) g_free,
					  (GDestroyNotify) g_object_unref);
454 455
  priv->auth_info_required = NULL;
  priv->auth_info = NULL;
Alexander Larsson's avatar
Alexander Larsson committed
456 457 458 459 460 461 462 463 464 465 466 467
}

static void
gtk_print_backend_dispose (GObject *object)
{
  GtkPrintBackend *backend;
  GtkPrintBackendPrivate *priv;

  backend = GTK_PRINT_BACKEND (object);
  priv = backend->priv;

  /* We unref the printers in dispose, not in finalize so that
Matthias Clasen's avatar
Matthias Clasen committed
468 469
   * we can break refcount cycles with gtk_print_backend_destroy 
   */
Alexander Larsson's avatar
Alexander Larsson committed
470
  if (priv->printers)
471
    {
Alexander Larsson's avatar
Alexander Larsson committed
472 473
      g_hash_table_destroy (priv->printers);
      priv->printers = NULL;
474 475
    }

Alexander Larsson's avatar
Alexander Larsson committed
476
  backend_parent_class->dispose (object);
477 478
}

Alexander Larsson's avatar
Alexander Larsson committed
479

480 481 482 483 484 485
static void
fallback_printer_request_details (GtkPrinter *printer)
{
}

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
486
fallback_printer_mark_conflicts (GtkPrinter          *printer,
487 488 489 490 491
				 GtkPrinterOptionSet *options)
{
  return FALSE;
}

492
static gboolean
493
fallback_printer_get_hard_margins (GtkPrinter *printer,
Matthias Clasen's avatar
Matthias Clasen committed
494 495 496 497
				   gdouble    *top,
				   gdouble    *bottom,
				   gdouble    *left,
				   gdouble    *right)
498
{
499
  return FALSE;
500 501 502 503 504 505 506 507
}

static GList *
fallback_printer_list_papers (GtkPrinter *printer)
{
  return NULL;
}

508 509 510 511 512 513
static GtkPageSetup *
fallback_printer_get_default_page_size (GtkPrinter *printer)
{
  return NULL;
}

514 515 516 517 518 519 520
static GtkPrintCapabilities
fallback_printer_get_capabilities (GtkPrinter *printer)
{
  return 0;
}


521
static void
Matthias Clasen's avatar
Matthias Clasen committed
522 523 524
printer_hash_to_sorted_active_list (const gchar  *key,
                                    gpointer      value,
                                    GList       **out_list)
525
{
Alexander Larsson's avatar
Alexander Larsson committed
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
  GtkPrinter *printer;

  printer = GTK_PRINTER (value);

  if (gtk_printer_get_name (printer) == NULL)
    return;

  if (!gtk_printer_is_active (printer))
    return;

  *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
}


void
gtk_print_backend_add_printer (GtkPrintBackend *backend,
Matthias Clasen's avatar
Matthias Clasen committed
542
			       GtkPrinter      *printer)
Alexander Larsson's avatar
Alexander Larsson committed
543 544
{
  GtkPrintBackendPrivate *priv;
545
  
Alexander Larsson's avatar
Alexander Larsson committed
546
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
547

Alexander Larsson's avatar
Alexander Larsson committed
548
  priv = backend->priv;
549

Alexander Larsson's avatar
Alexander Larsson committed
550 551 552 553 554 555 556 557 558 559
  if (!priv->printers)
    return;
  
  g_hash_table_insert (priv->printers,
		       g_strdup (gtk_printer_get_name (printer)), 
		       g_object_ref (printer));
}

void
gtk_print_backend_remove_printer (GtkPrintBackend *backend,
Matthias Clasen's avatar
Matthias Clasen committed
560
				  GtkPrinter      *printer)
Alexander Larsson's avatar
Alexander Larsson committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
{
  GtkPrintBackendPrivate *priv;
  
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
  priv = backend->priv;

  if (!priv->printers)
    return;
  
  g_hash_table_remove (priv->printers,
		       gtk_printer_get_name (printer));
}

void
gtk_print_backend_set_list_done (GtkPrintBackend *backend)
{
  if (!backend->priv->printer_list_done)
    {
      backend->priv->printer_list_done = TRUE;
      g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
581 582 583
    }
}

Alexander Larsson's avatar
Alexander Larsson committed
584

585 586 587
/**
 * gtk_print_backend_get_printer_list:
 *
588 589
 * Returns the current list of printers.
 *
590
 * Returns: (element-type GtkPrinter) (transfer container):
591 592
 *   A list of #GtkPrinter objects. The list should be freed
 *   with g_list_free().
593
 */
594
GList *
Alexander Larsson's avatar
Alexander Larsson committed
595
gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
596
{
Alexander Larsson's avatar
Alexander Larsson committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
  GtkPrintBackendPrivate *priv;
  GList *result;
  
  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);

  priv = backend->priv;

  result = NULL;
  if (priv->printers != NULL)
    g_hash_table_foreach (priv->printers,
                          (GHFunc) printer_hash_to_sorted_active_list,
                          &result);

  if (!priv->printer_list_requested && priv->printers != NULL)
    {
      if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
	GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
      priv->printer_list_requested = TRUE;
    }
616

Matthias Clasen's avatar
Matthias Clasen committed
617
  return result;
Alexander Larsson's avatar
Alexander Larsson committed
618
}
619

Alexander Larsson's avatar
Alexander Larsson committed
620 621 622 623
gboolean
gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
{
  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
624

Alexander Larsson's avatar
Alexander Larsson committed
625
  return print_backend->priv->printer_list_done;
626 627 628
}

GtkPrinter *
Alexander Larsson's avatar
Alexander Larsson committed
629
gtk_print_backend_find_printer (GtkPrintBackend *backend,
Matthias Clasen's avatar
Matthias Clasen committed
630
                                const gchar     *printer_name)
631
{
Alexander Larsson's avatar
Alexander Larsson committed
632 633 634 635 636 637
  GtkPrintBackendPrivate *priv;
  GtkPrinter *printer;
  
  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);

  priv = backend->priv;
638

Alexander Larsson's avatar
Alexander Larsson committed
639 640 641 642
  if (priv->printers)
    printer = g_hash_table_lookup (priv->printers, printer_name);
  else
    printer = NULL;
643

Alexander Larsson's avatar
Alexander Larsson committed
644
  return printer;  
645 646 647
}

void
Matthias Clasen's avatar
Matthias Clasen committed
648 649
gtk_print_backend_print_stream (GtkPrintBackend        *backend,
                                GtkPrintJob            *job,
650
                                GIOChannel             *data_io,
651
                                GtkPrintJobCompleteFunc callback,
Matthias Clasen's avatar
Matthias Clasen committed
652
                                gpointer                user_data,
653
				GDestroyNotify          dnotify)
654
{
Alexander Larsson's avatar
Alexander Larsson committed
655 656 657 658
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));

  GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
						       job,
659
						       data_io,
Alexander Larsson's avatar
Alexander Larsson committed
660 661
						       callback,
						       user_data,
662
						       dnotify);
Alexander Larsson's avatar
Alexander Larsson committed
663 664
}

665
void 
666 667
gtk_print_backend_set_password (GtkPrintBackend  *backend,
                                gchar           **auth_info_required,
668 669
                                gchar           **auth_info,
                                gboolean          store_auth_info)
670 671 672 673
{
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));

  if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
674 675 676 677 678 679 680 681 682 683 684 685
    GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend,
                                                         auth_info_required,
                                                         auth_info,
                                                         store_auth_info);
}

static void
store_auth_info_toggled (GtkCheckButton *chkbtn,
                         gpointer        user_data)
{
  gboolean *data = (gboolean *) user_data;
  *data = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chkbtn));
686 687 688
}

static void
689 690
store_entry (GtkEntry  *entry,
             gpointer   user_data)
691
{
692
  gchar **data = (gchar **) user_data;
693

694
  if (*data != NULL)
695
    {
696 697
      memset (*data, 0, strlen (*data));
      g_free (*data);
698 699
    }

700
  *data = g_strdup (gtk_entry_get_text (entry));
701 702 703 704 705 706 707 708
}

static void
password_dialog_response (GtkWidget       *dialog,
                          gint             response_id,
                          GtkPrintBackend *backend)
{
  GtkPrintBackendPrivate *priv = backend->priv;
709
  gint i, auth_info_len;
710 711

  if (response_id == GTK_RESPONSE_OK)
712
    gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info, priv->store_auth_info);
713
  else
714
    gtk_print_backend_set_password (backend, priv->auth_info_required, NULL, FALSE);
715

716 717 718 719 720 721 722 723 724 725 726
  /* We want to clear the data before freeing it */
  auth_info_len = g_strv_length (priv->auth_info_required);
  for (i = 0; i < auth_info_len; i++)
    {
      if (priv->auth_info[i] != NULL)
        {
          memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
          g_free (priv->auth_info[i]);
          priv->auth_info[i] = NULL;
        }
    }
727

728 729
  g_clear_pointer (&priv->auth_info, g_free);
  g_clear_pointer (&priv->auth_info_required, g_strfreev);
730 731 732 733 734 735 736

  gtk_widget_destroy (dialog);

  g_object_unref (backend);
}

static void
737 738 739 740 741
request_password (GtkPrintBackend  *backend,
                  gpointer          auth_info_required,
                  gpointer          auth_info_default,
                  gpointer          auth_info_display,
                  gpointer          auth_info_visible,
742 743
                  const gchar      *prompt,
                  gboolean          can_store_auth_info)
744 745
{
  GtkPrintBackendPrivate *priv = backend->priv;
746
  GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry, *chkbtn;
747
  GtkWidget *focus = NULL;
748
  GtkWidget *content_area;
749
  gchar     *markup;
750 751 752 753 754 755 756 757 758
  gint       length;
  gint       i;
  gchar    **ai_required = (gchar **) auth_info_required;
  gchar    **ai_default = (gchar **) auth_info_default;
  gchar    **ai_display = (gchar **) auth_info_display;
  gboolean  *ai_visible = (gboolean *) auth_info_visible;

  priv->auth_info_required = g_strdupv (ai_required);
  length = g_strv_length (ai_required);
759
  priv->auth_info = g_new0 (gchar *, length + 1);
760
  priv->store_auth_info = FALSE;
761 762

  dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL, 
763 764
                                         _("_Cancel"), GTK_RESPONSE_CANCEL,
                                         _("_OK"), GTK_RESPONSE_OK,
765 766 767 768
                                         NULL);

  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);

769
  main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
770 771

  /* Left */
772
  icon = gtk_image_new_from_icon_name ("dialog-password-symbolic", GTK_ICON_SIZE_DIALOG);
773 774
  gtk_widget_set_halign (icon, GTK_ALIGN_CENTER);
  gtk_widget_set_valign (icon, GTK_ALIGN_START);
775
  g_object_set (icon, "margin", 6, NULL);
776 777

  /* Right */
778
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
779 780 781 782 783 784 785 786 787 788 789 790
  gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);

  /* Right - 1. */
  label = gtk_label_new (NULL);
  markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
  gtk_label_set_markup (GTK_LABEL (label), markup);
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
  gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
  g_free (markup);


  /* Packing */
791 792
  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  gtk_box_pack_start (GTK_BOX (content_area), main_box, TRUE, FALSE, 0);
793 794 795 796 797

  gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
  gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);

  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
798 799 800 801 802 803 804
  
  /* Right - 2. */
  for (i = 0; i < length; i++)
    {
      priv->auth_info[i] = g_strdup (ai_default[i]);
      if (ai_display[i] != NULL)
        {
805 806
          box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
          gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
807 808

          label = gtk_label_new (ai_display[i]);
809 810
          gtk_widget_set_halign (label, GTK_ALIGN_START);
          gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
811

812 813
          entry = gtk_entry_new ();
          focus = entry;
814

815 816
          if (ai_default[i] != NULL)
            gtk_entry_set_text (GTK_ENTRY (entry), ai_default[i]);
817

818 819
          gtk_entry_set_visibility (GTK_ENTRY (entry), ai_visible[i]);
          gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
820

821
          gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 6);
822

823 824
          gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
          gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
825

826 827 828 829
          g_signal_connect (entry, "changed",
                            G_CALLBACK (store_entry), &(priv->auth_info[i]));
        }
    }
830

831 832 833 834 835 836 837 838 839 840
  if (can_store_auth_info)
    {
      chkbtn = gtk_check_button_new_with_mnemonic (_("_Remember password"));
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chkbtn), FALSE);
      gtk_box_pack_start (GTK_BOX (vbox), chkbtn, FALSE, FALSE, 6);
      g_signal_connect (chkbtn, "toggled",
                        G_CALLBACK (store_auth_info_toggled),
                        &(priv->store_auth_info));
    }

841 842 843 844 845
  if (focus != NULL)
    {
      gtk_widget_grab_focus (focus);
      focus = NULL;
    }
846 847 848 849 850 851 852 853

  g_object_ref (backend);
  g_signal_connect (G_OBJECT (dialog), "response",
                    G_CALLBACK (password_dialog_response), backend);

  gtk_widget_show_all (dialog);
}

Alexander Larsson's avatar
Alexander Larsson committed
854 855 856 857
void
gtk_print_backend_destroy (GtkPrintBackend *print_backend)
{
  /* The lifecycle of print backends and printers are tied, such that
Matthias Clasen's avatar
Matthias Clasen committed
858 859 860 861 862
   * the backend owns the printers, but the printers also ref the backend.
   * This is so that if the app has a reference to a printer its backend
   * will be around. However, this results in a cycle, which we break
   * with this call, which causes the print backend to release its printers.
   */
Alexander Larsson's avatar
Alexander Larsson committed
863
  g_object_run_dispose (G_OBJECT (print_backend));
864
}