Howdy everyone,

attached goes a patch adding gnome_vfs_async support to gnome-python.
The actual code goes in vfs-async-handle.c, also attached [1].

Short description (please ask for clarification if needed, comments are
welcome):
All new functionality lives under gnome.vfs.async, have a look to the
attached example to see usage of the wrapper.
Most gnome_vfs_async_* stuff is wrapped, exceptions being:
- set_file_info: Requires major gnome.vfs.FileInfo surgery.
- [open|create]_as_stream: Requires GIOChannel wrappers not yet written
AFAICS.
- async_xfer, find_directory, file_control: I'm lazy, but the current
gnome-python wrappers don't include the sync versions either. It
shouldn't be difficult in case someone desperately needs it, just ask
for it.

The api for the wrappers is straightforward, it follows the order of the
C api except for the callback parameter, which gets promoted to being
the last required arg, and the handle, which disappears. I.e.:
C: open(handle, uri, open_mode, priority, callback, data)
becomes
Python: open(uri, callback [, open_mode, priority, data])

Callback signatures can be seen in the attached example.

Is this the proper place to post this, or should I open a bugzilla entry
too?

Enjoy,
Iñaki

[1] Does anyone know how to make cvs diff produce a patch that includes
files not in the remote repository? -RuN doesn't appear to do what I
want.
? vfs-async-handle.c
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-python/gnome-python/gnome/Makefile.am,v
retrieving revision 1.30
diff -u -r1.30 Makefile.am
--- Makefile.am 24 Aug 2003 14:02:52 -0000      1.30
+++ Makefile.am 6 Sep 2003 13:53:45 -0000
@@ -71,7 +71,7 @@
 vfs_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initvfs
 vfs_la_LIBADD = $(GNOMEVFS_LIBS)
 vfs_la_SOURCES = vfsmodule.c vfs-uri.c vfs-file-info.c vfs-dir-handle.c \
- vfs-handle.c pygnomevfs.h pygnomevfs-private.h
+ vfs-handle.c vfs-async-handle.c pygnomevfs.h pygnomevfs-private.h
 
 # libzvt binding
 
Index: pygnomevfs-private.h
===================================================================
RCS file: /cvs/gnome/gnome-python/gnome-python/gnome/pygnomevfs-private.h,v
retrieving revision 1.1
diff -u -r1.1 pygnomevfs-private.h
--- pygnomevfs-private.h        29 Apr 2003 23:35:30 -0000      1.1
+++ pygnomevfs-private.h        6 Sep 2003 13:53:46 -0000
@@ -55,6 +55,9 @@
 #define pygnome_vfs_handle_get(v) (((PyGnomeVFSHandle *)(v))->fd)
 PyObject *pygnome_vfs_handle_new(GnomeVFSHandle *fd);
 
+/* vfs-async-handle.c */
+PyObject *pygvfs_async_module_init (void);
+
 typedef struct {
     PyObject *func, *data;
 } PyGVFSCustomNotify;
Index: vfsmodule.c
===================================================================
RCS file: /cvs/gnome/gnome-python/gnome-python/gnome/vfsmodule.c,v
retrieving revision 1.11
diff -u -r1.11 vfsmodule.c
--- vfsmodule.c 24 Aug 2003 14:02:52 -0000      1.11
+++ vfsmodule.c 6 Sep 2003 13:53:48 -0000
@@ -973,6 +973,8 @@
                         (PyObject *)&PyGnomeVFSDirectoryHandle_Type);
     PyDict_SetItemString(d, "Handle", (PyObject *)&PyGnomeVFSHandle_Type);
 
+    PyDict_SetItemString(d, "async", pygvfs_async_module_init ());
+
     PyDict_SetItemString(d, "open_directory",
                         (PyObject *)&PyGnomeVFSDirectoryHandle_Type);
     PyDict_SetItemString(d, "open", (PyObject *)&PyGnomeVFSHandle_Type);
/* -*- mode: C; c-basic-offset: 4 -*- */
#include <pygobject.h>
#include "pygnomevfs-private.h"
#include <libgnomevfs/gnome-vfs-async-ops.h>
#include <libgnomevfs/gnome-vfs-job-limit.h>

