Re: Speeding up the startup time of the print dialog (1/2)
- From: Matthias Clasen <mclasen redhat com>
- To: gnome-print-list gnome org
- Subject: Re: Speeding up the startup time of the print dialog (1/2)
- Date: Tue, 31 Aug 2004 12:37:07 -0400
On Fri, 2004-08-27 at 16:12, Matthias Clasen wrote:
> Here is the first of two patches to address these issues. It is
> against libgnomecups and does the following:
>
The libgnomecups patch had a couple of problems which prevented
it from working as intended. Here is an updated version.
Matthias
Index: libgnomecups/gnome-cups-printer.c
===================================================================
RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-printer.c,v
retrieving revision 1.26
diff -u -r1.26 gnome-cups-printer.c
--- libgnomecups/gnome-cups-printer.c 19 Aug 2004 20:46:19 -0000 1.26
+++ libgnomecups/gnome-cups-printer.c 31 Aug 2004 16:34:04 -0000
@@ -27,6 +27,8 @@
#include <cups/cups.h>
#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
#include "util.h"
#include "gnome-cups-request.h"
@@ -323,6 +325,185 @@
g_free (host);
}
+/*
+ * cups_get_dest() is copied from the cups libraries, file cups/dest.c,
+ * which is
+ * Copyright 1997-2004 by Easy Software Products.
+ */
+static int /* O - Number of destinations */
+cups_get_dests(const char *filename, /* I - File to read from */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int i; /* Looping var */
+ cups_dest_t *dest; /* Current destination */
+ FILE *fp; /* File pointer */
+ char line[8192], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *name, /* Name of destination/option */
+ *instance; /* Instance of destination */
+ const char *printer; /* PRINTER or LPDEST */
+
+
+ /*
+ * Check environment variables...
+ */
+
+ if ((printer = getenv("LPDEST")) == NULL)
+ if ((printer = getenv("PRINTER")) != NULL)
+ if (strcmp(printer, "lp") == 0)
+ printer = NULL;
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (num_dests);
+
+ /*
+ * Read each printer; each line looks like:
+ *
+ * Dest name[/instance] options
+ * Default name[/instance] options
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * See what type of line it is...
+ */
+
+ if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255))
+ lineptr = line + 4;
+ else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
+ lineptr = line + 7;
+ else
+ continue;
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ if (!*lineptr)
+ continue;
+
+ name = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
+ lineptr ++;
+
+ if (!*lineptr)
+ continue;
+
+ if (*lineptr == '/')
+ {
+ /*
+ * Found an instance...
+ */
+
+ *lineptr++ = '\0';
+ instance = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+ }
+ else
+ instance = NULL;
+
+ *lineptr++ = '\0';
+
+ /*
+ * See if the primary instance of the destination exists; if not,
+ * ignore this entry and move on...
+ */
+#if 0
+ /* Don't do this here, since we call this with an empty dests array */
+ if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
+ continue;
+#endif
+
+ /*
+ * Add the destination...
+ */
+
+ num_dests = cupsAddDest(name, instance, num_dests, dests);
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
+ {
+ /*
+ * Out of memory!
+ */
+
+ fclose(fp);
+ return (num_dests);
+ }
+
+ /*
+ * Add options until we hit the end of the line...
+ */
+
+ dest->num_options = cupsParseOptions(lineptr, dest->num_options,
+ &(dest->options));
+
+ /*
+ * Set this as default if needed...
+ */
+
+ if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
+ {
+ for (i = 0; i < num_dests; i ++)
+ (*dests)[i].is_default = 0;
+
+ dest->is_default = 1;
+ }
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ fclose(fp);
+
+ return (num_dests);
+}
+
+static int
+parse_lpoptions (cups_dest_t **dests)
+{
+ gchar *filename;
+ const gchar *home;
+ int num_dests;
+
+ num_dests = 0;
+ *dests = NULL;
+
+ home = g_getenv("CUPS_SERVERROOT");
+ if (!home)
+ home = "/etc/cups";
+ filename = g_build_filename (home, "lpoptions", NULL);
+ num_dests = cups_get_dests (filename, num_dests, dests);
+
+ g_free (filename);
+
+ filename = g_build_filename (g_get_home_dir (), ".lpoptions", NULL);
+ num_dests = cups_get_dests (filename, num_dests, dests);
+ g_free (filename);
+
+ return num_dests;
+}
+
static char *
get_default (void)
{
@@ -333,11 +514,11 @@
ipp_attribute_t *attr;
GError *error = NULL;
int num_dests;
- cups_dest_t *dests;
+ cups_dest_t *dests = NULL;
cups_dest_t *default_dest;
/* First look in the environment */
-
+
env = g_getenv ("LPDEST");
if (env) {
return g_strdup (env);
@@ -349,7 +530,7 @@
}
/* Then look in .lpoptions */
- num_dests = cupsGetDests (&dests);
+ num_dests = parse_lpoptions (&dests);
default_dest = cupsGetDest (NULL, NULL, num_dests, dests);
if (default_dest) {
name = g_strdup (default_dest->name);
@@ -580,7 +761,7 @@
} else if (!should_timeout && update_timeout_id) {
g_source_remove (update_timeout_id);
update_timeout_id = 0;
- }
+ }
}
guint
@@ -685,32 +866,6 @@
return NULL;
}
-static gboolean
-check_exists (const char *printer)
-{
- GError *error = NULL;
- ipp_t *request;
- ipp_t *response;
- char *printer_uri;
-
- request = gnome_cups_request_new (IPP_GET_PRINTER_ATTRIBUTES);
-
- printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", printer);
- ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
- "printer-uri", NULL, printer_uri);
- response = gnome_cups_request_execute (request, NULL, "/", &error);
- g_free (printer_uri);
-
- ippDelete (response);
-
- if (error) {
- g_error_free (error);
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
GnomeCupsPrinter *
gnome_cups_printer_get (const char *printer_name)
{
@@ -726,7 +881,7 @@
printer_name = default_printer;
}
- if (!check_exists (printer_name)) {
+ if (!name_in_list (printer_name, printer_names)) {
return NULL;
}
@@ -857,23 +1012,167 @@
return printer->details->full_state;
}
+static char *
+get_ppd_uri_path (GnomeCupsPrinter *printer)
+{
+ return g_strdup_printf ("/printers/%s.ppd", printer->details->printer_name);
+}
+
+static int
+get_tmp_ppd_file (GnomeCupsPrinter *printer,
+ char **filename,
+ GError **error)
+{
+ int fd;
+ char *tmpname;
+ char *tmp_filename;
+
+ tmpname = gnome_cups_util_escape_uri_string (printer->details->printer_name, GNOME_CUPS_UNSAFE_ALL);
+ tmp_filename = g_strdup_printf ("%s-printer-ppd-%s-XXXXXX",
+ g_get_user_name (),
+ tmpname);
+ g_free (tmpname);
+ fd = g_file_open_tmp (tmp_filename, filename, error);
+ g_free (tmp_filename);
+ return fd;
+}
+
+static GHashTable *get_ppd_options (GnomeCupsPrinter *printer, ppd_file_t *ppd);
+
ppd_file_t *
gnome_cups_printer_get_ppd (GnomeCupsPrinter *printer)
{
- const char *filename;
+ GError *error = NULL;
+ int fd;
+ char *host;
+ char *ppdpath;
+ char *filename;
ppd_file_t *ppd;
g_return_val_if_fail (GNOME_CUPS_IS_PRINTER (printer), NULL);
- filename = cupsGetPPD (printer->details->printer_name);
+ fd = get_tmp_ppd_file (printer, &filename, &error);
+ if (error != NULL) {
+ g_warning ("Couldn't create temporary file: %s",
+ error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ host = _gnome_cups_printer_get_host (printer);
+ ppdpath = get_ppd_uri_path (printer);
+
+ gnome_cups_request_file (host, ppdpath, fd, &error);
+ if (error != NULL) {
+ g_warning ("Couldn't retrieve PPD for %s: %s",
+ printer->details->printer_name,
+ error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ close (fd);
ppd = ppdOpenFile (filename);
+ g_free (filename);
/* This is loaded in to memory now, so we can free it. */
unlink (filename);
+ if (!printer->details->ppd_options)
+ printer->details->ppd_options = get_ppd_options (printer, ppd);
+
return ppd;
}
+typedef struct
+{
+ GnomeCupsPrinter *printer;
+ GnomeCupsPrinterGetPPDCallback cb;
+ gpointer user_data;
+ GDestroyNotify destroy_notify;
+ char *filename;
+ int fd;
+} GnomeCupsPrinterGetPPDWrapData;
+
+static void
+free_get_ppd_wrapper_data (gpointer p)
+{
+ GnomeCupsPrinterGetPPDWrapData *data = p;
+ g_object_unref (data->printer);
+ unlink (data->filename);
+ g_free (data->filename);
+ if (data->destroy_notify)
+ data->destroy_notify (data->user_data);
+ close (data->fd);
+ g_free (data);
+}
+
+static void
+wrap_ppd_request_cb (guint id,
+ const char *path,
+ ipp_t *response,
+ GError **error,
+ gpointer cb_data)
+{
+ GnomeCupsPrinterGetPPDWrapData *data = cb_data;
+ ppd_file_t *ppd;
+
+ if (error && *error != NULL) {
+ data->cb (id, NULL, error, data->user_data);
+ g_clear_error (error);
+ } else {
+ ppd = ppdOpenFile (data->filename);
+ if (!data->printer->details->ppd_options)
+ data->printer->details->ppd_options =
+ get_ppd_options (data->printer, ppd);
+
+ data->cb (id, ppd, NULL, data->user_data);
+ }
+}
+
+guint
+gnome_cups_printer_get_ppd_async (GnomeCupsPrinter *printer,
+ GnomeCupsPrinterGetPPDCallback cb,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ GError *error = NULL;
+ guint opid;
+ int fd;
+ char *host;
+ char *ppdpath;
+ char *filename;
+ GnomeCupsPrinterGetPPDWrapData *data;
+
+ g_return_val_if_fail (GNOME_CUPS_IS_PRINTER (printer), 0);
+
+ fd = get_tmp_ppd_file (printer, &filename, &error);
+ if (error != NULL) {
+ g_warning ("Couldn't create temporary file: %s",
+ error->message);
+ g_error_free (error);
+ return 0;
+ }
+
+ host = _gnome_cups_printer_get_host (printer);
+ ppdpath = get_ppd_uri_path (printer);
+
+ data = g_new0 (GnomeCupsPrinterGetPPDWrapData, 1);
+ data->printer = g_object_ref (printer);
+ data->filename = filename;
+ data->fd = fd;
+ data->cb = cb;
+ data->user_data = user_data;
+ data->destroy_notify = destroy_notify;
+
+ opid = gnome_cups_request_file_async (host, ppdpath, fd,
+ wrap_ppd_request_cb,
+ data,
+ free_get_ppd_wrapper_data);
+ g_free (ppdpath);
+ return opid;
+}
+
const char *
gnome_cups_printer_get_device_uri (GnomeCupsPrinter const *printer)
{
@@ -1091,9 +1390,9 @@
}
static GHashTable *
-get_ppd_options (GnomeCupsPrinter *printer)
+get_ppd_options (GnomeCupsPrinter *printer,
+ ppd_file_t *ppd)
{
- ppd_file_t *ppd;
int i;
GHashTable *options;
@@ -1101,7 +1400,6 @@
NULL,
(GDestroyNotify)gnome_cups_printer_option_free);
- ppd = gnome_cups_printer_get_ppd (printer);
if (!ppd)
return options;
@@ -1116,7 +1414,6 @@
g_hash_table_insert (options, option->id, option);
}
}
- ppdClose (ppd);
return options;
}
@@ -1124,40 +1421,43 @@
static GHashTable *
get_dest_options (GnomeCupsPrinter *printer)
{
- GHashTable *dest_options;
- int num_dests;
- cups_dest_t *dests;
+ int num_dests, i;
cups_dest_t *dest;
-
- dest_options = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
+ cups_dest_t *dests = NULL;
+ GHashTable *dest_options;
- num_dests = cupsGetDests (&dests);
+ /* just parse lpoptions */
+ num_dests = parse_lpoptions (&dests);
- dest = cupsGetDest (printer->details->printer_name, NULL,
- num_dests, dests);
+ dest = cupsGetDest (printer->details->printer_name, NULL, num_dests, dests);
+ dest_options = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+
if (dest) {
- int i;
for (i = 0; i < dest->num_options; i++) {
g_hash_table_insert (dest_options,
g_strdup (dest->options[i].name),
g_strdup (dest->options[i].value));
}
}
+ printer->details->options_invalid = FALSE;
cupsFreeDests (num_dests, dests);
- printer->details->options_invalid = FALSE;
-
return dest_options;
}
static void
update_options (GnomeCupsPrinter *printer)
-{
+{
if (!printer->details->ppd_options) {
- printer->details->ppd_options = get_ppd_options (printer);
+ ppd_file_t *ppd;
+
+ ppd = gnome_cups_printer_get_ppd (printer);
+
+ if (ppd)
+ ppdClose (ppd);
}
if (printer->details->options_invalid) {
@@ -1233,6 +1533,10 @@
return ret;
}
+
+extern int cups_get_dests(const char *filename, int num_dests,
+ cups_dest_t **dests);
+
GnomeCupsPrinterOption *
gnome_cups_printer_get_option (GnomeCupsPrinter *printer,
Index: libgnomecups/gnome-cups-printer.h
===================================================================
RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-printer.h,v
retrieving revision 1.11
diff -u -r1.11 gnome-cups-printer.h
--- libgnomecups/gnome-cups-printer.h 19 Aug 2004 20:46:19 -0000 1.11
+++ libgnomecups/gnome-cups-printer.h 31 Aug 2004 16:34:04 -0000
@@ -29,6 +29,9 @@
gpointer user_data);
typedef void (*GnomeCupsPrinterRemovedCallback) (const char *name,
gpointer user_data);
+typedef void (*GnomeCupsPrinterGetPPDCallback) (guint id, ppd_file_t *ppd,
+ GError **error,
+ gpointer user_data);
struct _GnomeCupsPrinter {
GObject parent;
@@ -150,6 +153,10 @@
/* Configuration */
ppd_file_t * gnome_cups_printer_get_ppd (GnomeCupsPrinter *printer);
+guint gnome_cups_printer_get_ppd_async (GnomeCupsPrinter *printer,
+ GnomeCupsPrinterGetPPDCallback cb,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
char * gnome_cups_printer_get_option_value (GnomeCupsPrinter *printer,
const char *id);
void gnome_cups_printer_set_option_value (GnomeCupsPrinter *printer,
Index: libgnomecups/gnome-cups-request.c
===================================================================
RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-request.c,v
retrieving revision 1.18
diff -u -r1.18 gnome-cups-request.c
--- libgnomecups/gnome-cups-request.c 25 Aug 2004 02:19:23 -0000 1.18
+++ libgnomecups/gnome-cups-request.c 31 Aug 2004 16:34:04 -0000
@@ -3,6 +3,7 @@
#include <glib.h>
#include <stdlib.h>
+#include <stdio.h>
#include <cups/cups.h>
#include <cups/language.h>
#include <cups/http.h>
@@ -41,12 +42,19 @@
ipp_t *request;
char *path;
+ int output_fd;
} GnomeCupsRequest;
static void request_thread_main (GnomeCupsRequest *request, gpointer unused);
+static ipp_t * gnome_cups_request_execute_sync_internal (ipp_t *request,
+ const char *server,
+ const char *path,
+ int output_fd,
+ GError **error);
static guint gnome_cups_request_execute_async_internal (ipp_t *request,
const char *server,
const char *path,
+ int output_fd,
gboolean direct_callback,
GnomeCupsAsyncRequestCallback callback,
gpointer cb_data,
@@ -227,7 +235,7 @@
g_static_mutex_unlock (&request_mutex);
return TRUE;
}
-
+
static gboolean
close_unused_connection (const char *server,
GnomeCupsConnection *connection,
@@ -291,14 +299,15 @@
static gboolean
idle_signal_request_complete (GnomeCupsRequest *request)
{
- if (!request->cancelled && request->callback)
+ if (!request->cancelled && request->callback) {
request->callback (request->id,
request->path,
request->response,
request->error,
request->cb_data);
- else {
- ippDelete (request->response);
+ } else {
+ if (request->response)
+ ippDelete (request->response);
}
g_static_mutex_lock (&request_mutex);
@@ -326,7 +335,6 @@
request_thread_main (GnomeCupsRequest *request,
gpointer unused)
{
- ipp_t *response;
ipp_status_t status;
if (request->cancelled) {
@@ -343,16 +351,24 @@
request->connection->http = httpConnectEncrypt (request->connection->server, ippPort(), cupsEncryption());
- response = cupsDoRequest (request->connection->http, request->request,
- request->path);
-
- /* FIXME - not currently threadsafe, but cups returns NULL on
- * any error. Thus we just set the status to an internal error
- * for now.
- */
- status = cupsLastError ();
- if (response == NULL)
- status = IPP_INTERNAL_ERROR;
+ if (request->request) {
+ request->response = cupsDoRequest (request->connection->http, request->request,
+ request->path);
+ /* FIXME - not currently threadsafe, but cups returns NULL on
+ * any error. Thus we just set the status to an internal error
+ * for now.
+ */
+ status = cupsLastError ();
+ if (request->response == NULL)
+ status = IPP_INTERNAL_ERROR;
+ } else if (request->output_fd >= 0) {
+ status = cupsGetFd(request->connection->http, request->path, request->output_fd);
+ request->response = NULL;
+ }
+ else {
+ status = IPP_INTERNAL_ERROR;
+ g_warning ("Neither request nor output_fd set\n");
+ }
g_atomic_int_dec_and_test (&request->connection->refcount);
g_mutex_unlock (request->connection->mutex);
@@ -363,7 +379,6 @@
get_error_string (status));
}
- request->response = response;
do_signal_complete (request);
return;
@@ -497,6 +512,33 @@
ipp_t *
gnome_cups_request_execute (ipp_t *request, const char *server, const char *path, GError **err)
{
+ return gnome_cups_request_execute_sync_internal (request, server, path, -1, err);
+}
+
+/**
+ * gnome_cups_request_file:
+ * @server: The hostname of the IPP server to connect to
+ * @path: The URI of the file to retrieve
+ * @output_fd: The file descriptor to which to write the retrieved file
+ * @err: A #GError for storing errors
+ *
+ * Retrieve the file named by @path via IPP, writing * the data to @output_fd.
+ **/
+void
+gnome_cups_request_file (const char *server, const char *path,
+ int output_fd,
+ GError **err)
+{
+ (void) gnome_cups_request_execute_sync_internal (NULL, server, path, output_fd, err);
+}
+
+static ipp_t *
+gnome_cups_request_execute_sync_internal (ipp_t *request,
+ const char *server,
+ const char *path,
+ int output_fd,
+ GError **err)
+{
guint id;
GnomeCupsAsyncWrapperData data;
@@ -507,7 +549,7 @@
data.error = err;
id = gnome_cups_request_execute_async_internal (request, server, path,
- TRUE,
+ output_fd, TRUE,
async_wrapper_cb,
&data,
NULL);
@@ -520,7 +562,7 @@
g_mutex_free (data.mutex);
g_cond_free (data.cond);
-
+
return data.response;
}
@@ -546,15 +588,44 @@
GDestroyNotify destroy_notify)
{
return gnome_cups_request_execute_async_internal (request, server,
- path, FALSE,
- callback, cb_data,
- destroy_notify);
+ path, -1,
+ FALSE, callback,
+ cb_data, destroy_notify);
+}
+
+/**
+ * gnome_cups_request_file_async:
+ * @server: The hostname of the IPP server to connect to
+ * @path: The URI of the file to retrieve
+ * @output_fd: The file descriptor to which to write the retrieved file
+ * @callback: A #GnomeCupsAsyncRequestCallback.
+ * @cb_data: Data for the callback
+ * @destroy_notify: A function to free the callback data
+ * @returns: an operation ID, suitable for passing to gnome_cups_request_cancel
+ *
+ * Creates a new asynchronous IPP request to retrieve the specified file, which will
+ * invoke @cb_data when complete. Note that the "response" parameter of the callback
+ * will always be #NULL.
+ **/
+guint
+gnome_cups_request_file_async (const char *server,
+ const char *path,
+ int output_fd,
+ GnomeCupsAsyncRequestCallback callback,
+ gpointer cb_data,
+ GDestroyNotify destroy_notify)
+{
+ return gnome_cups_request_execute_async_internal (NULL, server,
+ path, output_fd,
+ FALSE, callback,
+ cb_data, destroy_notify);
}
static guint
gnome_cups_request_execute_async_internal (ipp_t *request,
const char *server,
const char *path,
+ int output_fd,
gboolean direct_callback,
GnomeCupsAsyncRequestCallback callback,
gpointer cb_data,
@@ -593,6 +664,7 @@
req->cb_data = cb_data;
req->destroy_notify = destroy_notify;
req->path = g_strdup (path);
+ req->output_fd = output_fd;
req->direct_callback = direct_callback;
req->error = NULL;
Index: libgnomecups/gnome-cups-request.h
===================================================================
RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-request.h,v
retrieving revision 1.9
diff -u -r1.9 gnome-cups-request.h
--- libgnomecups/gnome-cups-request.h 13 Aug 2004 21:17:54 -0000 1.9
+++ libgnomecups/gnome-cups-request.h 31 Aug 2004 16:34:04 -0000
@@ -38,9 +38,19 @@
const char *server,
const char *path,
GError **err);
+void gnome_cups_request_file (const char *server,
+ const char *path,
+ int fd,
+ GError **err);
guint gnome_cups_request_execute_async (ipp_t *request,
- const char *server,
+ const char *server,
+ const char *path,
+ GnomeCupsAsyncRequestCallback callback,
+ gpointer cb_data,
+ GDestroyNotify destroy_notify);
+guint gnome_cups_request_file_async (const char *server,
const char *path,
+ int outfile_fd,
GnomeCupsAsyncRequestCallback callback,
gpointer cb_data,
GDestroyNotify destroy_notify);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]