gtkprintbackend.c 15.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/* GTK - The GIMP Toolkit
 * 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
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

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

#include <gmodule.h>

#include "gtkintl.h"
#include "gtkmodules.h"
#include "gtkprivate.h"
#include "gtkprintbackend.h"
30
#include "gtkprinter-private.h"
31 32
#include "gtkalias.h"

Alexander Larsson's avatar
Alexander Larsson committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#define GTK_PRINT_BACKEND_GET_PRIVATE(o)  \
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendPrivate))

static void gtk_print_backend_dispose (GObject *object);

struct _GtkPrintBackendPrivate
{
  GHashTable *printers;
  guint printer_list_requested : 1;
  guint printer_list_done : 1;
};

enum {
  PRINTER_LIST_CHANGED,
  PRINTER_LIST_DONE,
  PRINTER_ADDED,
  PRINTER_REMOVED,
  PRINTER_STATUS_CHANGED,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

static GObjectClass *backend_parent_class;
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

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;
};

Matthias Clasen's avatar
Matthias Clasen committed
92
G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
#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)
    {
      g_warning (g_module_error());
      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))
    {
      g_warning (g_module_error());
      g_module_close (pb_module->library);
      
      return FALSE;
    }

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

  /* call the filesystems's init function to let it */
  /* 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
169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
  module_class->load = gtk_print_backend_module_load;
  module_class->unload = gtk_print_backend_module_unload;

  gobject_class->finalize = gtk_print_backend_module_finalize;
}

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;
}

195
static GtkPrintBackend *
Matthias Clasen's avatar
Matthias Clasen committed
196
_gtk_print_backend_create (const gchar *backend_name)
197 198
{
  GSList *l;
Matthias Clasen's avatar
Matthias Clasen committed
199 200
  gchar *module_path;
  gchar *full_name;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
  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);
230 231

	  /* Increase use-count so that we don't unload print backends.
Matthias Clasen's avatar
Matthias Clasen committed
232 233 234
	   * There is a problem with module unloading in the cups module,
	   * see cups_dispatch_watch_finalize for details. 
	   */
235
	  g_type_module_use (G_TYPE_MODULE (pb_module));
236 237 238 239 240 241 242 243 244
	}
      
      g_free (module_path);
    }

  return pb;
}

GList *
Matthias Clasen's avatar
Matthias Clasen committed
245
gtk_print_backend_load_modules (void)
246 247 248 249 250 251 252 253 254 255 256
{
  GList *result;
  GtkPrintBackend *backend;
  gchar *setting;
  gchar **backends;
  gint i;
  GtkSettings *settings;

  result = NULL;

  settings = gtk_settings_get_default ();
257 258 259 260
  if (settings)
    g_object_get (settings, "gtk-print-backends", &setting, NULL);
  else
    setting = g_strdup (GTK_PRINT_BACKENDS);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282

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

  for (i = 0; backends[i]; i++)
    {
      g_strchug (backends[i]);
      g_strchomp (backends[i]);
      backend = _gtk_print_backend_create (backends[i]);
      
      if (backend)
        result = g_list_append (result, backend);
    }

  g_strfreev (backends);
  g_free (setting);

  return result;
}

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

Matthias Clasen's avatar
Matthias Clasen committed
284
G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
Alexander Larsson's avatar
Alexander Larsson committed
285

286 287 288 289 290 291 292 293 294 295 296
static void                 fallback_printer_request_details       (GtkPrinter          *printer);
static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
								    GtkPrinterOptionSet *options);
static void                 fallback_printer_get_hard_margins      (GtkPrinter          *printer,
								    gdouble             *top,
								    gdouble             *bottom,
								    gdouble             *left,
								    gdouble             *right);
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);
297
  