typedef struct {
    PyObject_HEAD;
    GnomeVFSAsyncHandle *fd;
} PyGnomeVFSAsyncHandle;
extern PyTypeObject PyGnomeVFSAsyncHandle_Type;

static PyObject *
pygnome_vfs_async_handle_new(GnomeVFSAsyncHandle *fd)
{
    PyGnomeVFSAsyncHandle *self;

    self = PyObject_NEW(PyGnomeVFSAsyncHandle, &PyGnomeVFSAsyncHandle_Type);
    if (self == NULL) return NULL;

    self->fd = fd;

    return (PyObject *)self;
}

static void
async_pass (void)
{
}

/* Get the exception in case any error has occured. Return 1 in case
   any error happened. */
static PyObject *
fetch_exception (GnomeVFSResult result, gboolean *error_happened)
{
    PyObject *retval;

    if (pygnome_vfs_result_check(result)) {
	retval = PyErr_Occurred();
	if (error_happened)
	    *error_happened = TRUE;
    } else {
	retval = Py_None;
	if (error_happened)
	    *error_happened = FALSE;
    }

    Py_INCREF (retval);
    PyErr_Clear ();

    return retval;
}

static void
pygvhandle_dealloc(PyGnomeVFSAsyncHandle *self)
{
    /* XXXX: unblock threads here */
    if (self->fd) {
	gnome_vfs_async_close(self->fd,
			      (GnomeVFSAsyncCloseCallback)async_pass, NULL);
    }

    PyObject_FREE(self);
}

typedef struct {
    PyObject *func, *data;
    PyGnomeVFSAsyncHandle *self;
    enum {
	ASYNC_NOTIFY_OPEN,
	ASYNC_NOTIFY_READ,
	ASYNC_NOTIFY_WRITE,
	ASYNC_NOTIFY_CLOSE,
	ASYNC_NOTIFY_G_INFO,
	ASYNC_NOTIFY_LOAD_DIRECTORY,
	ASYNC_NOTIFY_CREATE,
	ASYNC_NOTIFY_CREATE_SYMLINK
    } origin;
    PyObject *extra;
} PyGVFSAsyncNotify;

static PyGVFSAsyncNotify *
async_notify_new (PyObject *func, void *self,
		  PyObject *data, int origin)
{
    PyGVFSAsyncNotify *result = g_new0(PyGVFSAsyncNotify, 1);

    result->func = func;
    result->self = (PyGnomeVFSAsyncHandle *)self;
    result->data = data;
    result->origin = origin;

    Py_INCREF (func);
    Py_INCREF ((PyGnomeVFSAsyncHandle*)self);
    Py_XINCREF (data);

    return result;
}

static void
async_notify_free (PyGVFSAsyncNotify *notify)
{
    Py_DECREF (notify->func);
    Py_DECREF (notify->self);
    Py_XDECREF(notify->data);
    Py_XDECREF(notify->extra);

    g_free (notify);
}

/* Remember to decref the returned object after using it */
static GnomeVFSURI *
_object_to_uri (const char *name, PyObject *uri)
{
    if (PyObject_TypeCheck(uri, &PyGnomeVFSURI_Type)) {
	return gnome_vfs_uri_ref (pygnome_vfs_uri_get (uri));
    } else if (PyString_Check (uri)) {
	GnomeVFSURI *c_uri = gnome_vfs_uri_new (PyString_AsString (uri));
	if (c_uri == NULL)
	    PyErr_SetString(PyExc_TypeError, "Cannot build a gnome.vfs.URI");
	return c_uri;
    } else {
	gchar * buffer =
	    g_strdup_printf ("'%s' must be a gnome.vfs.URI or a string",
			     name);
	PyErr_SetString(PyExc_TypeError, buffer);
	g_free (buffer);
    }
    return NULL;
}

#define object_to_uri(OBJECT) _object_to_uri(#OBJECT, OBJECT)

static int
pygvhandle_init(PyGnomeVFSAsyncHandle *self, PyObject *args, PyObject *kwargs)
{
    return 0;
}

