#include <gtk/gtkprintsettings.h>
#include <gtk/gtkprintbackend.h>
#include <gtk/gtkprinter.h>
+#include <gtk/gtkprinter-private.h>
#include "gtkprintbackendcups.h"
#include "gtkprintercups.h"
#include "gtkcupsutils.h"
+#include "gtkdebug.h"
typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
static GType print_backend_cups_type = 0;
typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
- GtkCupsResult *result,
- gpointer user_data);
+ GtkCupsResult *result,
+ gpointer user_data);
typedef enum
{
guint list_printers_poll;
guint list_printers_pending : 1;
- guint got_default_printer : 1;
+ guint got_default_printer : 1;
};
static GObjectClass *backend_parent_class;
GtkCupsRequest *request,
GtkPrintCupsResponseCallbackFunc callback,
gpointer user_data,
- GDestroyNotify notify,
- GError **err);
+ GDestroyNotify notify);
static void cups_printer_get_settings_from_options (GtkPrinter *printer,
GtkPrinterOptionSet *options,
GtkPrintSettings *settings);
GtkPrinterOptionSet *options);
static GtkPrinterOptionSet *cups_printer_get_options (GtkPrinter *printer,
GtkPrintSettings *settings,
- GtkPageSetup *page_setup);
+ GtkPageSetup *page_setup,
+ GtkPrintCapabilities capabilities);
static void cups_printer_prepare_for_print (GtkPrinter *printer,
GtkPrintJob *print_job,
GtkPrintSettings *settings,
double *bottom,
double *left,
double *right);
+static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer);
static void set_option_from_settings (GtkPrinterOption *option,
GtkPrintSettings *setting);
static void cups_begin_polling_info (GtkPrintBackendCups *print_backend,
static gboolean cups_job_info_poll_timeout (gpointer user_data);
static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend,
GtkPrintJob *job,
- gint data_fd,
+ GIOChannel *data_io,
GtkPrintJobCompleteFunc callback,
gpointer user_data,
GDestroyNotify dnotify);
static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer,
+ GtkPrintSettings *settings,
gdouble width,
gdouble height,
- gint cache_fd);
+ GIOChannel *cache_io);
static void
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkPrintBackendCups),
- 0, /* n_preallocs */
+ 0, /* n_preallocs */
(GInstanceInitFunc) gtk_print_backend_cups_init
};
G_MODULE_EXPORT void
pb_module_init (GTypeModule *module)
{
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Initializing the CUPS print backend module\n"));
+
gtk_print_backend_cups_register_type (module);
gtk_printer_cups_register_type (module);
}
* the filesystem using Unix/Linux API calls
*
* Return value: the new #GtkPrintBackendCups object
- **/
+ */
GtkPrintBackend *
gtk_print_backend_cups_new (void)
{
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
+
return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
}
backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
backend_class->printer_list_papers = cups_printer_list_papers;
backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
+ backend_class->printer_get_capabilities = cups_printer_get_capabilities;
}
static cairo_status_t
-_cairo_write_to_cups (void *cache_fd_as_pointer,
+_cairo_write_to_cups (void *closure,
const unsigned char *data,
unsigned int length)
{
- cairo_status_t result;
- gint cache_fd;
- cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
+ GIOChannel *io = (GIOChannel *)closure;
+ gsize written;
+ GError *error;
- result = CAIRO_STATUS_WRITE_ERROR;
-
- /* write out the buffer */
- if (write (cache_fd, data, length) != -1)
- result = CAIRO_STATUS_SUCCESS;
-
- return result;
-}
+ error = NULL;
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Writting %i byte chunk to temp file\n", length));
+
+ while (length > 0)
+ {
+ g_io_channel_write_chars (io, data, length, &written, &error);
+
+ if (error != NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Error writting to temp file, %s\n", error->message));
+
+ g_error_free (error);
+ return CAIRO_STATUS_WRITE_ERROR;
+ }
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
+
+ data += written;
+ length -= written;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
static cairo_surface_t *
-cups_printer_create_cairo_surface (GtkPrinter *printer,
- gdouble width,
- gdouble height,
- gint cache_fd)
+cups_printer_create_cairo_surface (GtkPrinter *printer,
+ GtkPrintSettings *settings,
+ gdouble width,
+ gdouble height,
+ GIOChannel *cache_io)
{
cairo_surface_t *surface;
/* TODO: check if it is a ps or pdf printer */
- surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
+ surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height);
/* TODO: DPI from settings object? */
- cairo_ps_surface_set_dpi (surface, 300, 300);
+ cairo_surface_set_fallback_resolution (surface, 300, 300);
return surface;
}
static void
cups_free_print_stream_data (CupsPrintStreamData *data)
{
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
if (data->dnotify)
data->dnotify (data->user_data);
g_object_unref (data->job);
static void
cups_print_cb (GtkPrintBackendCups *print_backend,
- GtkCupsResult *result,
- gpointer user_data)
+ GtkCupsResult *result,
+ gpointer user_data)
{
GError *error = NULL;
CupsPrintStreamData *ps = user_data;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
if (gtk_cups_result_is_error (result))
error = g_error_new_literal (gtk_print_error_quark (),
GTK_PRINT_ERROR_INTERNAL_ERROR,
ipp_attribute_t *attr; /* IPP job-id attribute */
ipp_t *response = gtk_cups_result_get_response (result);
- if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
+ if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
job_id = attr->values[0].integer;
-
- if (job_id == 0)
- gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
- else
- {
- gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
- cups_begin_polling_info (print_backend, ps->job, job_id);
- }
- }
+ if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
+ gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
+ else
+ {
+ gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
+ cups_begin_polling_info (print_backend, ps->job, job_id);
+ }
+ }
else
gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
}
static void
-add_cups_options (const char *key,
- const char *value,
- gpointer user_data)
+add_cups_options (const gchar *key,
+ const gchar *value,
+ gpointer user_data)
{
GtkCupsRequest *request = user_data;
if (strcmp (value, "gtk-ignore-value") == 0)
return;
- key = key + strlen("cups-");
+ key = key + strlen ("cups-");
gtk_cups_request_encode_option (request, key, value);
}
static void
-gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
- GtkPrintJob *job,
- gint data_fd,
- GtkPrintJobCompleteFunc callback,
- gpointer user_data,
- GDestroyNotify dnotify)
+gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
+ GtkPrintJob *job,
+ GIOChannel *data_io,
+ GtkPrintJobCompleteFunc callback,
+ gpointer user_data,
+ GDestroyNotify dnotify)
{
- GError *error;
GtkPrinterCups *cups_printer;
CupsPrintStreamData *ps;
GtkCupsRequest *request;
GtkPrintSettings *settings;
const gchar *title;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
settings = gtk_print_job_get_settings (job);
- error = NULL;
-
request = gtk_cups_request_new (NULL,
GTK_CUPS_POST,
IPP_PRINT_JOB,
- data_fd,
+ data_io,
NULL,
cups_printer->device_uri);
request,
(GtkPrintCupsResponseCallbackFunc) cups_print_cb,
ps,
- (GDestroyNotify)cups_free_print_stream_data,
- &error);
+ (GDestroyNotify)cups_free_print_stream_data);
}
static void
gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
{
- backend_cups->list_printers_poll = 0;
+ backend_cups->list_printers_poll = FALSE;
+ backend_cups->got_default_printer = FALSE;
backend_cups->list_printers_pending = FALSE;
cups_request_default_printer (backend_cups);
gtk_print_backend_cups_finalize (GObject *object)
{
GtkPrintBackendCups *backend_cups;
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: finalizing CUPS backend module\n"));
backend_cups = GTK_PRINT_BACKEND_CUPS (object);
{
GtkPrintBackendCups *backend_cups;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
backend_cups = GTK_PRINT_BACKEND_CUPS (object);
if (backend_cups->list_printers_poll > 0)
GtkCupsPollState poll_state;
gboolean result;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
dispatch = (GtkPrintCupsDispatchWatch *) source;
poll_state = gtk_cups_request_get_poll_state (dispatch->request);
static gboolean
cups_dispatch_watch_prepare (GSource *source,
- gint *timeout_)
+ gint *timeout_)
{
GtkPrintCupsDispatchWatch *dispatch;
dispatch = (GtkPrintCupsDispatchWatch *) source;
-
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
*timeout_ = -1;
return gtk_cups_request_read_write (dispatch->request);
}
static gboolean
-cups_dispatch_watch_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
+cups_dispatch_watch_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
{
GtkPrintCupsDispatchWatch *dispatch;
GtkPrintCupsResponseCallbackFunc ep_callback;
result = gtk_cups_request_get_result (dispatch->request);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
if (gtk_cups_result_is_error (result))
- g_warning (gtk_cups_result_get_error_string (result));
+ g_warning ("Error result: %s", gtk_cups_result_get_error_string (result));
ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
{
GtkPrintCupsDispatchWatch *dispatch;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
dispatch = (GtkPrintCupsDispatchWatch *) source;
gtk_cups_request_free (dispatch->request);
if (dispatch->backend)
{
/* We need to unref this at idle time, because it might be the
- last reference to this module causing the code to be
- unloaded (including this particular function!)
- */
- gtk_print_backend_unref_at_idle (GTK_PRINT_BACKEND (dispatch->backend));
+ * last reference to this module causing the code to be
+ * unloaded (including this particular function!)
+ * Update: Doing this at idle caused a deadlock taking the
+ * mainloop context lock while being in a GSource callout for
+ * multithreaded apps. So, for now we just disable unloading
+ * of print backends. See _gtk_print_backend_create for the
+ * disabling.
+ */
+ g_object_unref (dispatch->backend);
dispatch->backend = NULL;
}
static void
-cups_request_execute (GtkPrintBackendCups *print_backend,
- GtkCupsRequest *request,
- GtkPrintCupsResponseCallbackFunc callback,
- gpointer user_data,
- GDestroyNotify notify,
- GError **err)
+cups_request_execute (GtkPrintBackendCups *print_backend,
+ GtkCupsRequest *request,
+ GtkPrintCupsResponseCallbackFunc callback,
+ gpointer user_data,
+ GDestroyNotify notify)
{
GtkPrintCupsDispatchWatch *dispatch;
dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
sizeof (GtkPrintCupsDispatchWatch));
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
+
dispatch->request = request;
dispatch->backend = g_object_ref (print_backend);
dispatch->data_poll = NULL;
static void
cups_request_printer_info_cb (GtkPrintBackendCups *backend,
- GtkCupsResult *result,
- gpointer user_data)
+ GtkCupsResult *result,
+ gpointer user_data)
{
ipp_attribute_t *attr;
ipp_t *response;
printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
printer_name);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
+
if (!printer)
- return;
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
+ return;
+ }
cups_printer = GTK_PRINTER_CUPS (printer);
response = gtk_cups_result_get_response (result);
/* TODO: determine printer type and use correct icon */
- gtk_printer_set_icon_name (printer, "printer");
+ gtk_printer_set_icon_name (printer, "gtk-print");
state_msg = "";
loc = "";
static void
cups_request_printer_info (GtkPrintBackendCups *print_backend,
- const gchar *printer_name)
+ const gchar *printer_name)
{
- GError *error;
GtkCupsRequest *request;
gchar *printer_uri;
static const char * const pattrs[] = /* Attributes we're interested in */
"queued-job-count"
};
- error = NULL;
-
request = gtk_cups_request_new (NULL,
GTK_CUPS_POST,
IPP_GET_PRINTER_ATTRIBUTES,
- 0,
+ NULL,
NULL,
NULL);
gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, printer_uri);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
+
g_free (printer_uri);
gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
g_strdup (printer_name),
- (GDestroyNotify) g_free,
- &error);
-
+ (GDestroyNotify) g_free);
}
} CupsJobPollData;
static void
-job_object_died (gpointer user_data,
+job_object_died (gpointer user_data,
GObject *where_the_object_was)
{
CupsJobPollData *data = user_data;
static void
cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
- GtkCupsResult *result,
- gpointer user_data)
+ GtkCupsResult *result,
+ gpointer user_data)
{
CupsJobPollData *data = user_data;
ipp_attribute_t *attr;
static void
cups_request_job_info (CupsJobPollData *data)
{
- GError *error;
GtkCupsRequest *request;
gchar *printer_uri;
-
- error = NULL;
request = gtk_cups_request_new (NULL,
GTK_CUPS_POST,
IPP_GET_JOB_ATTRIBUTES,
- 0,
+ NULL,
NULL,
NULL);
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
data,
- NULL,
- &error);
+ NULL);
}
static gboolean
static void
cups_begin_polling_info (GtkPrintBackendCups *print_backend,
- GtkPrintJob *job,
- int job_id)
+ GtkPrintJob *job,
+ gint job_id)
{
CupsJobPollData *data;
}
static void
-mark_printer_inactive (GtkPrinter *printer,
+mark_printer_inactive (GtkPrinter *printer,
GtkPrintBackend *backend)
{
gtk_printer_set_is_active (printer, FALSE);
- g_signal_emit_by_name (backend,
- "printer-removed", printer);
+ g_signal_emit_by_name (backend, "printer-removed", printer);
}
static gint
-find_printer (GtkPrinter *printer, const char *find_name)
+find_printer (GtkPrinter *printer,
+ const gchar *find_name)
{
- const char *printer_name;
+ const gchar *printer_name;
printer_name = gtk_printer_get_name (printer);
return g_ascii_strcasecmp (printer_name, find_name);
static void
cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
- GtkCupsResult *result,
- gpointer user_data)
+ GtkCupsResult *result,
+ gpointer user_data)
{
+ GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
ipp_attribute_t *attr;
ipp_t *response;
gboolean list_has_changed;
list_has_changed = FALSE;
- g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
cups_backend->list_printers_pending = FALSE;
if (gtk_cups_result_is_error (result))
{
g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
- return;
+
+ goto done;
}
- /* gether the names of the printers in the current queue
- so we may check to see if they were removed */
- removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
+ /* Gather the names of the printers in the current queue
+ * so we may check to see if they were removed
+ */
+ removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
response = gtk_cups_result_get_response (result);
-
for (attr = response->attrs; attr != NULL; attr = attr->next)
{
GtkPrinter *printer;
const gchar *printer_name;
- const char *printer_uri;
- const char *member_uris;
+ const gchar *printer_uri;
+ const gchar *member_uris;
GList *node;
- /*
- * Skip leading attributes until we hit a printer...
- */
+ /* Skip leading attributes until we hit a printer...
+ */
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
member_uris = NULL;
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
{
- if (!strcmp(attr->name, "printer-name") &&
+ if (!strcmp (attr->name, "printer-name") &&
attr->value_tag == IPP_TAG_NAME)
printer_name = attr->values[0].string.text;
- else if (!strcmp(attr->name, "printer-uri-supported") &&
+ else if (!strcmp (attr->name, "printer-uri-supported") &&
attr->value_tag == IPP_TAG_URI)
printer_uri = attr->values[0].string.text;
- else if (!strcmp(attr->name, "member-uris") &&
+ else if (!strcmp (attr->name, "member-uris") &&
attr->value_tag == IPP_TAG_URI)
member_uris = attr->values[0].string.text;
+ else
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Attribute %s ignored", attr->name));
+ }
attr = attr->next;
}
node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
- printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
+ printer = gtk_print_backend_find_printer (backend, printer_name);
if (!printer)
{
GtkPrinterCups *cups_printer;
- char uri[HTTP_MAX_URI], /* Printer URI */
- method[HTTP_MAX_URI], /* Method/scheme name */
- username[HTTP_MAX_URI], /* Username:password */
- hostname[HTTP_MAX_URI], /* Hostname */
- resource[HTTP_MAX_URI]; /* Resource name */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ char method[HTTP_MAX_URI]; /* Method/scheme name */
+ char username[HTTP_MAX_URI]; /* Username:password */
+ char hostname[HTTP_MAX_URI]; /* Hostname */
+ char resource[HTTP_MAX_URI]; /* Resource name */
int port; /* Port number */
list_has_changed = TRUE;
- cups_printer = gtk_printer_cups_new (printer_name,
- GTK_PRINT_BACKEND (cups_backend));
+ cups_printer = gtk_printer_cups_new (printer_name, backend);
cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
+ /* Check to see if we are looking at a class */
if (member_uris)
{
cups_printer->printer_uri = g_strdup (member_uris);
+ /* TODO if member_uris is a class we need to recursivly find a printer */
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
}
else
- cups_printer->printer_uri = g_strdup (printer_uri);
+ {
+ cups_printer->printer_uri = g_strdup (printer_uri);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Found printer %s\n", printer_uri));
+ }
#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
resource);
#endif
- gethostname(uri, sizeof(uri));
- if (strcasecmp(uri, hostname) == 0)
- strcpy(hostname, "localhost");
+ if (!strncmp (resource, "/printers/", 10))
+ {
+ cups_printer->ppd_name = g_strdup (resource + 10);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, printer_name));
+ }
+
+ gethostname (uri, sizeof(uri));
+ if (strcasecmp (uri, hostname) == 0)
+ strcpy (hostname, "localhost");
cups_printer->hostname = g_strdup (hostname);
cups_printer->port = port;
gtk_printer_set_is_default (printer, TRUE);
- gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
+ gtk_print_backend_add_printer (backend, printer);
}
else
g_object_ref (printer);
if (gtk_printer_is_new (printer))
{
- g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
- "printer-added",
- printer);
+ g_signal_emit_by_name (backend, "printer-added", printer);
gtk_printer_set_is_new (printer, FALSE);
}
as inactive if it is in the list, emitting a printer_removed signal */
if (removed_printer_checklist != NULL)
{
- g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
- GTK_PRINT_BACKEND (cups_backend));
+ g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
g_list_free (removed_printer_checklist);
list_has_changed = TRUE;
}
+done:
if (list_has_changed)
- g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
+ g_signal_emit_by_name (backend, "printer-list-changed");
- gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
+ gtk_print_backend_set_list_done (backend);
}
static gboolean
cups_request_printer_list (GtkPrintBackendCups *cups_backend)
{
- GError *error;
GtkCupsRequest *request;
static const char * const pattrs[] = /* Attributes we're interested in */
{
!cups_backend->got_default_printer)
return TRUE;
- cups_backend->list_printers_pending = TRUE;
+ g_object_ref (cups_backend);
+ GDK_THREADS_LEAVE ();
- error = NULL;
+ cups_backend->list_printers_pending = TRUE;
request = gtk_cups_request_new (NULL,
GTK_CUPS_POST,
CUPS_GET_PRINTERS,
- 0,
+ NULL,
NULL,
NULL);
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
request,
- NULL,
- &error);
-
+ NULL);
+ GDK_THREADS_ENTER ();
+ g_object_unref (cups_backend);
return TRUE;
}
if (cups_backend->list_printers_poll == 0)
{
cups_request_printer_list (cups_backend);
- cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
+ cups_backend->list_printers_poll = gdk_threads_add_timeout (3000,
(GSourceFunc) cups_request_printer_list,
backend);
}
typedef struct {
GtkPrinterCups *printer;
- gint ppd_fd;
- gchar *ppd_filename;
+ GIOChannel *ppd_io;
} GetPPDData;
static void
get_ppd_data_free (GetPPDData *data)
{
- close (data->ppd_fd);
- unlink (data->ppd_filename);
- g_free (data->ppd_filename);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
+ g_io_channel_unref (data->ppd_io);
g_object_unref (data->printer);
g_free (data);
}
static void
cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
- GtkCupsResult *result,
- GetPPDData *data)
+ GtkCupsResult *result,
+ GetPPDData *data)
{
ipp_t *response;
GtkPrinter *printer;
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
printer = GTK_PRINTER (data->printer);
GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
if (gtk_cups_result_is_error (result))
{
- g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+ g_signal_emit_by_name (printer, "details-acquired", FALSE);
return;
}
response = gtk_cups_result_get_response (result);
- data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
+ /* let ppdOpenFd take over the ownership of the open file */
+ g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
+ data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
+
gtk_printer_set_has_details (printer, TRUE);
- g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
+ g_signal_emit_by_name (printer, "details-acquired", TRUE);
}
static void
-cups_request_ppd (GtkPrinter *printer)
+cups_request_ppd (GtkPrinter *printer)
{
GError *error;
GtkPrintBackend *print_backend;
GtkPrinterCups *cups_printer;
GtkCupsRequest *request;
+ char *ppd_filename;
gchar *resource;
http_t *http;
GetPPDData *data;
-
+ int fd;
+
cups_printer = GTK_PRINTER_CUPS (printer);
error = NULL;
- http = httpConnectEncrypt(cups_printer->hostname,
- cups_printer->port,
- cupsEncryption());
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
+ /* FIXME this can return NULL! */
+ http = httpConnectEncrypt (cups_printer->hostname,
+ cups_printer->port,
+ cupsEncryption ());
data = g_new0 (GetPPDData, 1);
- data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
- &data->ppd_filename,
- &error);
+ fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
+ &ppd_filename,
+ &error);
+
+#ifdef G_ENABLE_DEBUG
+ /* If we are debugging printing don't delete the tmp files */
+ if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
+ unlink (ppd_filename);
+#else
+ unlink (ppd_filename);
+#endif /* G_ENABLE_DEBUG */
if (error != NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
httpClose (http);
+ g_free (ppd_filename);
g_free (data);
- g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+ g_signal_emit_by_name (printer, "details-acquired", FALSE);
return;
}
- fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
+ fchmod (fd, S_IRUSR | S_IWUSR);
+ data->ppd_io = g_io_channel_unix_new (fd);
+ g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
+ g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
data->printer = g_object_ref (printer);
- resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
+ resource = g_strdup_printf ("/printers/%s.ppd",
+ gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS(printer)));
request = gtk_cups_request_new (http,
GTK_CUPS_GET,
0,
- data->ppd_fd,
+ data->ppd_io,
cups_printer->hostname,
resource);
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
+
g_free (resource);
-
+ g_free (ppd_filename);
+
cups_printer->reading_ppd = TRUE;
print_backend = gtk_printer_get_backend (printer);
-
+
cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
data,
- (GDestroyNotify)get_ppd_data_free,
- &error);
+ (GDestroyNotify)get_ppd_data_free);
}
static void
cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
- GtkCupsResult *result,
- gpointer user_data)
+ GtkCupsResult *result,
+ gpointer user_data)
{
ipp_t *response;
ipp_attribute_t *attr;
response = gtk_cups_result_get_response (result);
- if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
+ if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
print_backend->default_printer = g_strdup (attr->values[0].string.text);
print_backend->got_default_printer = TRUE;
- /* Make sure to kick off get_printers if we are polling it, as we could
- have blocked this reading the default printer */
+ /* Make sure to kick off get_printers if we are polling it,
+ * as we could have blocked this reading the default printer
+ */
if (print_backend->list_printers_poll != 0)
cups_request_printer_list (print_backend);
}
static void
cups_request_default_printer (GtkPrintBackendCups *print_backend)
{
- GError *error;
GtkCupsRequest *request;
const char *str;
- error = NULL;
-
- if ((str = getenv("LPDEST")) != NULL)
+ if ((str = g_getenv ("LPDEST")) != NULL)
{
print_backend->default_printer = g_strdup (str);
print_backend->got_default_printer = TRUE;
return;
}
- else if ((str = getenv("PRINTER")) != NULL &&
- strcmp(str, "lp") != 0)
+ else if ((str = g_getenv ("PRINTER")) != NULL &&
+ strcmp (str, "lp") != 0)
{
print_backend->default_printer = g_strdup (str);
print_backend->got_default_printer = TRUE;
request = gtk_cups_request_new (NULL,
GTK_CUPS_POST,
CUPS_GET_DEFAULT,
- 0,
+ NULL,
NULL,
NULL);
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
g_object_ref (print_backend),
- g_object_unref,
- &error);
+ g_object_unref);
}
-
static void
cups_printer_request_details (GtkPrinter *printer)
{
}
static char *
-ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
+ppd_text_to_utf8 (ppd_file_t *ppd_file,
+ const char *text)
{
const char *encoding = NULL;
char *res;
};
static char *
-get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
+get_option_text (ppd_file_t *ppd_file,
+ ppd_option_t *option)
{
int i;
char *utf8;
}
static char *
-get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
+get_choice_text (ppd_file_t *ppd_file,
+ ppd_choice_t *choice)
{
int i;
ppd_option_t *option = choice->option;
}
static gboolean
-group_has_option (ppd_group_t *group, ppd_option_t *option)
+group_has_option (ppd_group_t *group,
+ ppd_option_t *option)
{
int i;
strcasecmp (value, "False") == 0);
}
+static char *
+ppd_group_name (ppd_group_t *group)
+{
+#if CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR == 1 && CUPS_VERSION_PATCH >= 18)
+ return group->name;
+#else
+ return group->text;
+#endif
+}
+
static int
-available_choices (ppd_file_t *ppd,
- ppd_option_t *option,
+available_choices (ppd_file_t *ppd,
+ ppd_option_t *option,
ppd_choice_t ***available,
- gboolean keep_if_only_one_option)
+ gboolean keep_if_only_one_option)
{
ppd_option_t *other_option;
int i, j;
- char *conflicts;
+ gchar *conflicts;
ppd_const_t *constraint;
const char *choice, *other_choice;
ppd_option_t *option1, *option2;
installed_options = NULL;
for (i = 0; i < ppd->num_groups; i++)
{
- if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
+ char *name;
+
+ name = ppd_group_name (&ppd->groups[i]);
+ if (strcmp (name, "InstallableOptions") == 0)
{
installed_options = &ppd->groups[i];
break;
/* Some ppds don't have a "use printer default" option for
- InputSlot. This means you always have to select a particular slot,
- and you can't auto-pick source based on the paper size. To support
- this we always add an auto option if there isn't one already. If
- the user chooses the generated option we don't send any InputSlot
- value when printing. The way we detect existing auto-cases is based
- on feedback from Michael Sweet of cups fame.
- */
+ * InputSlot. This means you always have to select a particular slot,
+ * and you can't auto-pick source based on the paper size. To support
+ * this we always add an auto option if there isn't one already. If
+ * the user chooses the generated option we don't send any InputSlot
+ * value when printing. The way we detect existing auto-cases is based
+ * on feedback from Michael Sweet of cups fame.
+ */
add_auto = 0;
if (strcmp (option->keyword, "InputSlot") == 0)
{
}
static GtkPrinterOption *
-create_pickone_option (ppd_file_t *ppd_file,
+create_pickone_option (ppd_file_t *ppd_file,
ppd_option_t *ppd_option,
- const char *gtk_name)
+ const gchar *gtk_name)
{
GtkPrinterOption *option;
ppd_choice_t **available;
char *label;
int n_choices;
int i;
+#ifdef HAVE_CUPS_API_1_2
+ ppd_coption_t *coption;
+#endif
g_assert (ppd_option->ui == PPD_UI_PICKONE);
n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
if (n_choices > 0)
{
+
+ /* right now only support one parameter per custom option
+ * if more than one print warning and only offer the default choices
+ */
+
label = get_option_text (ppd_file, ppd_option);
- option = gtk_printer_option_new (gtk_name, label,
- GTK_PRINTER_OPTION_TYPE_PICKONE);
+
+#ifdef HAVE_CUPS_API_1_2
+ coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
+
+ if (coption)
+ {
+ ppd_cparam_t *cparam;
+
+ cparam = ppdFirstCustomParam (coption);
+
+ if (ppdNextCustomParam (coption) == NULL)
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_INT:
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
+ break;
+ case PPD_CUSTOM_PASSCODE:
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
+ break;
+ case PPD_CUSTOM_PASSWORD:
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
+ break;
+ case PPD_CUSTOM_REAL:
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
+ break;
+ case PPD_CUSTOM_STRING:
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
+ break;
+ case PPD_CUSTOM_POINTS:
+ g_warning ("Not Supported: PPD Custom Points Option");
+ break;
+ case PPD_CUSTOM_CURVE:
+ g_warning ("Not Supported: PPD Custom Curve Option");
+ break;
+ case PPD_CUSTOM_INVCURVE:
+ g_warning ("Not Supported: PPD Custom Inverse Curve Option");
+ break;
+ }
+ }
+ else
+ g_warning ("Not Supported: PPD Custom Option has more than one parameter");
+ }
+#endif /* HAVE_CUPS_API_1_2 */
+
+ if (!option)
+ option = gtk_printer_option_new (gtk_name, label,
+ GTK_PRINTER_OPTION_TYPE_PICKONE);
g_free (label);
gtk_printer_option_allocate_choices (option, n_choices);
}
static GtkPrinterOption *
-create_boolean_option (ppd_file_t *ppd_file,
+create_boolean_option (ppd_file_t *ppd_file,
ppd_option_t *ppd_option,
- const char *gtk_name)
+ const gchar *gtk_name)
{
GtkPrinterOption *option;
ppd_choice_t **available;
{
label = get_option_text (ppd_file, ppd_option);
option = gtk_printer_option_new (gtk_name, label,
- GTK_PRINTER_OPTION_TYPE_BOOLEAN);
+ GTK_PRINTER_OPTION_TYPE_BOOLEAN);
g_free (label);
gtk_printer_option_allocate_choices (option, 2);
option->choices[0] = g_strdup ("True");
option->choices_display[0] = g_strdup ("True");
- option->choices[1] = g_strdup ("True");
- option->choices_display[1] = g_strdup ("True");
+ option->choices[1] = g_strdup ("False");
+ option->choices_display[1] = g_strdup ("False");
gtk_printer_option_set (option, ppd_option->defchoice);
}
return option;
}
-static char *
-get_option_name (const char *keyword)
+static gchar *
+get_option_name (const gchar *keyword)
{
int i;
}
static int
-strptr_cmp (const void *a, const void *b)
+strptr_cmp (const void *a,
+ const void *b)
{
char **aa = (char **)a;
char **bb = (char **)b;
static gboolean
-string_in_table (char *str, const char *table[], int table_len)
+string_in_table (gchar *str,
+ const gchar *table[],
+ gint table_len)
{
return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
}
static void
handle_option (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_option_t *ppd_option,
- ppd_group_t *toplevel_group,
- GtkPrintSettings *settings)
+ ppd_file_t *ppd_file,
+ ppd_option_t *ppd_option,
+ ppd_group_t *toplevel_group,
+ GtkPrintSettings *settings)
{
GtkPrinterOption *option;
char *name;
if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
return;
-
+
name = get_option_name (ppd_option->keyword);
option = NULL;
if (option)
{
- if (STRING_IN_TABLE (toplevel_group->name,
+ char *name;
+
+ name = ppd_group_name (toplevel_group);
+ if (STRING_IN_TABLE (name,
color_group_whitelist) ||
STRING_IN_TABLE (ppd_option->keyword,
color_option_whitelist))
{
option->group = g_strdup ("ColorPage");
}
- else if (STRING_IN_TABLE (toplevel_group->name,
+ else if (STRING_IN_TABLE (name,
image_quality_group_whitelist) ||
STRING_IN_TABLE (ppd_option->keyword,
image_quality_option_whitelist))
{
option->group = g_strdup ("ImageQualityPage");
}
- else if (STRING_IN_TABLE (toplevel_group->name,
+ else if (STRING_IN_TABLE (name,
finishing_group_whitelist) ||
STRING_IN_TABLE (ppd_option->keyword,
finishing_option_whitelist))
static void
handle_group (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_group_t *group,
- ppd_group_t *toplevel_group,
- GtkPrintSettings *settings)
+ ppd_file_t *ppd_file,
+ ppd_group_t *group,
+ ppd_group_t *toplevel_group,
+ GtkPrintSettings *settings)
{
- int i;
-
+ gint i;
+ gchar *name;
+
/* Ignore installable options */
- if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
+ name = ppd_group_name (toplevel_group);
+ if (strcmp (name, "InstallableOptions") == 0)
return;
for (i = 0; i < group->num_options; i++)
}
static GtkPrinterOptionSet *
-cups_printer_get_options (GtkPrinter *printer,
- GtkPrintSettings *settings,
- GtkPageSetup *page_setup)
+cups_printer_get_options (GtkPrinter *printer,
+ GtkPrintSettings *settings,
+ GtkPageSetup *page_setup,
+ GtkPrintCapabilities capabilities)
{
GtkPrinterOptionSet *set;
GtkPrinterOption *option;
{
GtkPaperSize *paper_size;
ppd_option_t *option;
-
+ const gchar *ppd_name;
+
ppdMarkDefaults (ppd_file);
paper_size = gtk_page_setup_get_paper_size (page_setup);
- option = ppdFindOption(ppd_file, "PageSize");
- strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
- PPD_MAX_NAME);
+ option = ppdFindOption (ppd_file, "PageSize");
+ ppd_name = gtk_paper_size_get_ppd_name (paper_size);
+
+ if (ppd_name)
+ strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
+ else
+ {
+ gchar *custom_name;
+
+ custom_name = g_strdup_printf (_("Custom.%2fx%.2f"),
+ gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
+ gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
+ strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
+ g_free (custom_name);
+ }
for (i = 0; i < ppd_file->num_groups; i++)
handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
static void
mark_option_from_set (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_option_t *ppd_option)
+ ppd_file_t *ppd_file,
+ ppd_option_t *ppd_option)
{
GtkPrinterOption *option;
char *name = get_option_name (ppd_option->keyword);
static void
mark_group_from_set (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_group_t *group)
+ ppd_file_t *ppd_file,
+ ppd_group_t *group)
{
int i;
static void
set_conflicts_from_option (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_option_t *ppd_option)
+ ppd_file_t *ppd_file,
+ ppd_option_t *ppd_option)
{
GtkPrinterOption *option;
char *name;
+
if (ppd_option->conflicted)
{
name = get_option_name (ppd_option->keyword);
static void
set_conflicts_from_group (GtkPrinterOptionSet *set,
- ppd_file_t *ppd_file,
- ppd_group_t *group)
+ ppd_file_t *ppd_file,
+ ppd_group_t *group)
{
int i;
}
static gboolean
-cups_printer_mark_conflicts (GtkPrinter *printer,
- GtkPrinterOptionSet *options)
+cups_printer_mark_conflicts (GtkPrinter *printer,
+ GtkPrinterOptionSet *options)
{
ppd_file_t *ppd_file;
int num_conflicts;
} NameMapping;
static void
-map_settings_to_option (GtkPrinterOption *option,
- const NameMapping table[],
- int n_elements,
- GtkPrintSettings *settings,
- const char *standard_name,
- const char *cups_name)
+map_settings_to_option (GtkPrinterOption *option,
+ const NameMapping table[],
+ gint n_elements,
+ GtkPrintSettings *settings,
+ const gchar *standard_name,
+ const gchar *cups_name)
{
int i;
char *name;
const char *standard_value;
/* If the cups-specific setting is set, always use that */
-
name = g_strdup_printf ("cups-%s", cups_name);
cups_value = gtk_print_settings_get (settings, name);
g_free (name);
- if (cups_value != NULL) {
- gtk_printer_option_set (option, cups_value);
- return;
- }
+ if (cups_value != NULL)
+ {
+ gtk_printer_option_set (option, cups_value);
+ return;
+ }
/* Otherwise we try to convert from the general setting */
standard_value = gtk_print_settings_get (settings, standard_name);
}
static void
-map_option_to_settings (const char *value,
- const NameMapping table[],
- int n_elements,
- GtkPrintSettings *settings,
- const char *standard_name,
- const char *cups_name)
+map_option_to_settings (const gchar *value,
+ const NameMapping table[],
+ gint n_elements,
+ GtkPrintSettings *settings,
+ const gchar *standard_name,
+ const gchar *cups_name)
{
int i;
char *name;
}
static void
-foreach_option_get_settings (GtkPrinterOption *option,
+foreach_option_get_settings (GtkPrinterOption *option,
gpointer user_data)
{
struct OptionData *data = user_data;
}
static void
-cups_printer_get_settings_from_options (GtkPrinter *printer,
+cups_printer_get_settings_from_options (GtkPrinter *printer,
GtkPrinterOptionSet *options,
- GtkPrintSettings *settings)
+ GtkPrintSettings *settings)
{
struct OptionData data;
const char *print_at, *print_at_time;
}
static void
-cups_printer_prepare_for_print (GtkPrinter *printer,
- GtkPrintJob *print_job,
+cups_printer_prepare_for_print (GtkPrinter *printer,
+ GtkPrintJob *print_job,
GtkPrintSettings *settings,
- GtkPageSetup *page_setup)
+ GtkPageSetup *page_setup)
{
GtkPageSet page_set;
GtkPaperSize *paper_size;
size = &ppd_file->sizes[i];
display_name = NULL;
- option = ppdFindOption(ppd_file, "PageSize");
+ option = ppdFindOption (ppd_file, "PageSize");
if (option)
{
- choice = ppdFindChoice(option, size->name);
+ choice = ppdFindChoice (option, size->name);
if (choice)
display_name = ppd_text_to_utf8 (ppd_file, choice->text);
}
static void
cups_printer_get_hard_margins (GtkPrinter *printer,
- double *top,
- double *bottom,
- double *left,
- double *right)
+ gdouble *top,
+ gdouble *bottom,
+ gdouble *left,
+ gdouble *right)
{
ppd_file_t *ppd_file;
*right = ppd_file->custom_margins[2];
*top = ppd_file->custom_margins[3];
}
+
+static GtkPrintCapabilities
+cups_printer_get_capabilities (GtkPrinter *printer)
+{
+ return
+ GTK_PRINT_CAPABILITY_COPIES |
+ GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE;
+}