Alexander Larsson's avatar
Alexander Larsson committed
298 299
static void
gtk_print_backend_class_init (GtkPrintBackendClass *class)
300
{
Alexander Larsson's avatar
Alexander Larsson committed
301 302
  GObjectClass *object_class;
  object_class = (GObjectClass *) class;
303

Alexander Larsson's avatar
Alexander Larsson committed
304 305 306 307
  backend_parent_class = g_type_class_peek_parent (class);
  
  object_class->dispose = gtk_print_backend_dispose;

308 309 310 311
  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;
312
  class->printer_get_default_page_size = fallback_printer_get_default_page_size;
313 314
  class->printer_get_capabilities = fallback_printer_get_capabilities;
  
Alexander Larsson's avatar
Alexander Larsson committed
315 316 317
  g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
  
  signals[PRINTER_LIST_CHANGED] =
Matthias Clasen's avatar
Matthias Clasen committed
318
    g_signal_new (I_("printer-list-changed"),
Alexander Larsson's avatar
Alexander Larsson committed
319 320 321 322 323 324 325
		  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
326
    g_signal_new (I_("printer-list-done"),
Alexander Larsson's avatar
Alexander Larsson committed
327 328 329 330 331 332 333
		    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
334
    g_signal_new (I_("printer-added"),
Alexander Larsson's avatar
Alexander Larsson committed
335 336 337 338 339 340 341
		  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
342
    g_signal_new (I_("printer-removed"),
Alexander Larsson's avatar
Alexander Larsson committed
343 344 345 346 347 348 349
		  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
350
    g_signal_new (I_("printer-status-changed"),
Alexander Larsson's avatar
Alexander Larsson committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
		  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);
}

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

  priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 

  priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
					  (GDestroyNotify) g_free,
					  (GDestroyNotify) g_object_unref);
}

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
381 382
   * we can break refcount cycles with gtk_print_backend_destroy 
   */
Alexander Larsson's avatar
Alexander Larsson committed
383
  if (priv->printers)
384
    {
Alexander Larsson's avatar
Alexander Larsson committed
385 386
      g_hash_table_destroy (priv->printers);
      priv->printers = NULL;
387 388
    }

Alexander Larsson's avatar
Alexander Larsson committed
389
  backend_parent_class->dispose (object);
390 391
}

Alexander Larsson's avatar
Alexander Larsson committed
392

393 394 395 396 397 398
static void
fallback_printer_request_details (GtkPrinter *printer)
{
}

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
399
fallback_printer_mark_conflicts (GtkPrinter          *printer,
400 401 402 403 404 405 406
				 GtkPrinterOptionSet *options)
{
  return FALSE;
}

static void
fallback_printer_get_hard_margins (GtkPrinter *printer,
Matthias Clasen's avatar
Matthias Clasen committed
407 408 409 410
				   gdouble    *top,
				   gdouble    *bottom,
				   gdouble    *left,
				   gdouble    *right)
411 412 413 414 415 416 417 418 419 420 421 422 423
{
  *top = 0;
  *bottom = 0;
  *left = 0;
  *right = 0;
}

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

424 425 426 427 428 429
static GtkPageSetup *
fallback_printer_get_default_page_size (GtkPrinter *printer)
{
  return NULL;
}

430 431 432 433 434 435 436
static GtkPrintCapabilities
fallback_printer_get_capabilities (GtkPrinter *printer)
{
  return 0;
}


437
static void
Matthias Clasen's avatar
Matthias Clasen committed
438 439 440
printer_hash_to_sorted_active_list (const gchar  *key,
                                    gpointer      value,
                                    GList       **out_list)
441
{
Alexander Larsson's avatar
Alexander Larsson committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
  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
458
			       GtkPrinter      *printer)
Alexander Larsson's avatar
Alexander Larsson committed
459 460
{
  GtkPrintBackendPrivate *priv;
461
  
Alexander Larsson's avatar
Alexander Larsson committed
462
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
463

Alexander Larsson's avatar
Alexander Larsson committed
464
  priv = backend->priv;
465

Alexander Larsson's avatar
Alexander Larsson committed
466 467 468 469 470 471 472 473 474 475
  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
476
				  GtkPrinter      *printer)
Alexander Larsson's avatar
Alexander Larsson committed
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
{
  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);
497 498 499
    }
}

Alexander Larsson's avatar
Alexander Larsson committed
500

501
GList *
Alexander Larsson's avatar
Alexander Larsson committed
502
gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
503
{
Alexander Larsson's avatar
Alexander Larsson committed
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
  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;
    }
  
Matthias Clasen's avatar
Matthias Clasen committed
524
  return result;
Alexander Larsson's avatar
Alexander Larsson committed
525
}
526

Alexander Larsson's avatar
Alexander Larsson committed
527 528 529 530
gboolean
gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
{
  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
531

Alexander Larsson's avatar
Alexander Larsson committed
532
  return print_backend->priv->printer_list_done;
533 534 535
}

GtkPrinter *
Alexander Larsson's avatar
Alexander Larsson committed
536
gtk_print_backend_find_printer (GtkPrintBackend *backend,
Matthias Clasen's avatar
Matthias Clasen committed
537
                                const gchar     *printer_name)
538
{
Alexander Larsson's avatar
Alexander Larsson committed
539 540 541 542 543 544
  GtkPrintBackendPrivate *priv;
  GtkPrinter *printer;
  
  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);

  priv = backend->priv;
545

Alexander Larsson's avatar
Alexander Larsson committed
546 547 548 549
  if (priv->printers)
    printer = g_hash_table_lookup (priv->printers, printer_name);
  else
    printer = NULL;
550

Alexander Larsson's avatar
Alexander Larsson committed
551
  return printer;  
552 553 554
}

void
Matthias Clasen's avatar
Matthias Clasen committed
555 556
gtk_print_backend_print_stream (GtkPrintBackend        *backend,
                                GtkPrintJob            *job,
557
                                GIOChannel             *data_io,
558
                                GtkPrintJobCompleteFunc callback,
Matthias Clasen's avatar
Matthias Clasen committed
559
                                gpointer                user_data,
560
				GDestroyNotify          dnotify)
561
{
Alexander Larsson's avatar
Alexander Larsson committed
562 563 564 565
  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));

  GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
						       job,
566
						       data_io,
Alexander Larsson's avatar
Alexander Larsson committed
567 568
						       callback,
						       user_data,
569
						       dnotify);
Alexander Larsson's avatar
Alexander Larsson committed
570 571 572 573 574 575
}

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
576 577 578 579 580
   * 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
581
  g_object_run_dispose (G_OBJECT (print_backend));
582 583 584 585
}

#define __GTK_PRINT_BACKEND_C__
#include "gtkaliasdef.c"