static void
callback_marshal (GnomeVFSAsyncHandle *handle,
		  GnomeVFSResult result,
		  PyGVFSAsyncNotify *notify)
{
    PyObject *retobj;
    PyObject *exception;
    gboolean error_happened;

    pyg_block_threads ();

    exception = fetch_exception (result, &error_happened);
    if (error_happened &&
	(notify->origin == ASYNC_NOTIFY_OPEN ||
	 notify->origin == ASYNC_NOTIFY_CREATE)) {
	notify->self->fd = NULL;
    }

    if (notify->origin == ASYNC_NOTIFY_CREATE_SYMLINK)
	notify->self->fd = NULL;

    if (notify->data)
	retobj = PyEval_CallFunction (notify->func, "(OOO)",
				      notify->self,
				      exception,
				      notify->data);
    else
	retobj = PyObject_CallFunction (notify->func, "(OO)",
					notify->self,
					exception);
    
    if (retobj == NULL) {
	PyErr_Print();
	PyErr_Clear();
    }

    Py_XDECREF (retobj);
    Py_DECREF (exception);
    
    async_notify_free (notify);
    
    pyg_unblock_threads ();
}

static PyObject*
pygvfs_async_open(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "uri", "callback", "open_mode", "priority",
			      "data", NULL };
    PyObject *uri;
    GnomeVFSOpenMode open_mode = GNOME_VFS_OPEN_READ;
    PyObject *callback;
    PyObject *data = NULL;
    int priority = GNOME_VFS_PRIORITY_DEFAULT;
    PyObject *pyself;
    GnomeVFSURI *c_uri;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OO|iiO:gnome.vfs.async.open",
				     kwlist, &uri, &callback, &open_mode,
				     &priority, &data))
	return NULL;

    /* XXXX: unblock threads here */

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }

    c_uri = object_to_uri (uri);
    if (c_uri == NULL)
	return NULL;

    pyself = pygnome_vfs_async_handle_new (NULL);

    gnome_vfs_async_open_uri(&((PyGnomeVFSAsyncHandle*)pyself)->fd,
			     c_uri,
			     open_mode,
			     priority,
			     (GnomeVFSAsyncOpenCallback)callback_marshal,
			     async_notify_new (callback, pyself, data,
					       ASYNC_NOTIFY_OPEN));

    gnome_vfs_uri_unref (c_uri);

    return pyself;
}

static PyObject*
pygvhandle_close(PyGnomeVFSAsyncHandle *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "callback", "data", NULL };
    PyObject *callback;
    PyObject *data = NULL;
    
    if (!self->fd) {
	PyErr_SetString(PyExc_ValueError, "I/O operation on closed handle");
	return NULL;
    }

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "O|O:gnome.vfs.async.Handle.close",
				     kwlist, &callback, &data))
	return NULL;

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }
    
    gnome_vfs_async_close(self->fd,
			  (GnomeVFSAsyncCloseCallback)callback_marshal,
			  async_notify_new (callback, self, data,
					    ASYNC_NOTIFY_CLOSE));

    self->fd = NULL;

    Py_INCREF (Py_None);
    return Py_None;
}

static void
read_write_marshal (GnomeVFSAsyncHandle *handle,
		    GnomeVFSResult result,
		    gpointer buffer,
		    GnomeVFSFileSize requested,
		    GnomeVFSFileSize done,
		    PyGVFSAsyncNotify *notify)
{
    PyObject *retobj;
    PyObject *pyvalue;
    PyObject *exception;
    gboolean error_happened;

    pyg_block_threads ();

    exception = fetch_exception (result, &error_happened);

    if (notify->origin == ASYNC_NOTIFY_READ)
	pyvalue = PyString_FromStringAndSize (buffer, done);
    else
	pyvalue = PyInt_FromLong (done);

    if (notify->data)
	retobj = PyEval_CallFunction (notify->func, "(OOOO)",
				      notify->self,
				      pyvalue,
				      exception,
				      notify->data);
    else
	retobj = PyObject_CallFunction (notify->func, "(OOO)",
					notify->self,
					pyvalue,
					exception);

    if (retobj == NULL) {
	PyErr_Print();
	PyErr_Clear();
    }

    Py_XDECREF (retobj);
    Py_DECREF (pyvalue);
    Py_DECREF (exception);

    if (notify->origin == ASYNC_NOTIFY_READ)
	g_free (buffer);
    else
	Py_DECREF (notify->extra);

    async_notify_free (notify);
  
    pyg_unblock_threads ();
}

