2006-04-21 15:09:32 +00:00
/* GTK - The GIMP Toolkit
* gtkprintbackendcups . h : Default implementation of GtkPrintBackend
* for the Common Unix Print System ( CUPS )
* 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 <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <stdlib.h>
# include <config.h>
# include <cups/cups.h>
# include <cups/language.h>
# include <cups/http.h>
# include <cups/ipp.h>
# include <errno.h>
# include <cairo.h>
# include <cairo-pdf.h>
# include <cairo-ps.h>
# include <glib/gi18n-lib.h>
# include <gmodule.h>
# include <gtk/gtkprintoperation.h>
# include <gtk/gtkprintsettings.h>
# include <gtk/gtkprintbackend.h>
# include <gtk/gtkprinter.h>
2006-06-16 05:08:14 +00:00
# include <gtk/gtkprinter-private.h>
2006-04-21 15:09:32 +00:00
# include "gtkprintbackendcups.h"
# include "gtkprintercups.h"
# include "gtkcupsutils.h"
2006-06-21 18:16:58 +00:00
# include "gtkdebug.h"
2006-04-21 15:09:32 +00:00
2006-10-03 15:05:05 +00:00
2006-04-21 15:09:32 +00:00
typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass ;
# define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
# define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
# define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
# define _CUPS_MAX_ATTEMPTS 10
# define _CUPS_MAX_CHUNK_SIZE 8192
# define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
2006-05-10 00:42:23 +00:00
# define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
2006-04-21 15:09:32 +00:00
static GType print_backend_cups_type = 0 ;
typedef void ( * GtkPrintCupsResponseCallbackFunc ) ( GtkPrintBackend * print_backend ,
2006-06-21 05:08:43 +00:00
GtkCupsResult * result ,
gpointer user_data ) ;
2006-04-21 15:09:32 +00:00
typedef enum
{
DISPATCH_SETUP ,
DISPATCH_REQUEST ,
DISPATCH_SEND ,
DISPATCH_CHECK ,
DISPATCH_READ ,
DISPATCH_ERROR
} GtkPrintCupsDispatchState ;
typedef struct
{
GSource source ;
http_t * http ;
GtkCupsRequest * request ;
GPollFD * data_poll ;
GtkPrintBackendCups * backend ;
} GtkPrintCupsDispatchWatch ;
struct _GtkPrintBackendCupsClass
{
2006-05-04 13:43:32 +00:00
GtkPrintBackendClass parent_class ;
2006-04-21 15:09:32 +00:00
} ;
struct _GtkPrintBackendCups
{
2006-05-04 13:43:32 +00:00
GtkPrintBackend parent_instance ;
2006-04-21 15:09:32 +00:00
char * default_printer ;
guint list_printers_poll ;
guint list_printers_pending : 1 ;
2006-06-21 05:08:43 +00:00
guint got_default_printer : 1 ;
2006-04-21 15:09:32 +00:00
} ;
static GObjectClass * backend_parent_class ;
static void gtk_print_backend_cups_class_init ( GtkPrintBackendCupsClass * class ) ;
static void gtk_print_backend_cups_init ( GtkPrintBackendCups * impl ) ;
static void gtk_print_backend_cups_finalize ( GObject * object ) ;
2006-05-04 13:43:32 +00:00
static void gtk_print_backend_cups_dispose ( GObject * object ) ;
static void cups_get_printer_list ( GtkPrintBackend * print_backend ) ;
2006-04-21 15:09:32 +00:00
static void cups_request_execute ( GtkPrintBackendCups * print_backend ,
GtkCupsRequest * request ,
GtkPrintCupsResponseCallbackFunc callback ,
gpointer user_data ,
2006-06-21 05:08:43 +00:00
GDestroyNotify notify ) ;
2006-04-21 15:09:32 +00:00
static void cups_printer_get_settings_from_options ( GtkPrinter * printer ,
GtkPrinterOptionSet * options ,
GtkPrintSettings * settings ) ;
static gboolean cups_printer_mark_conflicts ( GtkPrinter * printer ,
GtkPrinterOptionSet * options ) ;
static GtkPrinterOptionSet * cups_printer_get_options ( GtkPrinter * printer ,
GtkPrintSettings * settings ,
2006-06-21 05:56:14 +00:00
GtkPageSetup * page_setup ,
GtkPrintCapabilities capabilities ) ;
2006-04-21 15:09:32 +00:00
static void cups_printer_prepare_for_print ( GtkPrinter * printer ,
GtkPrintJob * print_job ,
GtkPrintSettings * settings ,
GtkPageSetup * page_setup ) ;
static GList * cups_printer_list_papers ( GtkPrinter * printer ) ;
static void cups_printer_request_details ( GtkPrinter * printer ) ;
static void cups_request_default_printer ( GtkPrintBackendCups * print_backend ) ;
static void cups_request_ppd ( GtkPrinter * printer ) ;
static void cups_printer_get_hard_margins ( GtkPrinter * printer ,
double * top ,
double * bottom ,
double * left ,
double * right ) ;
2006-05-24 10:50:57 +00:00
static GtkPrintCapabilities cups_printer_get_capabilities ( GtkPrinter * printer ) ;
2006-04-21 15:09:32 +00:00
static void set_option_from_settings ( GtkPrinterOption * option ,
GtkPrintSettings * setting ) ;
static void cups_begin_polling_info ( GtkPrintBackendCups * print_backend ,
GtkPrintJob * job ,
int job_id ) ;
static gboolean cups_job_info_poll_timeout ( gpointer user_data ) ;
2006-05-04 13:43:32 +00:00
static void gtk_print_backend_cups_print_stream ( GtkPrintBackend * backend ,
GtkPrintJob * job ,
2006-06-21 18:16:58 +00:00
GIOChannel * data_io ,
2006-05-04 13:43:32 +00:00
GtkPrintJobCompleteFunc callback ,
gpointer user_data ,
2006-06-21 18:16:58 +00:00
GDestroyNotify dnotify ) ;
2006-05-04 13:43:32 +00:00
static cairo_surface_t * cups_printer_create_cairo_surface ( GtkPrinter * printer ,
2006-06-16 05:08:14 +00:00
GtkPrintSettings * settings ,
2006-05-04 13:43:32 +00:00
gdouble width ,
gdouble height ,
2006-06-21 18:16:58 +00:00
GIOChannel * cache_io ) ;
2006-05-04 13:43:32 +00:00
2006-04-21 15:09:32 +00:00
static void
gtk_print_backend_cups_register_type ( GTypeModule * module )
{
2006-05-05 20:22:27 +00:00
static const GTypeInfo print_backend_cups_info =
{
sizeof ( GtkPrintBackendCupsClass ) ,
NULL , /* base_init */
NULL , /* base_finalize */
( GClassInitFunc ) gtk_print_backend_cups_class_init ,
NULL , /* class_finalize */
NULL , /* class_data */
sizeof ( GtkPrintBackendCups ) ,
2006-06-21 05:08:43 +00:00
0 , /* n_preallocs */
2006-05-05 20:22:27 +00:00
( GInstanceInitFunc ) gtk_print_backend_cups_init
} ;
print_backend_cups_type = g_type_module_register_type ( module ,
GTK_TYPE_PRINT_BACKEND ,
" GtkPrintBackendCups " ,
& print_backend_cups_info , 0 ) ;
2006-04-21 15:09:32 +00:00
}
G_MODULE_EXPORT void
pb_module_init ( GTypeModule * module )
{
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Initializing the CUPS print backend module \n " ) ) ;
2006-04-21 15:09:32 +00:00
gtk_print_backend_cups_register_type ( module ) ;
gtk_printer_cups_register_type ( module ) ;
}
G_MODULE_EXPORT void
pb_module_exit ( void )
{
}
G_MODULE_EXPORT GtkPrintBackend *
pb_module_create ( void )
{
return gtk_print_backend_cups_new ( ) ;
}
/*
* GtkPrintBackendCups
*/
GType
gtk_print_backend_cups_get_type ( void )
{
return print_backend_cups_type ;
}
/**
* gtk_print_backend_cups_new :
*
* Creates a new # GtkPrintBackendCups object . # GtkPrintBackendCups
* implements the # GtkPrintBackend interface with direct access to
* the filesystem using Unix / Linux API calls
*
* Return value : the new # GtkPrintBackendCups object
2006-06-21 05:08:43 +00:00
*/
2006-04-21 15:09:32 +00:00
GtkPrintBackend *
gtk_print_backend_cups_new ( void )
{
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Creating a new CUPS print backend object \n " ) ) ;
2006-04-21 15:09:32 +00:00
return g_object_new ( GTK_TYPE_PRINT_BACKEND_CUPS , NULL ) ;
}
static void
gtk_print_backend_cups_class_init ( GtkPrintBackendCupsClass * class )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( class ) ;
2006-05-04 13:43:32 +00:00
GtkPrintBackendClass * backend_class = GTK_PRINT_BACKEND_CLASS ( class ) ;
2006-04-21 15:09:32 +00:00
backend_parent_class = g_type_class_peek_parent ( class ) ;
gobject_class - > finalize = gtk_print_backend_cups_finalize ;
2006-05-04 13:43:32 +00:00
gobject_class - > dispose = gtk_print_backend_cups_dispose ;
backend_class - > request_printer_list = cups_get_printer_list ;
backend_class - > print_stream = gtk_print_backend_cups_print_stream ;
backend_class - > printer_request_details = cups_printer_request_details ;
backend_class - > printer_create_cairo_surface = cups_printer_create_cairo_surface ;
backend_class - > printer_get_options = cups_printer_get_options ;
backend_class - > printer_mark_conflicts = cups_printer_mark_conflicts ;
backend_class - > printer_get_settings_from_options = cups_printer_get_settings_from_options ;
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 ;
2006-05-24 10:50:57 +00:00
backend_class - > printer_get_capabilities = cups_printer_get_capabilities ;
2006-04-21 15:09:32 +00:00
}
static cairo_status_t
2006-06-16 18:29:09 +00:00
_cairo_write_to_cups ( void * closure ,
2006-04-21 15:09:32 +00:00
const unsigned char * data ,
unsigned int length )
{
2006-06-21 18:16:58 +00:00
GIOChannel * io = ( GIOChannel * ) closure ;
gsize written ;
GError * error ;
error = NULL ;
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Writting %i byte chunk to temp file \n " , length ) ) ;
2006-06-16 18:29:09 +00:00
while ( length > 0 )
{
2006-06-21 18:16:58 +00:00
g_io_channel_write_chars ( io , data , length , & written , & error ) ;
2006-06-16 18:29:09 +00:00
2006-06-21 18:16:58 +00:00
if ( error ! = NULL )
2006-06-16 18:29:09 +00:00
{
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Error writting to temp file, %s \n " , error - > message ) ) ;
g_error_free ( error ) ;
2006-06-16 18:29:09 +00:00
return CAIRO_STATUS_WRITE_ERROR ;
}
2006-04-21 15:09:32 +00:00
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Wrote %i bytes to temp file \n " , written ) ) ;
2006-06-16 18:29:09 +00:00
data + = written ;
length - = written ;
}
return CAIRO_STATUS_SUCCESS ;
}
2006-04-21 15:09:32 +00:00
static cairo_surface_t *
2006-06-16 18:29:09 +00:00
cups_printer_create_cairo_surface ( GtkPrinter * printer ,
2006-06-16 05:08:14 +00:00
GtkPrintSettings * settings ,
2006-06-16 18:29:09 +00:00
gdouble width ,
gdouble height ,
2006-06-21 18:16:58 +00:00
GIOChannel * cache_io )
2006-04-21 15:09:32 +00:00
{
cairo_surface_t * surface ;
/* TODO: check if it is a ps or pdf printer */
2006-06-21 18:16:58 +00:00
surface = cairo_ps_surface_create_for_stream ( _cairo_write_to_cups , cache_io , width , height ) ;
2006-04-21 15:09:32 +00:00
/* TODO: DPI from settings object? */
2006-06-16 05:08:14 +00:00
cairo_surface_set_fallback_resolution ( surface , 300 , 300 ) ;
2006-04-21 15:09:32 +00:00
return surface ;
}
typedef struct {
GtkPrintJobCompleteFunc callback ;
GtkPrintJob * job ;
gpointer user_data ;
GDestroyNotify dnotify ;
} CupsPrintStreamData ;
static void
cups_free_print_stream_data ( CupsPrintStreamData * data )
{
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-04-21 15:09:32 +00:00
if ( data - > dnotify )
data - > dnotify ( data - > user_data ) ;
g_object_unref ( data - > job ) ;
g_free ( data ) ;
}
static void
cups_print_cb ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
GError * error = NULL ;
CupsPrintStreamData * ps = user_data ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-04-21 15:09:32 +00:00
if ( gtk_cups_result_is_error ( result ) )
error = g_error_new_literal ( gtk_print_error_quark ( ) ,
GTK_PRINT_ERROR_INTERNAL_ERROR ,
gtk_cups_result_get_error_string ( result ) ) ;
if ( ps - > callback )
ps - > callback ( ps - > job , ps - > user_data , error ) ;
if ( error = = NULL )
{
int job_id = 0 ;
ipp_attribute_t * attr ; /* IPP job-id attribute */
ipp_t * response = gtk_cups_result_get_response ( result ) ;
2006-06-21 05:08:43 +00:00
if ( ( attr = ippFindAttribute ( response , " job-id " , IPP_TAG_INTEGER ) ) ! = NULL )
2006-04-21 15:09:32 +00:00
job_id = attr - > values [ 0 ] . integer ;
2006-05-15 16:22:38 +00:00
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 ) ;
}
}
2006-04-21 15:09:32 +00:00
else
gtk_print_job_set_status ( ps - > job , GTK_PRINT_STATUS_FINISHED_ABORTED ) ;
if ( error )
g_error_free ( error ) ;
}
static void
2006-06-21 05:08:43 +00:00
add_cups_options ( const gchar * key ,
const gchar * value ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
GtkCupsRequest * request = user_data ;
if ( ! g_str_has_prefix ( key , " cups- " ) )
return ;
if ( strcmp ( value , " gtk-ignore-value " ) = = 0 )
return ;
2006-06-21 05:08:43 +00:00
key = key + strlen ( " cups- " ) ;
2006-04-21 15:09:32 +00:00
gtk_cups_request_encode_option ( request , key , value ) ;
}
static void
2006-06-16 18:29:09 +00:00
gtk_print_backend_cups_print_stream ( GtkPrintBackend * print_backend ,
GtkPrintJob * job ,
2006-06-21 18:16:58 +00:00
GIOChannel * data_io ,
2006-06-16 18:29:09 +00:00
GtkPrintJobCompleteFunc callback ,
gpointer user_data ,
2006-06-21 18:16:58 +00:00
GDestroyNotify dnotify )
2006-04-21 15:09:32 +00:00
{
GtkPrinterCups * cups_printer ;
CupsPrintStreamData * ps ;
GtkCupsRequest * request ;
GtkPrintSettings * settings ;
const gchar * title ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-04-21 15:09:32 +00:00
cups_printer = GTK_PRINTER_CUPS ( gtk_print_job_get_printer ( job ) ) ;
settings = gtk_print_job_get_settings ( job ) ;
request = gtk_cups_request_new ( NULL ,
GTK_CUPS_POST ,
IPP_PRINT_JOB ,
2006-06-21 18:16:58 +00:00
data_io ,
2006-04-21 15:09:32 +00:00
NULL ,
cups_printer - > device_uri ) ;
gtk_cups_request_ipp_add_string ( request , IPP_TAG_OPERATION , IPP_TAG_URI , " printer-uri " ,
NULL , cups_printer - > printer_uri ) ;
gtk_cups_request_ipp_add_string ( request , IPP_TAG_OPERATION , IPP_TAG_NAME , " requesting-user-name " ,
NULL , cupsUser ( ) ) ;
title = gtk_print_job_get_title ( job ) ;
if ( title )
gtk_cups_request_ipp_add_string ( request , IPP_TAG_OPERATION , IPP_TAG_NAME , " job-name " , NULL ,
title ) ;
gtk_print_settings_foreach ( settings , add_cups_options , request ) ;
ps = g_new0 ( CupsPrintStreamData , 1 ) ;
ps - > callback = callback ;
ps - > user_data = user_data ;
ps - > dnotify = dnotify ;
ps - > job = g_object_ref ( job ) ;
cups_request_execute ( GTK_PRINT_BACKEND_CUPS ( print_backend ) ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_print_cb ,
ps ,
2006-06-21 05:08:43 +00:00
( GDestroyNotify ) cups_free_print_stream_data ) ;
2006-04-21 15:09:32 +00:00
}
static void
gtk_print_backend_cups_init ( GtkPrintBackendCups * backend_cups )
{
2006-08-28 18:03:44 +00:00
backend_cups - > list_printers_poll = FALSE ;
backend_cups - > got_default_printer = FALSE ;
2006-04-21 15:09:32 +00:00
backend_cups - > list_printers_pending = FALSE ;
cups_request_default_printer ( backend_cups ) ;
}
static void
gtk_print_backend_cups_finalize ( GObject * object )
{
GtkPrintBackendCups * backend_cups ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: finalizing CUPS backend module \n " ) ) ;
2006-04-21 15:09:32 +00:00
backend_cups = GTK_PRINT_BACKEND_CUPS ( object ) ;
g_free ( backend_cups - > default_printer ) ;
backend_cups - > default_printer = NULL ;
backend_parent_class - > finalize ( object ) ;
}
2006-05-04 13:43:32 +00:00
static void
gtk_print_backend_cups_dispose ( GObject * object )
{
GtkPrintBackendCups * backend_cups ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-05-04 13:43:32 +00:00
backend_cups = GTK_PRINT_BACKEND_CUPS ( object ) ;
if ( backend_cups - > list_printers_poll > 0 )
g_source_remove ( backend_cups - > list_printers_poll ) ;
backend_cups - > list_printers_poll = 0 ;
backend_parent_class - > dispose ( object ) ;
}
2006-04-21 15:09:32 +00:00
static gboolean
cups_dispatch_watch_check ( GSource * source )
{
GtkPrintCupsDispatchWatch * dispatch ;
GtkCupsPollState poll_state ;
gboolean result ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s <source %p> \n " , G_STRFUNC , source ) ) ;
2006-04-21 15:09:32 +00:00
dispatch = ( GtkPrintCupsDispatchWatch * ) source ;
poll_state = gtk_cups_request_get_poll_state ( dispatch - > request ) ;
if ( dispatch - > data_poll = = NULL & &
dispatch - > request - > http ! = NULL )
{
dispatch - > data_poll = g_new0 ( GPollFD , 1 ) ;
dispatch - > data_poll - > fd = dispatch - > request - > http - > fd ;
g_source_add_poll ( source , dispatch - > data_poll ) ;
}
if ( dispatch - > data_poll ! = NULL & & dispatch - > request - > http ! = NULL )
{
if ( dispatch - > data_poll - > fd ! = dispatch - > request - > http - > fd )
dispatch - > data_poll - > fd = dispatch - > request - > http - > fd ;
if ( poll_state = = GTK_CUPS_HTTP_READ )
dispatch - > data_poll - > events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI ;
else if ( poll_state = = GTK_CUPS_HTTP_WRITE )
dispatch - > data_poll - > events = G_IO_OUT | G_IO_ERR ;
else
dispatch - > data_poll - > events = 0 ;
}
if ( poll_state ! = GTK_CUPS_HTTP_IDLE )
if ( ! ( dispatch - > data_poll - > revents & dispatch - > data_poll - > events ) )
return FALSE ;
result = gtk_cups_request_read_write ( dispatch - > request ) ;
if ( result & & dispatch - > data_poll ! = NULL )
{
g_source_remove_poll ( source , dispatch - > data_poll ) ;
g_free ( dispatch - > data_poll ) ;
dispatch - > data_poll = NULL ;
}
return result ;
}
static gboolean
cups_dispatch_watch_prepare ( GSource * source ,
2006-06-16 18:29:09 +00:00
gint * timeout_ )
2006-04-21 15:09:32 +00:00
{
GtkPrintCupsDispatchWatch * dispatch ;
dispatch = ( GtkPrintCupsDispatchWatch * ) source ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s <source %p> \n " , G_STRFUNC , source ) ) ;
2006-04-21 15:09:32 +00:00
* timeout_ = - 1 ;
return gtk_cups_request_read_write ( dispatch - > request ) ;
}
static gboolean
2006-06-16 18:29:09 +00:00
cups_dispatch_watch_dispatch ( GSource * source ,
GSourceFunc callback ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
GtkPrintCupsDispatchWatch * dispatch ;
GtkPrintCupsResponseCallbackFunc ep_callback ;
GtkCupsResult * result ;
g_assert ( callback ! = NULL ) ;
ep_callback = ( GtkPrintCupsResponseCallbackFunc ) callback ;
dispatch = ( GtkPrintCupsDispatchWatch * ) source ;
result = gtk_cups_request_get_result ( dispatch - > request ) ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s <source %p> \n " , G_STRFUNC , source ) ) ;
2006-04-21 15:09:32 +00:00
if ( gtk_cups_result_is_error ( result ) )
2006-06-21 18:16:58 +00:00
g_warning ( " Error result: %s " , gtk_cups_result_get_error_string ( result ) ) ;
2006-04-21 15:09:32 +00:00
ep_callback ( GTK_PRINT_BACKEND ( dispatch - > backend ) , result , user_data ) ;
return FALSE ;
}
static void
cups_dispatch_watch_finalize ( GSource * source )
{
GtkPrintCupsDispatchWatch * dispatch ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s <source %p> \n " , G_STRFUNC , source ) ) ;
2006-04-21 15:09:32 +00:00
dispatch = ( GtkPrintCupsDispatchWatch * ) source ;
gtk_cups_request_free ( dispatch - > request ) ;
if ( dispatch - > backend )
{
2006-05-04 13:43:32 +00:00
/* We need to unref this at idle time, because it might be the
2006-05-15 15:24:12 +00:00
* 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 ) ;
2006-04-21 15:09:32 +00:00
dispatch - > backend = NULL ;
}
if ( dispatch - > data_poll ! = NULL )
g_free ( dispatch - > data_poll ) ;
}
static GSourceFuncs _cups_dispatch_watch_funcs = {
cups_dispatch_watch_prepare ,
cups_dispatch_watch_check ,
cups_dispatch_watch_dispatch ,
cups_dispatch_watch_finalize
} ;
static void
2006-06-16 18:29:09 +00:00
cups_request_execute ( GtkPrintBackendCups * print_backend ,
GtkCupsRequest * request ,
GtkPrintCupsResponseCallbackFunc callback ,
gpointer user_data ,
2006-06-21 05:08:43 +00:00
GDestroyNotify notify )
2006-04-21 15:09:32 +00:00
{
GtkPrintCupsDispatchWatch * dispatch ;
2006-05-04 13:43:32 +00:00
2006-04-21 15:09:32 +00:00
dispatch = ( GtkPrintCupsDispatchWatch * ) g_source_new ( & _cups_dispatch_watch_funcs ,
sizeof ( GtkPrintCupsDispatchWatch ) ) ;
2006-06-21 18:16:58 +00:00
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 ) ) ;
2006-04-21 15:09:32 +00:00
dispatch - > request = request ;
dispatch - > backend = g_object_ref ( print_backend ) ;
dispatch - > data_poll = NULL ;
g_source_set_callback ( ( GSource * ) dispatch , ( GSourceFunc ) callback , user_data , notify ) ;
g_source_attach ( ( GSource * ) dispatch , NULL ) ;
2006-05-04 13:43:32 +00:00
g_source_unref ( ( GSource * ) dispatch ) ;
2006-04-21 15:09:32 +00:00
}
static void
2006-05-04 13:43:32 +00:00
cups_request_printer_info_cb ( GtkPrintBackendCups * backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
ipp_attribute_t * attr ;
ipp_t * response ;
gchar * printer_name ;
GtkPrinterCups * cups_printer ;
GtkPrinter * printer ;
gchar * loc ;
gchar * desc ;
gchar * state_msg ;
int job_count ;
gboolean status_changed ;
2006-05-04 13:43:32 +00:00
g_assert ( GTK_IS_PRINT_BACKEND_CUPS ( backend ) ) ;
2006-04-21 15:09:32 +00:00
printer_name = ( gchar * ) user_data ;
2006-05-04 13:43:32 +00:00
printer = gtk_print_backend_find_printer ( GTK_PRINT_BACKEND ( backend ) ,
printer_name ) ;
2006-04-21 15:09:32 +00:00
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s - Got printer info for printer '%s' \n " , G_STRFUNC , printer_name ) ) ;
2006-05-04 13:43:32 +00:00
if ( ! printer )
2006-06-21 18:16:58 +00:00
{
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Could not find printer called '%s' \n " , printer_name ) ) ;
return ;
}
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
cups_printer = GTK_PRINTER_CUPS ( printer ) ;
2006-04-21 15:09:32 +00:00
if ( gtk_cups_result_is_error ( result ) )
{
if ( gtk_printer_is_new ( printer ) )
{
2006-05-04 13:43:32 +00:00
gtk_print_backend_remove_printer ( GTK_PRINT_BACKEND ( backend ) ,
printer ) ;
2006-04-21 15:09:32 +00:00
return ;
}
else
return ; /* TODO: mark as inactive printer */
}
response = gtk_cups_result_get_response ( result ) ;
/* TODO: determine printer type and use correct icon */
2006-06-17 01:04:50 +00:00
gtk_printer_set_icon_name ( printer , " gtk-print " ) ;
2006-05-10 00:42:23 +00:00
2006-04-21 15:09:32 +00:00
state_msg = " " ;
loc = " " ;
desc = " " ;
job_count = 0 ;
for ( attr = response - > attrs ; attr ! = NULL ; attr = attr - > next )
{
if ( ! attr - > name )
continue ;
_CUPS_MAP_ATTR_STR ( attr , loc , " printer-location " ) ;
_CUPS_MAP_ATTR_STR ( attr , desc , " printer-info " ) ;
_CUPS_MAP_ATTR_STR ( attr , state_msg , " printer-state-message " ) ;
_CUPS_MAP_ATTR_INT ( attr , cups_printer - > state , " printer-state " ) ;
_CUPS_MAP_ATTR_INT ( attr , job_count , " queued-job-count " ) ;
}
status_changed = gtk_printer_set_job_count ( printer , job_count ) ;
status_changed | = gtk_printer_set_location ( printer , loc ) ;
status_changed | = gtk_printer_set_description ( printer , desc ) ;
status_changed | = gtk_printer_set_state_message ( printer , state_msg ) ;
if ( status_changed )
2006-05-04 13:43:32 +00:00
g_signal_emit_by_name ( GTK_PRINT_BACKEND ( backend ) ,
" printer-status-changed " , printer ) ;
2006-04-21 15:09:32 +00:00
}
static void
cups_request_printer_info ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
const gchar * printer_name )
2006-04-21 15:09:32 +00:00
{
GtkCupsRequest * request ;
gchar * printer_uri ;
2006-05-04 13:43:32 +00:00
static const char * const pattrs [ ] = /* Attributes we're interested in */
{
" printer-location " ,
" printer-info " ,
" printer-state-message " ,
" printer-state " ,
" queued-job-count "
} ;
2006-04-21 15:09:32 +00:00
request = gtk_cups_request_new ( NULL ,
GTK_CUPS_POST ,
IPP_GET_PRINTER_ATTRIBUTES ,
2006-06-21 18:16:58 +00:00
NULL ,
2006-04-21 15:09:32 +00:00
NULL ,
NULL ) ;
printer_uri = g_strdup_printf ( " ipp://localhost/printers/%s " ,
printer_name ) ;
gtk_cups_request_ipp_add_string ( request , IPP_TAG_OPERATION , IPP_TAG_URI ,
" printer-uri " , NULL , printer_uri ) ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s - Requesting printer info for URI '%s' \n " , G_STRFUNC , printer_uri ) ) ;
2006-04-21 15:09:32 +00:00
g_free ( printer_uri ) ;
2006-05-04 13:43:32 +00:00
gtk_cups_request_ipp_add_strings ( request , IPP_TAG_OPERATION , IPP_TAG_KEYWORD ,
" requested-attributes " , G_N_ELEMENTS ( pattrs ) ,
NULL , pattrs ) ;
2006-04-21 15:09:32 +00:00
cups_request_execute ( print_backend ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_request_printer_info_cb ,
g_strdup ( printer_name ) ,
2006-06-21 05:08:43 +00:00
( GDestroyNotify ) g_free ) ;
2006-04-21 15:09:32 +00:00
}
typedef struct {
GtkPrintBackendCups * print_backend ;
GtkPrintJob * job ;
int job_id ;
int counter ;
} CupsJobPollData ;
static void
2006-06-16 18:29:09 +00:00
job_object_died ( gpointer user_data ,
2006-04-21 15:09:32 +00:00
GObject * where_the_object_was )
{
CupsJobPollData * data = user_data ;
data - > job = NULL ;
}
static void
cups_job_poll_data_free ( CupsJobPollData * data )
{
if ( data - > job )
g_object_weak_unref ( G_OBJECT ( data - > job ) , job_object_died , data ) ;
g_free ( data ) ;
}
static void
cups_request_job_info_cb ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
CupsJobPollData * data = user_data ;
ipp_attribute_t * attr ;
ipp_t * response ;
int state ;
gboolean done ;
if ( data - > job = = NULL )
{
cups_job_poll_data_free ( data ) ;
return ;
}
data - > counter + + ;
response = gtk_cups_result_get_response ( result ) ;
state = 0 ;
for ( attr = response - > attrs ; attr ! = NULL ; attr = attr - > next )
{
if ( ! attr - > name )
continue ;
_CUPS_MAP_ATTR_INT ( attr , state , " job-state " ) ;
}
done = FALSE ;
switch ( state )
{
case IPP_JOB_PENDING :
case IPP_JOB_HELD :
case IPP_JOB_STOPPED :
gtk_print_job_set_status ( data - > job ,
GTK_PRINT_STATUS_PENDING ) ;
break ;
case IPP_JOB_PROCESSING :
gtk_print_job_set_status ( data - > job ,
GTK_PRINT_STATUS_PRINTING ) ;
break ;
default :
case IPP_JOB_CANCELLED :
case IPP_JOB_ABORTED :
gtk_print_job_set_status ( data - > job ,
GTK_PRINT_STATUS_FINISHED_ABORTED ) ;
done = TRUE ;
break ;
case 0 :
case IPP_JOB_COMPLETED :
gtk_print_job_set_status ( data - > job ,
GTK_PRINT_STATUS_FINISHED ) ;
done = TRUE ;
break ;
}
if ( ! done & & data - > job ! = NULL )
{
guint32 timeout ;
if ( data - > counter < 5 )
timeout = 100 ;
else if ( data - > counter < 10 )
timeout = 500 ;
else
timeout = 1000 ;
g_timeout_add ( timeout , cups_job_info_poll_timeout , data ) ;
}
else
cups_job_poll_data_free ( data ) ;
}
static void
cups_request_job_info ( CupsJobPollData * data )
{
GtkCupsRequest * request ;
gchar * printer_uri ;
request = gtk_cups_request_new ( NULL ,
GTK_CUPS_POST ,
IPP_GET_JOB_ATTRIBUTES ,
2006-06-21 18:16:58 +00:00
NULL ,
2006-04-21 15:09:32 +00:00
NULL ,
NULL ) ;
printer_uri = g_strdup_printf ( " ipp://localhost/jobs/%d " , data - > job_id ) ;
gtk_cups_request_ipp_add_string ( request , IPP_TAG_OPERATION , IPP_TAG_URI ,
" job-uri " , NULL , printer_uri ) ;
g_free ( printer_uri ) ;
cups_request_execute ( data - > print_backend ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_request_job_info_cb ,
data ,
2006-06-21 05:08:43 +00:00
NULL ) ;
2006-04-21 15:09:32 +00:00
}
static gboolean
cups_job_info_poll_timeout ( gpointer user_data )
{
CupsJobPollData * data = user_data ;
if ( data - > job = = NULL )
cups_job_poll_data_free ( data ) ;
else
cups_request_job_info ( data ) ;
return FALSE ;
}
static void
cups_begin_polling_info ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
GtkPrintJob * job ,
2006-06-21 05:08:43 +00:00
gint job_id )
2006-04-21 15:09:32 +00:00
{
CupsJobPollData * data ;
data = g_new0 ( CupsJobPollData , 1 ) ;
data - > print_backend = print_backend ;
data - > job = job ;
data - > job_id = job_id ;
data - > counter = 0 ;
g_object_weak_ref ( G_OBJECT ( job ) , job_object_died , data ) ;
cups_request_job_info ( data ) ;
}
static void
2006-06-16 18:29:09 +00:00
mark_printer_inactive ( GtkPrinter * printer ,
2006-05-04 13:43:32 +00:00
GtkPrintBackend * backend )
2006-04-21 15:09:32 +00:00
{
2006-05-04 13:43:32 +00:00
gtk_printer_set_is_active ( printer , FALSE ) ;
2006-06-21 05:08:43 +00:00
g_signal_emit_by_name ( backend , " printer-removed " , printer ) ;
2006-04-21 15:09:32 +00:00
}
2006-05-04 13:43:32 +00:00
static gint
2006-06-16 18:29:09 +00:00
find_printer ( GtkPrinter * printer ,
const gchar * find_name )
2006-04-21 15:09:32 +00:00
{
2006-06-16 18:29:09 +00:00
const gchar * printer_name ;
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
printer_name = gtk_printer_get_name ( printer ) ;
return g_ascii_strcasecmp ( printer_name , find_name ) ;
2006-04-21 15:09:32 +00:00
}
static void
cups_request_printer_list_cb ( GtkPrintBackendCups * cups_backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
2006-06-21 05:08:43 +00:00
GtkPrintBackend * backend = GTK_PRINT_BACKEND ( cups_backend ) ;
2006-04-21 15:09:32 +00:00
ipp_attribute_t * attr ;
ipp_t * response ;
gboolean list_has_changed ;
GList * removed_printer_checklist ;
list_has_changed = FALSE ;
2006-07-06 17:55:32 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-04-21 15:09:32 +00:00
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 ) ) ;
2006-08-31 17:44:07 +00:00
goto done ;
2006-04-21 15:09:32 +00:00
}
2006-05-04 13:43:32 +00:00
2006-06-21 05:08:43 +00:00
/* 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 ) ;
2006-05-04 13:43:32 +00:00
2006-04-21 15:09:32 +00:00
response = gtk_cups_result_get_response ( result ) ;
2006-05-04 13:43:32 +00:00
for ( attr = response - > attrs ; attr ! = NULL ; attr = attr - > next )
2006-04-21 15:09:32 +00:00
{
GtkPrinter * printer ;
const gchar * printer_name ;
2006-06-21 05:08:43 +00:00
const gchar * printer_uri ;
const gchar * member_uris ;
2006-04-21 15:09:32 +00:00
GList * node ;
2006-05-04 13:43:32 +00:00
2006-06-21 05:08:43 +00:00
/* Skip leading attributes until we hit a printer...
*/
2006-05-04 13:43:32 +00:00
while ( attr ! = NULL & & attr - > group_tag ! = IPP_TAG_PRINTER )
attr = attr - > next ;
if ( attr = = NULL )
break ;
printer_name = NULL ;
printer_uri = NULL ;
member_uris = NULL ;
while ( attr ! = NULL & & attr - > group_tag = = IPP_TAG_PRINTER )
{
2006-06-21 05:08:43 +00:00
if ( ! strcmp ( attr - > name , " printer-name " ) & &
2006-05-04 13:43:32 +00:00
attr - > value_tag = = IPP_TAG_NAME )
printer_name = attr - > values [ 0 ] . string . text ;
2006-06-21 05:08:43 +00:00
else if ( ! strcmp ( attr - > name , " printer-uri-supported " ) & &
2006-05-04 13:43:32 +00:00
attr - > value_tag = = IPP_TAG_URI )
printer_uri = attr - > values [ 0 ] . string . text ;
2006-06-21 05:08:43 +00:00
else if ( ! strcmp ( attr - > name , " member-uris " ) & &
2006-05-04 13:43:32 +00:00
attr - > value_tag = = IPP_TAG_URI )
member_uris = attr - > values [ 0 ] . string . text ;
2006-07-06 17:55:32 +00:00
else
{
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Attribute %s ignored " , attr - > name ) ) ;
}
2006-05-04 13:43:32 +00:00
attr = attr - > next ;
}
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
if ( printer_name = = NULL | |
( printer_uri = = NULL & & member_uris = = NULL ) )
{
if ( attr = = NULL )
break ;
else
continue ;
}
2006-04-21 15:09:32 +00:00
/* remove name from checklist if it was found */
2006-05-04 13:43:32 +00:00
node = g_list_find_custom ( removed_printer_checklist , printer_name , ( GCompareFunc ) find_printer ) ;
2006-04-21 15:09:32 +00:00
removed_printer_checklist = g_list_delete_link ( removed_printer_checklist , node ) ;
2006-06-21 05:08:43 +00:00
printer = gtk_print_backend_find_printer ( backend , printer_name ) ;
2006-05-04 13:43:32 +00:00
if ( ! printer )
2006-04-21 15:09:32 +00:00
{
2006-05-04 13:43:32 +00:00
GtkPrinterCups * cups_printer ;
2006-06-21 05:08:43 +00:00
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 */
2006-05-04 13:43:32 +00:00
int port ; /* Port number */
2006-04-21 15:09:32 +00:00
list_has_changed = TRUE ;
2006-06-21 05:08:43 +00:00
cups_printer = gtk_printer_cups_new ( printer_name , backend ) ;
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
cups_printer - > device_uri = g_strdup_printf ( " /printers/%s " , printer_name ) ;
2006-07-06 17:55:32 +00:00
/* Check to see if we are looking at a class */
2006-05-04 13:43:32 +00:00
if ( member_uris )
2006-07-06 17:55:32 +00:00
{
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 ) ) ;
}
2006-05-04 13:43:32 +00:00
else
2006-07-06 17:55:32 +00:00
{
cups_printer - > printer_uri = g_strdup ( printer_uri ) ;
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Found printer %s \n " , printer_uri ) ) ;
}
2006-05-04 13:43:32 +00:00
# if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
httpSeparateURI ( HTTP_URI_CODING_ALL , cups_printer - > printer_uri ,
method , sizeof ( method ) ,
username , sizeof ( username ) ,
hostname , sizeof ( hostname ) ,
& port ,
resource , sizeof ( resource ) ) ;
# else
httpSeparate ( cups_printer - > printer_uri ,
method ,
username ,
hostname ,
& port ,
resource ) ;
# endif
2006-11-25 05:12:48 +00:00
if ( ! strncmp ( resource , " /printers/ " , 10 ) )
2006-07-06 17:55:32 +00:00
{
cups_printer - > ppd_name = g_strdup ( resource + 10 ) ;
GTK_NOTE ( PRINTING ,
2006-11-25 05:12:48 +00:00
g_print ( " CUPS Backend: Setting ppd name '%s' for printer/class '%s' \n " , cups_printer - > ppd_name , printer_name ) ) ;
2006-07-06 17:55:32 +00:00
}
2006-06-21 05:08:43 +00:00
gethostname ( uri , sizeof ( uri ) ) ;
if ( strcasecmp ( uri , hostname ) = = 0 )
strcpy ( hostname , " localhost " ) ;
2006-05-04 13:43:32 +00:00
cups_printer - > hostname = g_strdup ( hostname ) ;
cups_printer - > port = port ;
printer = GTK_PRINTER ( cups_printer ) ;
2006-04-21 15:09:32 +00:00
if ( cups_backend - > default_printer ! = NULL & &
strcmp ( cups_backend - > default_printer , gtk_printer_get_name ( printer ) ) = = 0 )
gtk_printer_set_is_default ( printer , TRUE ) ;
2006-05-04 13:43:32 +00:00
2006-06-21 05:08:43 +00:00
gtk_print_backend_add_printer ( backend , printer ) ;
2006-04-21 15:09:32 +00:00
}
2006-05-04 13:43:32 +00:00
else
g_object_ref ( printer ) ;
2006-04-21 15:09:32 +00:00
if ( ! gtk_printer_is_active ( printer ) )
{
gtk_printer_set_is_active ( printer , TRUE ) ;
gtk_printer_set_is_new ( printer , TRUE ) ;
list_has_changed = TRUE ;
}
if ( gtk_printer_is_new ( printer ) )
{
2006-06-21 05:08:43 +00:00
g_signal_emit_by_name ( backend , " printer-added " , printer ) ;
2006-04-21 15:09:32 +00:00
gtk_printer_set_is_new ( printer , FALSE ) ;
}
cups_request_printer_info ( cups_backend , gtk_printer_get_name ( printer ) ) ;
2006-05-04 13:43:32 +00:00
/* The ref is held by GtkPrintBackend, in add_printer() */
g_object_unref ( printer ) ;
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
if ( attr = = NULL )
break ;
}
2006-04-21 15:09:32 +00:00
2006-05-04 13:43:32 +00:00
/* look at the removed printers checklist and mark any printer
as inactive if it is in the list , emitting a printer_removed signal */
if ( removed_printer_checklist ! = NULL )
{
2006-06-21 05:08:43 +00:00
g_list_foreach ( removed_printer_checklist , ( GFunc ) mark_printer_inactive , backend ) ;
2006-05-04 13:43:32 +00:00
g_list_free ( removed_printer_checklist ) ;
list_has_changed = TRUE ;
}
2006-08-31 17:44:07 +00:00
done :
2006-05-04 13:43:32 +00:00
if ( list_has_changed )
2006-06-21 05:08:43 +00:00
g_signal_emit_by_name ( backend , " printer-list-changed " ) ;
2006-05-04 13:43:32 +00:00
2006-06-21 05:08:43 +00:00
gtk_print_backend_set_list_done ( backend ) ;
2006-04-21 15:09:32 +00:00
}
static gboolean
cups_request_printer_list ( GtkPrintBackendCups * cups_backend )
{
GtkCupsRequest * request ;
2006-05-04 13:43:32 +00:00
static const char * const pattrs [ ] = /* Attributes we're interested in */
{
" printer-name " ,
" printer-uri-supported " ,
" member-uris "
} ;
2006-04-21 15:09:32 +00:00
if ( cups_backend - > list_printers_pending | |
! cups_backend - > got_default_printer )
return TRUE ;
2006-12-22 19:10:43 +00:00
g_object_ref ( cups_backend ) ;
GDK_THREADS_LEAVE ( ) ;
2006-04-21 15:09:32 +00:00
cups_backend - > list_printers_pending = TRUE ;
request = gtk_cups_request_new ( NULL ,
GTK_CUPS_POST ,
CUPS_GET_PRINTERS ,
2006-06-21 18:16:58 +00:00
NULL ,
2006-04-21 15:09:32 +00:00
NULL ,
NULL ) ;
2006-05-04 13:43:32 +00:00
gtk_cups_request_ipp_add_strings ( request , IPP_TAG_OPERATION , IPP_TAG_KEYWORD ,
" requested-attributes " , G_N_ELEMENTS ( pattrs ) ,
NULL , pattrs ) ;
2006-04-21 15:09:32 +00:00
cups_request_execute ( cups_backend ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_request_printer_list_cb ,
request ,
2006-06-21 05:08:43 +00:00
NULL ) ;
2006-12-22 19:10:43 +00:00
GDK_THREADS_ENTER ( ) ;
g_object_unref ( cups_backend ) ;
2006-04-21 15:09:32 +00:00
return TRUE ;
}
2006-05-04 13:43:32 +00:00
static void
cups_get_printer_list ( GtkPrintBackend * backend )
2006-04-21 15:09:32 +00:00
{
GtkPrintBackendCups * cups_backend ;
2006-05-04 13:43:32 +00:00
cups_backend = GTK_PRINT_BACKEND_CUPS ( backend ) ;
2006-04-21 15:09:32 +00:00
if ( cups_backend - > list_printers_poll = = 0 )
{
cups_request_printer_list ( cups_backend ) ;
2006-12-22 19:10:43 +00:00
cups_backend - > list_printers_poll = gdk_threads_add_timeout ( 3000 ,
2006-04-21 15:09:32 +00:00
( GSourceFunc ) cups_request_printer_list ,
2006-05-04 13:43:32 +00:00
backend ) ;
2006-04-21 15:09:32 +00:00
}
}
typedef struct {
GtkPrinterCups * printer ;
2006-06-21 18:16:58 +00:00
GIOChannel * ppd_io ;
2006-04-21 15:09:32 +00:00
} GetPPDData ;
static void
get_ppd_data_free ( GetPPDData * data )
{
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
g_io_channel_unref ( data - > ppd_io ) ;
2006-04-21 15:09:32 +00:00
g_object_unref ( data - > printer ) ;
g_free ( data ) ;
}
static void
cups_request_ppd_cb ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
GetPPDData * data )
2006-04-21 15:09:32 +00:00
{
ipp_t * response ;
GtkPrinter * printer ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-04-21 15:09:32 +00:00
printer = GTK_PRINTER ( data - > printer ) ;
GTK_PRINTER_CUPS ( printer ) - > reading_ppd = FALSE ;
if ( gtk_cups_result_is_error ( result ) )
{
2006-07-06 17:55:32 +00:00
g_signal_emit_by_name ( printer , " details-acquired " , FALSE ) ;
2006-04-21 15:09:32 +00:00
return ;
}
response = gtk_cups_result_get_response ( result ) ;
2006-06-21 18:16:58 +00:00
/* 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 ) ) ) ;
2006-04-21 15:09:32 +00:00
gtk_printer_set_has_details ( printer , TRUE ) ;
2006-07-06 17:55:32 +00:00
g_signal_emit_by_name ( printer , " details-acquired " , TRUE ) ;
2006-04-21 15:09:32 +00:00
}
static void
2006-06-16 18:29:09 +00:00
cups_request_ppd ( GtkPrinter * printer )
2006-04-21 15:09:32 +00:00
{
GError * error ;
GtkPrintBackend * print_backend ;
GtkPrinterCups * cups_printer ;
GtkCupsRequest * request ;
2006-06-21 18:16:58 +00:00
char * ppd_filename ;
2006-04-21 15:09:32 +00:00
gchar * resource ;
http_t * http ;
GetPPDData * data ;
2006-06-21 18:16:58 +00:00
int fd ;
2006-04-21 15:09:32 +00:00
cups_printer = GTK_PRINTER_CUPS ( printer ) ;
error = NULL ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: %s \n " , G_STRFUNC ) ) ;
2006-06-16 05:08:14 +00:00
/* FIXME this can return NULL! */
2006-06-21 05:08:43 +00:00
http = httpConnectEncrypt ( cups_printer - > hostname ,
cups_printer - > port ,
cupsEncryption ( ) ) ;
2006-04-21 15:09:32 +00:00
data = g_new0 ( GetPPDData , 1 ) ;
2006-06-21 18:16:58 +00:00
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 */
2006-04-21 15:09:32 +00:00
if ( error ! = NULL )
{
g_warning ( " %s " , error - > message ) ;
g_error_free ( error ) ;
httpClose ( http ) ;
2006-06-21 18:16:58 +00:00
g_free ( ppd_filename ) ;
2006-04-21 15:09:32 +00:00
g_free ( data ) ;
2006-07-06 17:55:32 +00:00
g_signal_emit_by_name ( printer , " details-acquired " , FALSE ) ;
2006-04-21 15:09:32 +00:00
return ;
}
2006-06-21 18:16:58 +00:00
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 ) ;
2006-04-21 15:09:32 +00:00
data - > printer = g_object_ref ( printer ) ;
2006-07-06 17:55:32 +00:00
resource = g_strdup_printf ( " /printers/%s.ppd " ,
gtk_printer_cups_get_ppd_name ( GTK_PRINTER_CUPS ( printer ) ) ) ;
2006-04-21 15:09:32 +00:00
request = gtk_cups_request_new ( http ,
GTK_CUPS_GET ,
0 ,
2006-06-21 18:16:58 +00:00
data - > ppd_io ,
2006-04-21 15:09:32 +00:00
cups_printer - > hostname ,
resource ) ;
2006-06-21 18:16:58 +00:00
GTK_NOTE ( PRINTING ,
g_print ( " CUPS Backend: Requesting resource %s to be written to temp file %s \n " , resource , ppd_filename ) ) ;
2006-04-21 15:09:32 +00:00
g_free ( resource ) ;
2006-06-21 18:16:58 +00:00
g_free ( ppd_filename ) ;
2006-04-21 15:09:32 +00:00
cups_printer - > reading_ppd = TRUE ;
print_backend = gtk_printer_get_backend ( printer ) ;
2006-06-16 05:08:14 +00:00
2006-04-21 15:09:32 +00:00
cups_request_execute ( GTK_PRINT_BACKEND_CUPS ( print_backend ) ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_request_ppd_cb ,
data ,
2006-06-21 05:08:43 +00:00
( GDestroyNotify ) get_ppd_data_free ) ;
2006-04-21 15:09:32 +00:00
}
static void
cups_request_default_printer_cb ( GtkPrintBackendCups * print_backend ,
2006-06-16 18:29:09 +00:00
GtkCupsResult * result ,
gpointer user_data )
2006-04-21 15:09:32 +00:00
{
ipp_t * response ;
ipp_attribute_t * attr ;
response = gtk_cups_result_get_response ( result ) ;
2006-06-21 05:08:43 +00:00
if ( ( attr = ippFindAttribute ( response , " printer-name " , IPP_TAG_NAME ) ) ! = NULL )
2006-04-21 15:09:32 +00:00
print_backend - > default_printer = g_strdup ( attr - > values [ 0 ] . string . text ) ;
print_backend - > got_default_printer = TRUE ;
2006-06-21 05:08:43 +00:00
/* Make sure to kick off get_printers if we are polling it,
* as we could have blocked this reading the default printer
*/
2006-04-21 15:09:32 +00:00
if ( print_backend - > list_printers_poll ! = 0 )
cups_request_printer_list ( print_backend ) ;
}
static void
cups_request_default_printer ( GtkPrintBackendCups * print_backend )
{
GtkCupsRequest * request ;
const char * str ;
2006-06-21 05:08:43 +00:00
if ( ( str = g_getenv ( " LPDEST " ) ) ! = NULL )
2006-04-21 15:09:32 +00:00
{
print_backend - > default_printer = g_strdup ( str ) ;
print_backend - > got_default_printer = TRUE ;
return ;
}
2006-06-21 05:08:43 +00:00
else if ( ( str = g_getenv ( " PRINTER " ) ) ! = NULL & &
strcmp ( str , " lp " ) ! = 0 )
2006-04-21 15:09:32 +00:00
{
print_backend - > default_printer = g_strdup ( str ) ;
print_backend - > got_default_printer = TRUE ;
return ;
}
request = gtk_cups_request_new ( NULL ,
GTK_CUPS_POST ,
CUPS_GET_DEFAULT ,
2006-06-21 18:16:58 +00:00
NULL ,
2006-04-21 15:09:32 +00:00
NULL ,
NULL ) ;
cups_request_execute ( print_backend ,
request ,
( GtkPrintCupsResponseCallbackFunc ) cups_request_default_printer_cb ,
g_object_ref ( print_backend ) ,
2006-06-21 05:08:43 +00:00
g_object_unref ) ;
2006-04-21 15:09:32 +00:00
}
static void
cups_printer_request_details ( GtkPrinter * printer )
{
GtkPrinterCups * cups_printer ;
cups_printer = GTK_PRINTER_CUPS ( printer ) ;
if ( ! cups_printer - > reading_ppd & &
gtk_printer_cups_get_ppd ( cups_printer ) = = NULL )
cups_request_ppd ( printer ) ;
}
static char *
2006-06-21 05:08:43 +00:00
ppd_text_to_utf8 ( ppd_file_t * ppd_file ,
const char * text )
2006-04-21 15:09:32 +00:00
{
const char * encoding = NULL ;
char * res ;
if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " UTF-8 " ) = = 0 )
{
return g_strdup ( text ) ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " ISOLatin1 " ) = = 0 )
{
encoding = " ISO-8859-1 " ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " ISOLatin2 " ) = = 0 )
{
encoding = " ISO-8859-2 " ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " ISOLatin5 " ) = = 0 )
{
encoding = " ISO-8859-5 " ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " JIS83-RKSJ " ) = = 0 )
{
encoding = " SHIFT-JIS " ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " MacStandard " ) = = 0 )
{
encoding = " MACINTOSH " ;
}
else if ( g_ascii_strcasecmp ( ppd_file - > lang_encoding , " WindowsANSI " ) = = 0 )
{
encoding = " WINDOWS-1252 " ;
}
else
{
/* Fallback, try iso-8859-1... */
encoding = " ISO-8859-1 " ;
}
res = g_convert ( text , - 1 , " UTF-8 " , encoding , NULL , NULL , NULL ) ;
if ( res = = NULL )
{
g_warning ( " unable to convert PPD text " ) ;
res = g_strdup ( " ??? " ) ;
}
return res ;
}
/* TODO: Add more translations for common settings here */
static const struct {
const char * keyword ;
const char * translation ;
} cups_option_translations [ ] = {
{ " Duplex " , N_ ( " Two Sided " ) } ,
2006-04-25 04:38:07 +00:00
{ " MediaType " , N_ ( " Paper Type " ) } ,
{ " InputSlot " , N_ ( " Paper Source " ) } ,
{ " OutputBin " , N_ ( " Output Tray " ) } ,
2006-04-21 15:09:32 +00:00
} ;
static const struct {
const char * keyword ;
const char * choice ;
const char * translation ;
} cups_choice_translations [ ] = {
{ " Duplex " , " None " , N_ ( " One Sided " ) } ,
{ " InputSlot " , " Auto " , N_ ( " Auto Select " ) } ,
{ " InputSlot " , " AutoSelect " , N_ ( " Auto Select " ) } ,
{ " InputSlot " , " Default " , N_ ( " Printer Default " ) } ,
{ " InputSlot " , " None " , N_ ( " Printer Default " ) } ,
{ " InputSlot " , " PrinterDefault " , N_ ( " Printer Default " ) } ,
{ " InputSlot " , " Unspecified " , N_ ( " Auto Select " ) } ,
} ;
static const struct {
const char * ppd_keyword ;
const char * name ;
} option_names [ ] = {
{ " Duplex " , " gtk-duplex " } ,
{ " MediaType " , " gtk-paper-type " } ,
{ " InputSlot " , " gtk-paper-source " } ,
{ " OutputBin " , " gtk-output-tray " } ,
} ;
/* keep sorted when changing */
static const char * color_option_whitelist [ ] = {
" BRColorEnhancement " ,
" BRColorMatching " ,
" BRColorMatching " ,
" BRColorMode " ,
" BRGammaValue " ,
" BRImprovedGray " ,
" BlackSubstitution " ,
" ColorModel " ,
" HPCMYKInks " ,
" HPCSGraphics " ,
" HPCSImages " ,
" HPCSText " ,
" HPColorSmart " ,
" RPSBlackMode " ,
" RPSBlackOverPrint " ,
" Rcmyksimulation " ,
} ;
/* keep sorted when changing */
static const char * color_group_whitelist [ ] = {
" ColorPage " ,
" FPColorWise1 " ,
" FPColorWise2 " ,
" FPColorWise3 " ,
" FPColorWise4 " ,
" FPColorWise5 " ,
" HPColorOptionsPanel " ,
} ;
/* keep sorted when changing */
static const char * image_quality_option_whitelist [ ] = {
" BRDocument " ,
" BRHalfTonePattern " ,
" BRNormalPrt " ,
" BRPrintQuality " ,
" BitsPerPixel " ,
" Darkness " ,
" Dithering " ,
" EconoMode " ,
" Economode " ,
" HPEconoMode " ,
" HPEdgeControl " ,
" HPGraphicsHalftone " ,
" HPHalftone " ,
" HPLJDensity " ,
" HPPhotoHalftone " ,
" OutputMode " ,
" REt " ,
" RPSBitsPerPixel " ,
" RPSDitherType " ,
" Resolution " ,
" ScreenLock " ,
" Smoothing " ,
" TonerSaveMode " ,
" UCRGCRForImage " ,
} ;
/* keep sorted when changing */
static const char * image_quality_group_whitelist [ ] = {
" FPImageQuality1 " ,
" FPImageQuality2 " ,
" FPImageQuality3 " ,
" ImageQualityPage " ,
} ;
/* keep sorted when changing */
static const char * finishing_option_whitelist [ ] = {
" BindColor " ,
" BindEdge " ,
" BindType " ,
" BindWhen " ,
" Booklet " ,
" FoldType " ,
" FoldWhen " ,
" HPStaplerOptions " ,
" Jog " ,
" Slipsheet " ,
" Sorter " ,
" StapleLocation " ,
" StapleOrientation " ,
" StapleWhen " ,
" StapleX " ,
" StapleY " ,
} ;
/* keep sorted when changing */
static const char * finishing_group_whitelist [ ] = {
" FPFinishing1 " ,
" FPFinishing2 " ,
" FPFinishing3 " ,
" FPFinishing4 " ,
" FinishingPage " ,
" HPFinishingPanel " ,
} ;
/* keep sorted when changing */
static const char * cups_option_blacklist [ ] = {
" Collate " ,
" Copies " ,
" OutputOrder " ,
" PageRegion " ,
" PageSize " ,
} ;
static char *
2006-06-16 18:29:09 +00:00
get_option_text ( ppd_file_t * ppd_file ,
ppd_option_t * option )
2006-04-21 15:09:32 +00:00
{
int i ;
char * utf8 ;
for ( i = 0 ; i < G_N_ELEMENTS ( cups_option_translations ) ; i + + )
{
if ( strcmp ( cups_option_translations [ i ] . keyword , option - > keyword ) = = 0 )
return g_strdup ( _ ( cups_option_translations [ i ] . translation ) ) ;
}
utf8 = ppd_text_to_utf8 ( ppd_file , option - > text ) ;
/* Some ppd files have spaces in the text before the colon */
g_strchomp ( utf8 ) ;
return utf8 ;
}
static char *
2006-06-16 18:29:09 +00:00
get_choice_text ( ppd_file_t * ppd_file ,
ppd_choice_t * choice )
2006-04-21 15:09:32 +00:00
{
int i ;
ppd_option_t * option = choice - > option ;
const char * keyword = option - > keyword ;
for ( i = 0 ; i < G_N_ELEMENTS ( cups_choice_translations ) ; i + + )
{
if ( strcmp ( cups_choice_translations [ i ] . keyword , keyword ) = = 0 & &
strcmp ( cups_choice_translations [ i ] . choice , choice - > choice ) = = 0 )
return g_strdup ( _ ( cups_choice_translations [ i ] . translation ) ) ;
}
return ppd_text_to_utf8 ( ppd_file , choice - > text ) ;
}
static gboolean
2006-06-16 18:29:09 +00:00
group_has_option ( ppd_group_t * group ,
ppd_option_t * option )
2006-04-21 15:09:32 +00:00
{
int i ;
if ( group = = NULL )
return FALSE ;
if ( group - > num_options > 0 & &
option > = group - > options & & option < group - > options + group - > num_options )
return TRUE ;
for ( i = 0 ; i < group - > num_subgroups ; i + + )
{
if ( group_has_option ( & group - > subgroups [ i ] , option ) )
return TRUE ;
}
return FALSE ;
}
static void
set_option_off ( GtkPrinterOption * option )
{
/* Any of these will do, _set only applies the value
* if its allowed of the option */
gtk_printer_option_set ( option , " False " ) ;
gtk_printer_option_set ( option , " Off " ) ;
gtk_printer_option_set ( option , " None " ) ;
}
static gboolean
value_is_off ( const char * value )
{
return ( strcasecmp ( value , " None " ) = = 0 | |
strcasecmp ( value , " Off " ) = = 0 | |
strcasecmp ( value , " False " ) = = 0 ) ;
}
2006-10-03 15:05:05 +00:00
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
}
2006-04-21 15:09:32 +00:00
static int
2006-06-16 18:29:09 +00:00
available_choices ( ppd_file_t * ppd ,
ppd_option_t * option ,
2006-04-21 15:09:32 +00:00
ppd_choice_t * * * available ,
2006-06-16 18:29:09 +00:00
gboolean keep_if_only_one_option )
2006-04-21 15:09:32 +00:00
{
ppd_option_t * other_option ;
int i , j ;
2006-06-21 05:08:43 +00:00
gchar * conflicts ;
2006-04-21 15:09:32 +00:00
ppd_const_t * constraint ;
const char * choice , * other_choice ;
ppd_option_t * option1 , * option2 ;
ppd_group_t * installed_options ;
int num_conflicts ;
gboolean all_default ;
int add_auto ;
if ( available )
* available = NULL ;
conflicts = g_new0 ( char , option - > num_choices ) ;
installed_options = NULL ;
for ( i = 0 ; i < ppd - > num_groups ; i + + )
{
2006-10-03 15:05:05 +00:00
char * name ;
name = ppd_group_name ( & ppd - > groups [ i ] ) ;
if ( strcmp ( name , " InstallableOptions " ) = = 0 )
2006-04-21 15:09:32 +00:00
{
installed_options = & ppd - > groups [ i ] ;
break ;
}
}
for ( i = ppd - > num_consts , constraint = ppd - > consts ; i > 0 ; i - - , constraint + + )
{
option1 = ppdFindOption ( ppd , constraint - > option1 ) ;
if ( option1 = = NULL )
continue ;
option2 = ppdFindOption ( ppd , constraint - > option2 ) ;
if ( option2 = = NULL )
continue ;
if ( option = = option1 )
{
choice = constraint - > choice1 ;
other_option = option2 ;
other_choice = constraint - > choice2 ;
}
else if ( option = = option2 )
{
choice = constraint - > choice2 ;
other_option = option1 ;
other_choice = constraint - > choice1 ;
}
else
continue ;
/* We only care of conflicts with installed_options and
PageSize */
if ( ! group_has_option ( installed_options , other_option ) & &
( strcmp ( other_option - > keyword , " PageSize " ) ! = 0 ) )
continue ;
if ( * other_choice = = 0 )
{
/* Conflict only if the installed option is not off */
if ( value_is_off ( other_option - > defchoice ) )
continue ;
}
/* Conflict if the installed option has the specified default */
else if ( strcasecmp ( other_choice , other_option - > defchoice ) ! = 0 )
continue ;
if ( * choice = = 0 )
{
/* Conflict with all non-off choices */
for ( j = 0 ; j < option - > num_choices ; j + + )
{
if ( ! value_is_off ( option - > choices [ j ] . choice ) )
conflicts [ j ] = 1 ;
}
}
else
{
for ( j = 0 ; j < option - > num_choices ; j + + )
{
if ( strcasecmp ( option - > choices [ j ] . choice , choice ) = = 0 )
conflicts [ j ] = 1 ;
}
}
}
num_conflicts = 0 ;
all_default = TRUE ;
for ( j = 0 ; j < option - > num_choices ; j + + )
{
if ( conflicts [ j ] )
num_conflicts + + ;
else if ( strcmp ( option - > choices [ j ] . choice , option - > defchoice ) ! = 0 )
all_default = FALSE ;
}
if ( all_default & & ! keep_if_only_one_option )
return 0 ;
if ( num_conflicts = = option - > num_choices )
return 0 ;
/* Some ppds don't have a "use printer default" option for
2006-06-21 05:08:43 +00:00
* 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 .
*/
2006-04-21 15:09:32 +00:00
add_auto = 0 ;
if ( strcmp ( option - > keyword , " InputSlot " ) = = 0 )
{
gboolean found_auto = FALSE ;
for ( j = 0 ; j < option - > num_choices ; j + + )
{
if ( ! conflicts [ j ] )
{
if ( strcmp ( option - > choices [ j ] . choice , " Auto " ) = = 0 | |
strcmp ( option - > choices [ j ] . choice , " AutoSelect " ) = = 0 | |
strcmp ( option - > choices [ j ] . choice , " Default " ) = = 0 | |
strcmp ( option - > choices [ j ] . choice , " None " ) = = 0 | |
strcmp ( option - > choices [ j ] . choice , " PrinterDefault " ) = = 0 | |
strcmp ( option - > choices [ j ] . choice , " Unspecified " ) = = 0 | |
option - > choices [ j ] . code = = NULL | |
option - > choices [ j ] . code [ 0 ] = = 0 )
{
found_auto = TRUE ;
break ;
}
}
}
if ( ! found_auto )
add_auto = 1 ;
}
if ( available )
{
* available = g_new ( ppd_choice_t * , option - > num_choices - num_conflicts + add_auto ) ;
i = 0 ;
for ( j = 0 ; j < option - > num_choices ; j + + )
{
if ( ! conflicts [ j ] )
( * available ) [ i + + ] = & option - > choices [ j ] ;
}
if ( add_auto )
( * available ) [ i + + ] = NULL ;
}
return option - > num_choices - num_conflicts + add_auto ;
}
static GtkPrinterOption *
2006-08-15 16:05:13 +00:00
create_pickone_option ( ppd_file_t * ppd_file ,
ppd_option_t * ppd_option ,
const gchar * gtk_name )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOption * option ;
ppd_choice_t * * available ;
char * label ;
int n_choices ;
int i ;
2006-08-15 16:05:13 +00:00
# ifdef HAVE_CUPS_API_1_2
ppd_coption_t * coption ;
# endif
2006-04-21 15:09:32 +00:00
g_assert ( ppd_option - > ui = = PPD_UI_PICKONE ) ;
option = NULL ;
n_choices = available_choices ( ppd_file , ppd_option , & available , g_str_has_prefix ( gtk_name , " gtk- " ) ) ;
if ( n_choices > 0 )
{
2006-07-18 18:26:51 +00:00
/* right now only support one parameter per custom option
* if more than one print warning and only offer the default choices
*/
2006-08-15 16:05:13 +00:00
label = get_option_text ( ppd_file , ppd_option ) ;
# ifdef HAVE_CUPS_API_1_2
coption = ppdFindCustomOption ( ppd_file , ppd_option - > keyword ) ;
2006-07-18 18:26:51 +00:00
if ( coption )
{
2006-08-15 16:05:13 +00:00
ppd_cparam_t * cparam ;
2006-07-18 18:26:51 +00:00
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 " ) ;
}
2006-08-15 16:05:13 +00:00
# endif /* HAVE_CUPS_API_1_2 */
2006-07-18 18:26:51 +00:00
if ( ! option )
option = gtk_printer_option_new ( gtk_name , label ,
GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
2006-04-21 15:09:32 +00:00
g_free ( label ) ;
gtk_printer_option_allocate_choices ( option , n_choices ) ;
for ( i = 0 ; i < n_choices ; i + + )
{
if ( available [ i ] = = NULL )
{
/* This was auto-added */
option - > choices [ i ] = g_strdup ( " gtk-ignore-value " ) ;
option - > choices_display [ i ] = g_strdup ( _ ( " Printer Default " ) ) ;
}
else
{
option - > choices [ i ] = g_strdup ( available [ i ] - > choice ) ;
option - > choices_display [ i ] = get_choice_text ( ppd_file , available [ i ] ) ;
}
}
gtk_printer_option_set ( option , ppd_option - > defchoice ) ;
}
# ifdef PRINT_IGNORED_OPTIONS
else
g_warning ( " Ignoring pickone %s \n " , ppd_option - > text ) ;
# endif
g_free ( available ) ;
return option ;
}
2006-07-18 18:26:51 +00:00
2006-04-21 15:09:32 +00:00
static GtkPrinterOption *
2006-06-16 18:29:09 +00:00
create_boolean_option ( ppd_file_t * ppd_file ,
2006-04-21 15:09:32 +00:00
ppd_option_t * ppd_option ,
2006-06-16 18:29:09 +00:00
const gchar * gtk_name )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOption * option ;
ppd_choice_t * * available ;
char * label ;
int n_choices ;
g_assert ( ppd_option - > ui = = PPD_UI_BOOLEAN ) ;
option = NULL ;
n_choices = available_choices ( ppd_file , ppd_option , & available , g_str_has_prefix ( gtk_name , " gtk- " ) ) ;
if ( n_choices = = 2 )
{
label = get_option_text ( ppd_file , ppd_option ) ;
option = gtk_printer_option_new ( gtk_name , label ,
2006-06-21 05:08:43 +00:00
GTK_PRINTER_OPTION_TYPE_BOOLEAN ) ;
2006-04-21 15:09:32 +00:00
g_free ( label ) ;
gtk_printer_option_allocate_choices ( option , 2 ) ;
option - > choices [ 0 ] = g_strdup ( " True " ) ;
option - > choices_display [ 0 ] = g_strdup ( " True " ) ;
2006-06-21 05:08:43 +00:00
option - > choices [ 1 ] = g_strdup ( " False " ) ;
option - > choices_display [ 1 ] = g_strdup ( " False " ) ;
2006-04-21 15:09:32 +00:00
gtk_printer_option_set ( option , ppd_option - > defchoice ) ;
}
# ifdef PRINT_IGNORED_OPTIONS
else
g_warning ( " Ignoring boolean %s \n " , ppd_option - > text ) ;
# endif
g_free ( available ) ;
return option ;
}
2006-06-16 18:29:09 +00:00
static gchar *
get_option_name ( const gchar * keyword )
2006-04-21 15:09:32 +00:00
{
int i ;
for ( i = 0 ; i < G_N_ELEMENTS ( option_names ) ; i + + )
if ( strcmp ( option_names [ i ] . ppd_keyword , keyword ) = = 0 )
return g_strdup ( option_names [ i ] . name ) ;
return g_strdup_printf ( " cups-%s " , keyword ) ;
}
static int
2006-06-16 18:29:09 +00:00
strptr_cmp ( const void * a ,
const void * b )
2006-04-21 15:09:32 +00:00
{
char * * aa = ( char * * ) a ;
char * * bb = ( char * * ) b ;
return strcmp ( * aa , * bb ) ;
}
static gboolean
2006-06-16 18:29:09 +00:00
string_in_table ( gchar * str ,
const gchar * table [ ] ,
gint table_len )
2006-04-21 15:09:32 +00:00
{
return bsearch ( & str , table , table_len , sizeof ( char * ) , ( void * ) strptr_cmp ) ! = NULL ;
}
# define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
static void
handle_option ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_option_t * ppd_option ,
ppd_group_t * toplevel_group ,
GtkPrintSettings * settings )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOption * option ;
char * name ;
2006-07-18 21:47:04 +00:00
2006-04-21 15:09:32 +00:00
if ( STRING_IN_TABLE ( ppd_option - > keyword , cups_option_blacklist ) )
return ;
2006-07-18 21:47:04 +00:00
name = get_option_name ( ppd_option - > keyword ) ;
2006-07-18 18:26:51 +00:00
2006-04-21 15:09:32 +00:00
option = NULL ;
if ( ppd_option - > ui = = PPD_UI_PICKONE )
{
2006-08-15 16:05:13 +00:00
option = create_pickone_option ( ppd_file , ppd_option , name ) ;
2006-04-21 15:09:32 +00:00
}
else if ( ppd_option - > ui = = PPD_UI_BOOLEAN )
{
option = create_boolean_option ( ppd_file , ppd_option , name ) ;
}
else
g_warning ( " Ignored pickmany setting %s \n " , ppd_option - > text ) ;
if ( option )
{
2006-10-03 15:05:05 +00:00
char * name ;
name = ppd_group_name ( toplevel_group ) ;
if ( STRING_IN_TABLE ( name ,
2006-04-21 15:09:32 +00:00
color_group_whitelist ) | |
STRING_IN_TABLE ( ppd_option - > keyword ,
color_option_whitelist ) )
{
option - > group = g_strdup ( " ColorPage " ) ;
}
2006-10-03 15:05:05 +00:00
else if ( STRING_IN_TABLE ( name ,
2006-04-21 15:09:32 +00:00
image_quality_group_whitelist ) | |
STRING_IN_TABLE ( ppd_option - > keyword ,
image_quality_option_whitelist ) )
{
option - > group = g_strdup ( " ImageQualityPage " ) ;
}
2006-10-03 15:05:05 +00:00
else if ( STRING_IN_TABLE ( name ,
2006-04-21 15:09:32 +00:00
finishing_group_whitelist ) | |
STRING_IN_TABLE ( ppd_option - > keyword ,
finishing_option_whitelist ) )
{
option - > group = g_strdup ( " FinishingPage " ) ;
}
else
{
option - > group = g_strdup ( toplevel_group - > text ) ;
}
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
}
g_free ( name ) ;
}
static void
handle_group ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_group_t * group ,
ppd_group_t * toplevel_group ,
GtkPrintSettings * settings )
2006-04-21 15:09:32 +00:00
{
2006-06-16 18:29:09 +00:00
gint i ;
2006-10-03 15:05:05 +00:00
gchar * name ;
2006-04-21 15:09:32 +00:00
/* Ignore installable options */
2006-10-03 15:05:05 +00:00
name = ppd_group_name ( toplevel_group ) ;
if ( strcmp ( name , " InstallableOptions " ) = = 0 )
2006-04-21 15:09:32 +00:00
return ;
for ( i = 0 ; i < group - > num_options ; i + + )
handle_option ( set , ppd_file , & group - > options [ i ] , toplevel_group , settings ) ;
for ( i = 0 ; i < group - > num_subgroups ; i + + )
handle_group ( set , ppd_file , & group - > subgroups [ i ] , toplevel_group , settings ) ;
}
static GtkPrinterOptionSet *
2006-06-21 05:56:14 +00:00
cups_printer_get_options ( GtkPrinter * printer ,
GtkPrintSettings * settings ,
GtkPageSetup * page_setup ,
GtkPrintCapabilities capabilities )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOptionSet * set ;
GtkPrinterOption * option ;
ppd_file_t * ppd_file ;
int i ;
char * print_at [ ] = { " now " , " at " , " on-hold " } ;
char * n_up [ ] = { " 1 " , " 2 " , " 4 " , " 6 " , " 9 " , " 16 " } ;
char * prio [ ] = { " 100 " , " 80 " , " 50 " , " 30 " } ;
char * prio_display [ ] = { N_ ( " Urgent " ) , N_ ( " High " ) , N_ ( " Medium " ) , N_ ( " Low " ) } ;
char * cover [ ] = { " none " , " classified " , " confidential " , " secret " , " standard " , " topsecret " , " unclassified " } ;
char * cover_display [ ] = { N_ ( " None " ) , N_ ( " Classified " ) , N_ ( " Confidential " ) , N_ ( " Secret " ) , N_ ( " Standard " ) , N_ ( " Top Secret " ) , N_ ( " Unclassified " ) , } ;
set = gtk_printer_option_set_new ( ) ;
/* Cups specific, non-ppd related settings */
option = gtk_printer_option_new ( " gtk-n-up " , " Pages Per Sheet " , GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
gtk_printer_option_choices_from_array ( option , G_N_ELEMENTS ( n_up ) ,
n_up , n_up ) ;
gtk_printer_option_set ( option , " 1 " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
for ( i = 0 ; i < G_N_ELEMENTS ( prio_display ) ; i + + )
prio_display [ i ] = _ ( prio_display [ i ] ) ;
option = gtk_printer_option_new ( " gtk-job-prio " , " Job Priority " , GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
gtk_printer_option_choices_from_array ( option , G_N_ELEMENTS ( prio ) ,
prio , prio_display ) ;
gtk_printer_option_set ( option , " 50 " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
option = gtk_printer_option_new ( " gtk-billing-info " , " Billing Info " , GTK_PRINTER_OPTION_TYPE_STRING ) ;
gtk_printer_option_set ( option , " " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
for ( i = 0 ; i < G_N_ELEMENTS ( cover_display ) ; i + + )
cover_display [ i ] = _ ( cover_display [ i ] ) ;
option = gtk_printer_option_new ( " gtk-cover-before " , " Before " , GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
gtk_printer_option_choices_from_array ( option , G_N_ELEMENTS ( cover ) ,
cover , cover_display ) ;
gtk_printer_option_set ( option , " none " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
option = gtk_printer_option_new ( " gtk-cover-after " , " After " , GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
gtk_printer_option_choices_from_array ( option , G_N_ELEMENTS ( cover ) ,
cover , cover_display ) ;
gtk_printer_option_set ( option , " none " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
option = gtk_printer_option_new ( " gtk-print-time " , " Print at " , GTK_PRINTER_OPTION_TYPE_PICKONE ) ;
gtk_printer_option_choices_from_array ( option , G_N_ELEMENTS ( print_at ) ,
print_at , print_at ) ;
gtk_printer_option_set ( option , " now " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
option = gtk_printer_option_new ( " gtk-print-time-text " , " Print at time " , GTK_PRINTER_OPTION_TYPE_STRING ) ;
gtk_printer_option_set ( option , " " ) ;
set_option_from_settings ( option , settings ) ;
gtk_printer_option_set_add ( set , option ) ;
g_object_unref ( option ) ;
/* Printer (ppd) specific settings */
ppd_file = gtk_printer_cups_get_ppd ( GTK_PRINTER_CUPS ( printer ) ) ;
if ( ppd_file )
{
GtkPaperSize * paper_size ;
ppd_option_t * option ;
2006-11-15 18:54:43 +00:00
const gchar * ppd_name ;
2006-06-21 18:16:58 +00:00
2006-04-21 15:09:32 +00:00
ppdMarkDefaults ( ppd_file ) ;
paper_size = gtk_page_setup_get_paper_size ( page_setup ) ;
2006-06-21 05:08:43 +00:00
option = ppdFindOption ( ppd_file , " PageSize " ) ;
2006-11-15 18:54:43 +00:00
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 ) ;
}
2006-04-21 15:09:32 +00:00
for ( i = 0 ; i < ppd_file - > num_groups ; i + + )
handle_group ( set , ppd_file , & ppd_file - > groups [ i ] , & ppd_file - > groups [ i ] , settings ) ;
}
return set ;
}
static void
mark_option_from_set ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_option_t * ppd_option )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOption * option ;
char * name = get_option_name ( ppd_option - > keyword ) ;
option = gtk_printer_option_set_lookup ( set , name ) ;
if ( option )
ppdMarkOption ( ppd_file , ppd_option - > keyword , option - > value ) ;
g_free ( name ) ;
}
static void
mark_group_from_set ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_group_t * group )
2006-04-21 15:09:32 +00:00
{
int i ;
for ( i = 0 ; i < group - > num_options ; i + + )
mark_option_from_set ( set , ppd_file , & group - > options [ i ] ) ;
for ( i = 0 ; i < group - > num_subgroups ; i + + )
mark_group_from_set ( set , ppd_file , & group - > subgroups [ i ] ) ;
}
static void
set_conflicts_from_option ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_option_t * ppd_option )
2006-04-21 15:09:32 +00:00
{
GtkPrinterOption * option ;
char * name ;
2006-06-21 05:08:43 +00:00
2006-04-21 15:09:32 +00:00
if ( ppd_option - > conflicted )
{
name = get_option_name ( ppd_option - > keyword ) ;
option = gtk_printer_option_set_lookup ( set , name ) ;
if ( option )
gtk_printer_option_set_has_conflict ( option , TRUE ) ;
else
g_warning ( " conflict for option %s ignored " , ppd_option - > keyword ) ;
g_free ( name ) ;
}
}
static void
set_conflicts_from_group ( GtkPrinterOptionSet * set ,
2006-06-16 18:29:09 +00:00
ppd_file_t * ppd_file ,
ppd_group_t * group )
2006-04-21 15:09:32 +00:00
{
int i ;
for ( i = 0 ; i < group - > num_options ; i + + )
set_conflicts_from_option ( set , ppd_file , & group - > options [ i ] ) ;
for ( i = 0 ; i < group - > num_subgroups ; i + + )
set_conflicts_from_group ( set , ppd_file , & group - > subgroups [ i ] ) ;
}
static gboolean
2006-06-21 05:56:14 +00:00
cups_printer_mark_conflicts ( GtkPrinter * printer ,
GtkPrinterOptionSet * options )
2006-04-21 15:09:32 +00:00
{
ppd_file_t * ppd_file ;
int num_conflicts ;
int i ;
ppd_file = gtk_printer_cups_get_ppd ( GTK_PRINTER_CUPS ( printer ) ) ;
if ( ppd_file = = NULL )
return FALSE ;
ppdMarkDefaults ( ppd_file ) ;
for ( i = 0 ; i < ppd_file - > num_groups ; i + + )
mark_group_from_set ( options , ppd_file , & ppd_file - > groups [ i ] ) ;
num_conflicts = ppdConflicts ( ppd_file ) ;
if ( num_conflicts > 0 )
{
for ( i = 0 ; i < ppd_file - > num_groups ; i + + )
set_conflicts_from_group ( options , ppd_file , & ppd_file - > groups [ i ] ) ;
}
return num_conflicts > 0 ;
}
struct OptionData {
GtkPrinter * printer ;
GtkPrinterOptionSet * options ;
GtkPrintSettings * settings ;
ppd_file_t * ppd_file ;
} ;
typedef struct {
const char * cups ;
const char * standard ;
} NameMapping ;
static void
2006-06-16 18:29:09 +00:00
map_settings_to_option ( GtkPrinterOption * option ,
const NameMapping table [ ] ,
gint n_elements ,
GtkPrintSettings * settings ,
const gchar * standard_name ,
const gchar * cups_name )
2006-04-21 15:09:32 +00:00
{
int i ;
char * name ;
const char * cups_value ;
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 ) ;
2006-06-21 05:08:43 +00:00
if ( cups_value ! = NULL )
{
gtk_printer_option_set ( option , cups_value ) ;
return ;
}
2006-04-21 15:09:32 +00:00
/* Otherwise we try to convert from the general setting */
standard_value = gtk_print_settings_get ( settings , standard_name ) ;
if ( standard_value = = NULL )
return ;
for ( i = 0 ; i < n_elements ; i + + )
{
if ( table [ i ] . cups = = NULL & & table [ i ] . standard = = NULL )
{
gtk_printer_option_set ( option , standard_value ) ;
break ;
}
else if ( table [ i ] . cups = = NULL & &
strcmp ( table [ i ] . standard , standard_value ) = = 0 )
{
set_option_off ( option ) ;
break ;
}
else if ( strcmp ( table [ i ] . standard , standard_value ) = = 0 )
{
gtk_printer_option_set ( option , table [ i ] . cups ) ;
break ;
}
}
}
static void
2006-06-16 18:29:09 +00:00
map_option_to_settings ( const gchar * value ,
const NameMapping table [ ] ,
gint n_elements ,
GtkPrintSettings * settings ,
const gchar * standard_name ,
const gchar * cups_name )
2006-04-21 15:09:32 +00:00
{
int i ;
char * name ;
for ( i = 0 ; i < n_elements ; i + + )
{
if ( table [ i ] . cups = = NULL & & table [ i ] . standard = = NULL )
{
gtk_print_settings_set ( settings ,
standard_name ,
value ) ;
break ;
}
else if ( table [ i ] . cups = = NULL & & table [ i ] . standard ! = NULL )
{
if ( value_is_off ( value ) )
{
gtk_print_settings_set ( settings ,
standard_name ,
table [ i ] . standard ) ;
break ;
}
}
else if ( strcmp ( table [ i ] . cups , value ) = = 0 )
{
gtk_print_settings_set ( settings ,
standard_name ,
table [ i ] . standard ) ;
break ;
}
}
/* Always set the corresponding cups-specific setting */
name = g_strdup_printf ( " cups-%s " , cups_name ) ;
gtk_print_settings_set ( settings , name , value ) ;
g_free ( name ) ;
}
static const NameMapping paper_source_map [ ] = {
{ " Lower " , " lower " } ,
{ " Middle " , " middle " } ,
{ " Upper " , " upper " } ,
{ " Rear " , " rear " } ,
{ " Envelope " , " envelope " } ,
{ " Cassette " , " cassette " } ,
{ " LargeCapacity " , " large-capacity " } ,
{ " AnySmallFormat " , " small-format " } ,
{ " AnyLargeFormat " , " large-format " } ,
{ NULL , NULL }
} ;
static const NameMapping output_tray_map [ ] = {
{ " Upper " , " upper " } ,
{ " Lower " , " lower " } ,
{ " Rear " , " rear " } ,
{ NULL , NULL }
} ;
static const NameMapping duplex_map [ ] = {
{ " DuplexTumble " , " vertical " } ,
{ " DuplexNoTumble " , " horizontal " } ,
{ NULL , " simplex " }
} ;
static const NameMapping output_mode_map [ ] = {
{ " Standard " , " normal " } ,
{ " Normal " , " normal " } ,
{ " Draft " , " draft " } ,
{ " Fast " , " draft " } ,
} ;
static const NameMapping media_type_map [ ] = {
{ " Transparency " , " transparency " } ,
{ " Standard " , " stationery " } ,
{ NULL , NULL }
} ;
static const NameMapping all_map [ ] = {
{ NULL , NULL }
} ;
static void
set_option_from_settings ( GtkPrinterOption * option ,
GtkPrintSettings * settings )
{
const char * cups_value ;
char * value ;
if ( settings = = NULL )
return ;
if ( strcmp ( option - > name , " gtk-paper-source " ) = = 0 )
map_settings_to_option ( option , paper_source_map , G_N_ELEMENTS ( paper_source_map ) ,
settings , GTK_PRINT_SETTINGS_DEFAULT_SOURCE , " InputSlot " ) ;
else if ( strcmp ( option - > name , " gtk-output-tray " ) = = 0 )
map_settings_to_option ( option , output_tray_map , G_N_ELEMENTS ( output_tray_map ) ,
settings , GTK_PRINT_SETTINGS_OUTPUT_BIN , " OutputBin " ) ;
else if ( strcmp ( option - > name , " gtk-duplex " ) = = 0 )
map_settings_to_option ( option , duplex_map , G_N_ELEMENTS ( duplex_map ) ,
settings , GTK_PRINT_SETTINGS_DUPLEX , " Duplex " ) ;
else if ( strcmp ( option - > name , " cups-OutputMode " ) = = 0 )
map_settings_to_option ( option , output_mode_map , G_N_ELEMENTS ( output_mode_map ) ,
settings , GTK_PRINT_SETTINGS_QUALITY , " OutputMode " ) ;
else if ( strcmp ( option - > name , " cups-Resolution " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , option - > name ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
else
{
int res = gtk_print_settings_get_resolution ( settings ) ;
if ( res ! = 0 )
{
value = g_strdup_printf ( " %ddpi " , res ) ;
gtk_printer_option_set ( option , value ) ;
g_free ( value ) ;
}
}
}
else if ( strcmp ( option - > name , " gtk-paper-type " ) = = 0 )
map_settings_to_option ( option , media_type_map , G_N_ELEMENTS ( media_type_map ) ,
settings , GTK_PRINT_SETTINGS_MEDIA_TYPE , " MediaType " ) ;
else if ( strcmp ( option - > name , " gtk-n-up " ) = = 0 )
{
map_settings_to_option ( option , all_map , G_N_ELEMENTS ( all_map ) ,
settings , GTK_PRINT_SETTINGS_NUMBER_UP , " number-up " ) ;
}
else if ( strcmp ( option - > name , " gtk-billing-info " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " cups-job-billing " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( strcmp ( option - > name , " gtk-job-prio " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " cups-job-priority " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( strcmp ( option - > name , " gtk-cover-before " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " cover-before " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( strcmp ( option - > name , " gtk-cover-after " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " cover-after " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( strcmp ( option - > name , " gtk-print-time " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " print-at " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( strcmp ( option - > name , " gtk-print-time-text " ) = = 0 )
{
cups_value = gtk_print_settings_get ( settings , " print-at-time " ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
else if ( g_str_has_prefix ( option - > name , " cups- " ) )
{
cups_value = gtk_print_settings_get ( settings , option - > name ) ;
if ( cups_value )
gtk_printer_option_set ( option , cups_value ) ;
}
}
static void
2006-06-16 18:29:09 +00:00
foreach_option_get_settings ( GtkPrinterOption * option ,
2006-04-21 15:09:32 +00:00
gpointer user_data )
{
struct OptionData * data = user_data ;
GtkPrintSettings * settings = data - > settings ;
const char * value ;
value = option - > value ;
if ( strcmp ( option - > name , " gtk-paper-source " ) = = 0 )
map_option_to_settings ( value , paper_source_map , G_N_ELEMENTS ( paper_source_map ) ,
settings , GTK_PRINT_SETTINGS_DEFAULT_SOURCE , " InputSlot " ) ;
else if ( strcmp ( option - > name , " gtk-output-tray " ) = = 0 )
map_option_to_settings ( value , output_tray_map , G_N_ELEMENTS ( output_tray_map ) ,
settings , GTK_PRINT_SETTINGS_OUTPUT_BIN , " OutputBin " ) ;
else if ( strcmp ( option - > name , " gtk-duplex " ) = = 0 )
map_option_to_settings ( value , duplex_map , G_N_ELEMENTS ( duplex_map ) ,
settings , GTK_PRINT_SETTINGS_DUPLEX , " Duplex " ) ;
else if ( strcmp ( option - > name , " cups-OutputMode " ) = = 0 )
map_option_to_settings ( value , output_mode_map , G_N_ELEMENTS ( output_mode_map ) ,
settings , GTK_PRINT_SETTINGS_QUALITY , " OutputMode " ) ;
else if ( strcmp ( option - > name , " cups-Resolution " ) = = 0 )
{
int res = atoi ( value ) ;
/* TODO: What if resolution is on XXXxYYYdpi form? */
if ( res ! = 0 )
gtk_print_settings_set_resolution ( settings , res ) ;
gtk_print_settings_set ( settings , option - > name , value ) ;
}
else if ( strcmp ( option - > name , " gtk-paper-type " ) = = 0 )
map_option_to_settings ( value , media_type_map , G_N_ELEMENTS ( media_type_map ) ,
settings , GTK_PRINT_SETTINGS_MEDIA_TYPE , " MediaType " ) ;
else if ( strcmp ( option - > name , " gtk-n-up " ) = = 0 )
map_option_to_settings ( value , all_map , G_N_ELEMENTS ( all_map ) ,
settings , GTK_PRINT_SETTINGS_NUMBER_UP , " number-up " ) ;
else if ( strcmp ( option - > name , " gtk-billing-info " ) = = 0 & & strlen ( value ) > 0 )
gtk_print_settings_set ( settings , " cups-job-billing " , value ) ;
else if ( strcmp ( option - > name , " gtk-job-prio " ) = = 0 )
gtk_print_settings_set ( settings , " cups-job-priority " , value ) ;
else if ( strcmp ( option - > name , " gtk-cover-before " ) = = 0 )
gtk_print_settings_set ( settings , " cover-before " , value ) ;
else if ( strcmp ( option - > name , " gtk-cover-after " ) = = 0 )
gtk_print_settings_set ( settings , " cover-after " , value ) ;
else if ( strcmp ( option - > name , " gtk-print-time " ) = = 0 )
gtk_print_settings_set ( settings , " print-at " , value ) ;
else if ( strcmp ( option - > name , " gtk-print-time-text " ) = = 0 )
gtk_print_settings_set ( settings , " print-at-time " , value ) ;
else if ( g_str_has_prefix ( option - > name , " cups- " ) )
gtk_print_settings_set ( settings , option - > name , value ) ;
}
static void
2006-06-16 18:29:09 +00:00
cups_printer_get_settings_from_options ( GtkPrinter * printer ,
2006-04-21 15:09:32 +00:00
GtkPrinterOptionSet * options ,
2006-06-16 18:29:09 +00:00
GtkPrintSettings * settings )
2006-04-21 15:09:32 +00:00
{
struct OptionData data ;
const char * print_at , * print_at_time ;
data . printer = printer ;
data . options = options ;
data . settings = settings ;
data . ppd_file = gtk_printer_cups_get_ppd ( GTK_PRINTER_CUPS ( printer ) ) ;
if ( data . ppd_file ! = NULL )
{
GtkPrinterOption * cover_before , * cover_after ;
gtk_printer_option_set_foreach ( options , foreach_option_get_settings , & data ) ;
cover_before = gtk_printer_option_set_lookup ( options , " gtk-cover-before " ) ;
cover_after = gtk_printer_option_set_lookup ( options , " gtk-cover-after " ) ;
if ( cover_before & & cover_after )
{
char * value = g_strdup_printf ( " %s,%s " , cover_before - > value , cover_after - > value ) ;
gtk_print_settings_set ( settings , " cups-job-sheets " , value ) ;
g_free ( value ) ;
}
print_at = gtk_print_settings_get ( settings , " print-at " ) ;
print_at_time = gtk_print_settings_get ( settings , " print-at-time " ) ;
if ( strcmp ( print_at , " at " ) = = 0 )
gtk_print_settings_set ( settings , " cups-job-hold-until " , print_at_time ) ;
else if ( strcmp ( print_at , " on-hold " ) = = 0 )
gtk_print_settings_set ( settings , " cups-job-hold-until " , " indefinite " ) ;
}
}
static void
2006-06-16 18:29:09 +00:00
cups_printer_prepare_for_print ( GtkPrinter * printer ,
GtkPrintJob * print_job ,
2006-04-21 15:09:32 +00:00
GtkPrintSettings * settings ,
2006-06-16 18:29:09 +00:00
GtkPageSetup * page_setup )
2006-04-21 15:09:32 +00:00
{
GtkPageSet page_set ;
GtkPaperSize * paper_size ;
const char * ppd_paper_name ;
double scale ;
print_job - > print_pages = gtk_print_settings_get_print_pages ( settings ) ;
print_job - > page_ranges = NULL ;
print_job - > num_page_ranges = 0 ;
if ( print_job - > print_pages = = GTK_PRINT_PAGES_RANGES )
print_job - > page_ranges =
gtk_print_settings_get_page_ranges ( settings ,
& print_job - > num_page_ranges ) ;
if ( gtk_print_settings_get_collate ( settings ) )
gtk_print_settings_set ( settings , " cups-Collate " , " True " ) ;
print_job - > collate = FALSE ;
if ( gtk_print_settings_get_reverse ( settings ) )
gtk_print_settings_set ( settings , " cups-OutputOrder " , " Reverse " ) ;
print_job - > reverse = FALSE ;
2006-05-12 09:47:58 +00:00
if ( gtk_print_settings_get_n_copies ( settings ) > 1 )
2006-04-21 15:09:32 +00:00
gtk_print_settings_set_int ( settings , " cups-copies " ,
2006-05-12 09:47:58 +00:00
gtk_print_settings_get_n_copies ( settings ) ) ;
2006-04-21 15:09:32 +00:00
print_job - > num_copies = 1 ;
scale = gtk_print_settings_get_scale ( settings ) ;
print_job - > scale = 1.0 ;
if ( scale ! = 100.0 )
print_job - > scale = scale / 100.0 ;
page_set = gtk_print_settings_get_page_set ( settings ) ;
if ( page_set = = GTK_PAGE_SET_EVEN )
gtk_print_settings_set ( settings , " cups-page-set " , " even " ) ;
else if ( page_set = = GTK_PAGE_SET_ODD )
gtk_print_settings_set ( settings , " cups-page-set " , " odd " ) ;
print_job - > page_set = GTK_PAGE_SET_ALL ;
paper_size = gtk_page_setup_get_paper_size ( page_setup ) ;
ppd_paper_name = gtk_paper_size_get_ppd_name ( paper_size ) ;
if ( ppd_paper_name ! = NULL )
gtk_print_settings_set ( settings , " cups-PageSize " , ppd_paper_name ) ;
else
{
char * 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 ) ) ;
gtk_print_settings_set ( settings , " cups-PageSize " , custom_name ) ;
g_free ( custom_name ) ;
}
print_job - > rotate_to_orientation = TRUE ;
}
static GList *
cups_printer_list_papers ( GtkPrinter * printer )
{
ppd_file_t * ppd_file ;
ppd_size_t * size ;
char * display_name ;
GtkPageSetup * page_setup ;
GtkPaperSize * paper_size ;
ppd_option_t * option ;
ppd_choice_t * choice ;
GList * l ;
int i ;
ppd_file = gtk_printer_cups_get_ppd ( GTK_PRINTER_CUPS ( printer ) ) ;
if ( ppd_file = = NULL )
return NULL ;
l = NULL ;
for ( i = 0 ; i < ppd_file - > num_sizes ; i + + )
{
size = & ppd_file - > sizes [ i ] ;
display_name = NULL ;
2006-06-21 05:08:43 +00:00
option = ppdFindOption ( ppd_file , " PageSize " ) ;
2006-04-21 15:09:32 +00:00
if ( option )
{
2006-06-21 05:08:43 +00:00
choice = ppdFindChoice ( option , size - > name ) ;
2006-04-21 15:09:32 +00:00
if ( choice )
display_name = ppd_text_to_utf8 ( ppd_file , choice - > text ) ;
}
if ( display_name = = NULL )
display_name = g_strdup ( size - > name ) ;
page_setup = gtk_page_setup_new ( ) ;
paper_size = gtk_paper_size_new_from_ppd ( size - > name ,
display_name ,
size - > width ,
size - > length ) ;
gtk_page_setup_set_paper_size ( page_setup , paper_size ) ;
gtk_paper_size_free ( paper_size ) ;
gtk_page_setup_set_top_margin ( page_setup , size - > length - size - > top , GTK_UNIT_POINTS ) ;
gtk_page_setup_set_bottom_margin ( page_setup , size - > bottom , GTK_UNIT_POINTS ) ;
gtk_page_setup_set_left_margin ( page_setup , size - > left , GTK_UNIT_POINTS ) ;
gtk_page_setup_set_right_margin ( page_setup , size - > width - size - > right , GTK_UNIT_POINTS ) ;
g_free ( display_name ) ;
l = g_list_prepend ( l , page_setup ) ;
}
return g_list_reverse ( l ) ;
}
static void
cups_printer_get_hard_margins ( GtkPrinter * printer ,
2006-06-16 18:29:09 +00:00
gdouble * top ,
gdouble * bottom ,
gdouble * left ,
gdouble * right )
2006-04-21 15:09:32 +00:00
{
ppd_file_t * ppd_file ;
ppd_file = gtk_printer_cups_get_ppd ( GTK_PRINTER_CUPS ( printer ) ) ;
if ( ppd_file = = NULL )
return ;
* left = ppd_file - > custom_margins [ 0 ] ;
* bottom = ppd_file - > custom_margins [ 1 ] ;
* right = ppd_file - > custom_margins [ 2 ] ;
* top = ppd_file - > custom_margins [ 3 ] ;
}
2006-05-24 10:50:57 +00:00
static GtkPrintCapabilities
cups_printer_get_capabilities ( GtkPrinter * printer )
{
return
GTK_PRINT_CAPABILITY_COPIES |
GTK_PRINT_CAPABILITY_COLLATE |
GTK_PRINT_CAPABILITY_REVERSE ;
}