static PyObject*
pygvhandle_read (PyGnomeVFSAsyncHandle *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "bytes", "callback", "data", NULL };
    glong bytes;
    PyObject *data = NULL;
    PyObject *callback;

    if (!self->fd) {
	PyErr_SetString(PyExc_ValueError, "I/O operation on closed handle");
	return NULL;
    }

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "lO|O:gnome.vfs.async.Handle.read",
				     kwlist, &bytes, &callback, &data))
	return NULL;

    if (!PyCallable_Check(callback)) {
        PyErr_SetString(PyExc_TypeError, "third argument not callable");
        return NULL;
    }

    gnome_vfs_async_read (self->fd, g_malloc(bytes), bytes,
			  (GnomeVFSAsyncReadCallback)read_write_marshal,
			  async_notify_new (callback, self, data,
					    ASYNC_NOTIFY_READ));

    Py_INCREF (Py_None);
    return Py_None;
}

static PyObject*
pygvhandle_write (PyGnomeVFSAsyncHandle *self,
		  PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "buffer", "callback", "data", NULL };
    PyObject *buffer;
    PyObject *data = NULL;
    PyObject *callback;
    PyGVFSAsyncNotify *notify;

    if (!self->fd) {
	PyErr_SetString(PyExc_ValueError, "I/O operation on closed handle");
	return NULL;
    }

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OO|O:gnome.vfs.async.Handle.read",
				     kwlist, &buffer, &callback, &data))
	return NULL;

    if (!PyCallable_Check(callback)) {
        PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
        return NULL;
    }

    if (!PyString_Check(buffer)) {
	PyErr_SetString(PyExc_TypeError, "'buffer' must be a string object");
	return NULL;
    }

    Py_INCREF (buffer);
    notify = async_notify_new (callback, self, data, ASYNC_NOTIFY_WRITE);
    notify->extra = buffer;
    gnome_vfs_async_write (self->fd, PyString_AsString(buffer),
			   PyString_Size (buffer),
			   (GnomeVFSAsyncWriteCallback)read_write_marshal,
			   notify);

    Py_INCREF (Py_None);
    return Py_None;
}

static void
get_info_marshal (GnomeVFSAsyncHandle *handle,
		  GList *results,
		  PyGVFSAsyncNotify *notify)
{
    PyObject *retobj;
    PyObject *pyresults; /* a list of (uri, exception, info) tuples */
    gint length;
    gint i;

    pyg_block_threads ();

    notify->self->fd = NULL;

    length = g_list_length (results);
    pyresults = PyList_New (length);

    for (i=0; i<length; i++, results = results->next) {
	PyObject *item = PyTuple_New(3);
	GnomeVFSGetFileInfoResult *r = results->data;
	gnome_vfs_uri_ref (r->uri);
	PyTuple_SetItem (item, 0, pygnome_vfs_uri_new (r->uri));
	PyTuple_SetItem (item, 1, fetch_exception (r->result, NULL));
	gnome_vfs_file_info_ref (r->file_info);
	PyTuple_SetItem (item, 2, pygnome_vfs_file_info_new (r->file_info));

	PyList_SetItem (pyresults, i, item);
    }

    if (notify->data)
	retobj = PyEval_CallFunction (notify->func, "(OOO)",
				      notify->self,
				      pyresults,
				      notify->data);
    else
	retobj = PyObject_CallFunction (notify->func, "(OO)",
					notify->self,
					pyresults);
      
    if (retobj == NULL) {
	PyErr_Print();
	PyErr_Clear();
    }

    Py_XDECREF (retobj);
    Py_DECREF (pyresults);

    async_notify_free (notify);
  
    pyg_unblock_threads ();
}

static PyObject *
pygvfs_async_get_file_info (PyObject *self,
			  PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "urilist", "callback", "options", "priority",
			      "data", NULL };
    PyObject *py_urilist;
    GList *urilist = NULL;
    GnomeVFSFileInfoOptions options = GNOME_VFS_FILE_INFO_DEFAULT;
    PyObject *callback;
    PyObject *data = NULL;
    int priority = GNOME_VFS_PRIORITY_DEFAULT;
    int size, i;
    PyObject *pyself;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OO|iiO:gnome.vfs.async.get_file_info",
				     kwlist, &py_urilist, &callback, &options,
				     &priority, &data))
	return NULL;

    /* XXXX: unblock threads here */

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }

    if (PyString_Check(py_urilist)) {
	urilist = g_list_append (urilist,
				 gnome_vfs_uri_new(PyString_AsString
						   (py_urilist)));
    }
    else if (PyObject_TypeCheck(py_urilist, &PyGnomeVFSURI_Type)) {
	urilist = g_list_append (urilist,
				 gnome_vfs_uri_ref
				 (pygnome_vfs_uri_get (py_urilist)));
    } else if (PySequence_Check(py_urilist)) {
	size = PySequence_Size(py_urilist);
	for (i = 0; i < size; ++i) {
	    PyObject *item = PySequence_GetItem(py_urilist, i);
	    GnomeVFSURI *uri = NULL;
	    if (PyObject_TypeCheck(item, &PyGnomeVFSURI_Type))
		uri = gnome_vfs_uri_ref(pygnome_vfs_uri_get(item));
	    else if (PyString_Check(item)) {
		uri = gnome_vfs_uri_new(PyString_AsString(item)); }
	    else {
		PyErr_SetString(PyExc_TypeError, "all items in sequence must be of string type or gnome.vfs.URI");
		return NULL;
	    }
	    urilist = g_list_append(urilist, uri);
	    Py_DECREF (item);
	}
    }
    else {
	PyErr_SetString(PyExc_TypeError, "'urilist' must be either a string, gnome.vfs.URI or a sequence of those");
        return NULL;
    }

    pyself = pygnome_vfs_async_handle_new (NULL);
    gnome_vfs_async_get_file_info(&((PyGnomeVFSAsyncHandle*)pyself)->fd,
				  urilist,
				  options,
				  priority,
				  (GnomeVFSAsyncGetFileInfoCallback)get_info_marshal,
				  async_notify_new (callback, pyself, data,
						    ASYNC_NOTIFY_G_INFO));

    while (urilist) {
	gnome_vfs_uri_unref ((GnomeVFSURI*)urilist->data);
	urilist = urilist->next;
    }
    g_list_free (urilist);

    return pyself;
}

static PyObject *
pygvhandle_is_open (PyGnomeVFSAsyncHandle *self)
{
    return PyInt_FromLong (self->fd != NULL);
}

static PyObject *
pygvhandle_cancel (PyGnomeVFSAsyncHandle *self)
{
    if (self->fd) {
	gnome_vfs_async_cancel (self->fd);
	self->fd = NULL;
    }

    Py_INCREF (Py_None);
    return Py_None;
}

static void
load_dir_marshal (GnomeVFSAsyncHandle *handle,
		  GnomeVFSResult result,
		  GList *list,
		  guint length,
		  PyGVFSAsyncNotify *notify)
{
    PyObject *retobj;
    PyObject *pyresults; /* a list of gnome.vfs.FileInfo */
    gint i;
    gboolean error_happened;
    PyObject *exception;

    pyg_block_threads ();

    exception = fetch_exception (result, &error_happened);
    if (error_happened &&
	notify->origin == ASYNC_NOTIFY_LOAD_DIRECTORY)
	notify->self->fd = NULL;

    pyresults = PyList_New (length);

    for (i=0; i<length; i++, list = list->next) {
	GnomeVFSFileInfo *info = list->data;

	gnome_vfs_file_info_ref (info);
	PyList_SetItem (pyresults, i, pygnome_vfs_file_info_new (info));
    }
    
    if (notify->data)
	retobj = PyEval_CallFunction (notify->func, "(OOOO)",
				      notify->self,
				      pyresults,
				      exception,
				      notify->data);
    else
	retobj = PyObject_CallFunction (notify->func, "(OOO)",
					notify->self,
					pyresults,
					exception);
      
    if (retobj == NULL) {
	PyErr_Print();
	PyErr_Clear();
    }

    Py_XDECREF (retobj);
    Py_DECREF (pyresults);
    Py_DECREF (exception);

    /* Supposedly we don't get called after errors? */
    if (error_happened)
	async_notify_free (notify);
  
    pyg_unblock_threads ();
}

static PyObject*
pygvfs_async_load_directory (PyObject *self,
			     PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "uri", "callback",
			      "options",
			      "items_per_notification",
			      "priority",
			      "data", NULL };
    PyObject *uri;
    PyObject *callback;
    GnomeVFSFileInfoOptions options = GNOME_VFS_FILE_INFO_DEFAULT;
    guint items_per_notification = 20; /* Some default to keep the
					  order of the parameters as in
					  the C API */
    int priority = GNOME_VFS_PRIORITY_DEFAULT;
    PyObject *data = NULL;
    PyObject *pyself;
    GnomeVFSURI *c_uri;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OO|iIiO:gnome.vfs.async.load_directory",
				     kwlist, &uri, &callback,
				     &options,
				     &items_per_notification,
				     &priority, &data))
	return NULL;

    /* XXXX: unblock threads here */

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }

    c_uri = object_to_uri (uri);
    if (c_uri == NULL)
	return NULL;
    
    pyself = pygnome_vfs_async_handle_new (NULL);
    gnome_vfs_async_load_directory_uri(&((PyGnomeVFSAsyncHandle*)pyself)->fd,
				       c_uri,
				       options,
				       items_per_notification,
				       priority,
				       (GnomeVFSAsyncDirectoryLoadCallback)load_dir_marshal,
				       async_notify_new (callback, pyself, data,
							 ASYNC_NOTIFY_LOAD_DIRECTORY));

    gnome_vfs_uri_unref (c_uri);

    return pyself;
}

static PyObject*
pygvfs_async_create (PyObject *self,
		     PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "uri", "callback",
			      "open_mode",
			      "exclusive",
			      "perm",
			      "priority",
			      "data", NULL };
    PyObject *uri;
    PyObject *callback;
    GnomeVFSOpenMode open_mode = GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE;
    gboolean exclusive = FALSE;
    guint perm = 0666;    
    int priority = GNOME_VFS_PRIORITY_DEFAULT;
    PyObject *data = NULL;
    PyObject *pyself;
    GnomeVFSURI *c_uri;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OO|iiiiO:gnome.vfs.async.create",
				     kwlist, &uri, &callback,
				     &open_mode, &exclusive,
				     &perm, &priority, &data))
	return NULL;

    /* XXXX: unblock threads here */

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }

    c_uri = object_to_uri (uri);
    if (c_uri == NULL)
	return NULL;

    pyself = pygnome_vfs_async_handle_new (NULL);
    gnome_vfs_async_create_uri(&((PyGnomeVFSAsyncHandle*)pyself)->fd,
			       c_uri,
			       open_mode,
			       exclusive,
			       perm,
			       priority,
			       (GnomeVFSAsyncOpenCallback)callback_marshal,
			       async_notify_new (callback, pyself, data,
						 ASYNC_NOTIFY_CREATE));

    gnome_vfs_uri_unref (c_uri);

    return pyself;
}

static PyObject*
pygvfs_async_create_symbolic_link (PyObject *self,
				   PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "uri", "reference", "callback",
			      "priority",
			      "data", NULL };
    PyObject *uri;
    PyObject *reference;
    PyObject *callback;
    int priority = GNOME_VFS_PRIORITY_DEFAULT;
    PyObject *data = NULL;
    PyObject *pyself;
    GnomeVFSURI *c_uri, *c_reference;
    gchar *reference_buffer;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "OOO|iO:gnome.vfs.async.create_symbolic_link",
				     kwlist, &uri, &reference, &callback,
				     &priority, &data))
	return NULL;

    /* XXXX: unblock threads here */

    if (!PyCallable_Check(callback)) {
	PyErr_SetString(PyExc_TypeError, "'callback' argument not callable");
	return NULL;
    }
    
    c_uri = object_to_uri (uri);
    if (c_uri == NULL)
	return NULL;

    c_reference = object_to_uri (reference);
    if (c_reference == NULL) {
	gnome_vfs_uri_unref (c_uri);
	return NULL;
    }
    /* hmmm... */
    reference_buffer = gnome_vfs_uri_to_string (c_reference,
						GNOME_VFS_URI_HIDE_NONE);

    pyself = pygnome_vfs_async_handle_new (NULL);
    gnome_vfs_async_create_symbolic_link(&((PyGnomeVFSAsyncHandle*)pyself)->fd,
					 c_uri,
					 reference_buffer,
					 priority,
					 (GnomeVFSAsyncOpenCallback)callback_marshal,
					 async_notify_new (callback, pyself, data,
							   ASYNC_NOTIFY_CREATE_SYMLINK));

    g_free (reference_buffer);
    gnome_vfs_uri_unref (c_uri);
    gnome_vfs_uri_unref (c_reference);

    return pyself;
}

static PyObject *
pygvfs_async_get_job_limit (PyObject *self)
{
    return PyInt_FromLong (gnome_vfs_async_get_job_limit ());
}

static PyObject*
pygvfs_async_set_job_limit (PyObject *self,
			    PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "limit", NULL };
    int limit;
    
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
				     "i:gnome.vfs.async.set_job_limit",
				     kwlist, &limit))
	return NULL;

    gnome_vfs_async_set_job_limit (limit);

    Py_INCREF (Py_None);
    return Py_None;
}

static PyMethodDef pygnomevfs_async_functions[] = {
    { "open", (PyCFunction)pygvfs_async_open, METH_VARARGS|METH_KEYWORDS },
    { "get_file_info", (PyCFunction)pygvfs_async_get_file_info,
      METH_VARARGS|METH_KEYWORDS },
    { "load_directory", (PyCFunction)pygvfs_async_load_directory,
      METH_VARARGS|METH_KEYWORDS },
    { "create", (PyCFunction)pygvfs_async_create,
      METH_VARARGS|METH_KEYWORDS },
    { "create_symbolic_link",
      (PyCFunction)pygvfs_async_create_symbolic_link,
      METH_VARARGS|METH_KEYWORDS },
    { "get_job_limit", (PyCFunction)pygvfs_async_get_job_limit,
      METH_NOARGS },
    { "set_job_limit", (PyCFunction)pygvfs_async_set_job_limit,
      METH_VARARGS|METH_KEYWORDS },
    { NULL, NULL, 0}
};

PyObject *
pygvfs_async_module_init (void)
{
    PyObject *m;
    PyObject *d;

    PyGnomeVFSAsyncHandle_Type.ob_type = &PyType_Type;

    if (PyType_Ready(&PyGnomeVFSAsyncHandle_Type) < 0)
	return NULL;

    m = Py_InitModule("gnome.vfs.async", pygnomevfs_async_functions);
    d = PyModule_GetDict(m);

    PyDict_SetItemString(d, "Handle",
			 (PyObject *)&PyGnomeVFSAsyncHandle_Type);

    return m;
}

static PyMethodDef pygvhandle_methods[] = {
    { "close", (PyCFunction)pygvhandle_close,
      METH_VARARGS|METH_KEYWORDS },
    { "read", (PyCFunction)pygvhandle_read, METH_VARARGS|METH_KEYWORDS },
    { "write", (PyCFunction)pygvhandle_write, METH_VARARGS|METH_KEYWORDS },
    { "is_open", (PyCFunction)pygvhandle_is_open, METH_NOARGS },
    { "cancel", (PyCFunction)pygvhandle_cancel, METH_NOARGS },
    { NULL, NULL, 0 }
};

PyTypeObject PyGnomeVFSAsyncHandle_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                  /* ob_size */
    "gnome.vfs.async.Handle",           /* tp_name */
    sizeof(PyGnomeVFSAsyncHandle),      /* tp_basicsize */
    0,                                  /* tp_itemsize */
    /* methods */
    (destructor)pygvhandle_dealloc,     /* tp_dealloc */
    (printfunc)0,                       /* tp_print */
    (getattrfunc)0,                     /* tp_getattr */
    (setattrfunc)0,                     /* tp_setattr */
    (cmpfunc)0,                         /* tp_compare */
    (reprfunc)0,                        /* tp_repr */
    0,                                  /* tp_as_number */
    0,                                  /* tp_as_sequence */
    0,                                  /* tp_as_mapping */
    (hashfunc)0,                        /* tp_hash */
    (ternaryfunc)0,                     /* tp_call */
    (reprfunc)0,                        /* tp_str */
    (getattrofunc)0,                    /* tp_getattro */
    (setattrofunc)0,                    /* tp_setattro */
    0,                                  /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
    NULL, /* Documentation string */
    (traverseproc)0,                    /* tp_traverse */
    (inquiry)0,                         /* tp_clear */
    (richcmpfunc)0,                     /* tp_richcompare */
    0,                                  /* tp_weaklistoffset */
    (getiterfunc)0,                     /* tp_iter */
    (iternextfunc)0,                    /* tp_iternext */
    pygvhandle_methods,                 /* tp_methods */
    0,                                  /* tp_members */
    0,                                  /* tp_getset */
    (PyTypeObject *)0,                  /* tp_base */
    (PyObject *)0,                      /* tp_dict */
    0,                                  /* tp_descr_get */
    0,                                  /* tp_descr_set */
    0,                                  /* tp_dictoffset */
    (initproc)pygvhandle_init,          /* tp_init */
    PyType_GenericAlloc,                /* tp_alloc */
    PyType_GenericNew,                  /* tp_new */
    0,                                  /* tp_free */
    (inquiry)0,                         /* tp_is_gc */
    (PyObject *)0,                      /* tp_bases */
};
import gtk
import gnome.vfs

def task_done():
    global counter
    counter -= 1
    if not counter:
        gtk.main_quit()

def write_callback(handle, bytes, exception):
    print 'Write done:', handle, bytes, exception
    handle.close(lambda *args: None)
    task_done()
    
def read_callback(handle, buffer, exception):
    print 'Read done:', handle, buffer, exception
    handle.close(lambda *args: None)
    task_done()

def create_callback(handle, exception):
    print 'Create done', handle, exception
    if not exception:
        handle.write('Hello world!\n', write_callback)
    else:
        task_done()

def symlink_callback(handle, exception):
    print 'Symlink done:', handle, exception
    task_done()

def open_callback(handle, exception):
    print 'Open done:', handle, exception
    if not exception:
        handle.read(14, read_callback)
    else:
        task_done()

def info_callback(handle, results):
    for uri, exception, info in results:
        print '-'*len(str(uri))
        print uri
        print '-'*len(str(uri))
        if not exception:
            try:
                print 'mime_type:\t', info.mime_type
                print 'size (bytes):\t', info.size
                print 'permissions:\t%o' % (info.permissions,)
            except ValueError:
                pass
            print
        else:
            print 'Error:\t', exception
    task_done()

def dir_callback(handle, results, exception):
    if not exception or exception == gnome.vfs.EOFError:
        for result in results:
            print result.name
            print '-'*len(str(result.name))
            try:
                print 'mime_type:\t', result.mime_type
                print 'size (bytes):\t', result.size
                print 'permissions:\t%o' % (result.permissions,)
            except ValueError:
                pass
            print
        if exception == gnome.vfs.EOFError:
            task_done()
    else:
        print 'Error:\t', exception
        task_done()

counter = 0

print 'Current job limit:', gnome.vfs.async.get_job_limit()

if 1:
    counter += 1
    print gnome.vfs.async.get_file_info(('/etc/fstab',
                                         'http://www.gnome.org/index.html'),
                                        info_callback,
                                        options = gnome.vfs.FILE_INFO_DEFAULT |
                                        gnome.vfs.FILE_INFO_GET_MIME_TYPE)
if 1:
    counter += 1
    print gnome.vfs.async.load_directory('fonts:',
                                         dir_callback,
                                         options =gnome.vfs.FILE_INFO_DEFAULT |
                                         gnome.vfs.FILE_INFO_GET_MIME_TYPE)


if 1:
    counter += 1
    print gnome.vfs.async.open('/etc/fstab', open_callback)

if 1:
    counter += 1
    print gnome.vfs.async.create('/tmp/test_file', create_callback)

if 1:
    counter += 1
    print gnome.vfs.async.create_symbolic_link('/tmp/test_link',
                                               '/etc/fstab',
                                               symlink_callback)

if counter:
    gtk.main()
_______________________________________________
pygtk mailing list   [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/

Reply via email to