From d98974c0a3de11fde1e5cdfd6dd469624c6c17d6 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Thu, 14 Jan 2010 11:48:05 +0100 Subject: Add XCB support using xpyb Signed-off-by: Julien Danjou --- configure.ac | 6 +++ doc/reference/surfaces.rst | 23 ++++++++++-- src/cairomodule.c | 5 +++ src/private.h | 5 +++ src/surface.c | 93 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 127 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index f305587..550ae3e 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ m4_define(pycairo_version, pycairo_version_major.pycairo_version_minor.pycairo_v # versions of packages we require m4_define(cairo_required_version, 1.8.8) +m4_define(xpyb_required_version, 1.3) AC_INIT([pycairo], [pycairo_version], @@ -45,6 +46,11 @@ if test -n "$export_dynamic"; then CAIRO_LIBS=`echo $CAIRO_LIBS | sed -e "s/$export_dynamic//"` fi +# xpyb +PKG_CHECK_MODULES(XPYB, xpyb >= xpyb_required_version,[have_xpyb=yes],[have_xpyb=no]) +AS_IF([test "x$have_xpyb" = "xyes"], + [AC_DEFINE([HAVE_XPYB], [1], [Define to 1 if xpyb is available])]) + # Checks for header files --- AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) diff --git a/doc/reference/surfaces.rst b/doc/reference/surfaces.rst index 0957649..fbec39e 100644 --- a/doc/reference/surfaces.rst +++ b/doc/reference/surfaces.rst @@ -637,10 +637,27 @@ Note that the XCB surface automatically takes advantage of X render extension if it is available. .. class:: XCBSurface + :param connection: an XCB connection + :param drawable: a X drawable + :param visualtype: a X visualtype + :param width: The surface width + :param height: The surface height - .. note:: *XCBSurface* cannot be instantiated directly because Python - interaction with XCB would require open source Python bindings to Xlib - which provided a C API. + Creates a cairo surface that targets the given drawable (pixmap or window). + + .. note:: This methods works using xpyb. + + .. method:: set_size(width, height) + :param width: The width of the surface + :param height: The height of the surface + + Informs cairo of the new size of the X Drawable underlying the surface. For a surface created + for a Window (rather than a Pixmap), this function must be called each time the size of the + window changes. (For a subwindow, you are normally resizing the window yourself, but for a + toplevel window, it is necessary to listen for ConfigureNotify events.) + + A Pixmap can never change size, so it is never necessary to call this function on a surface + created for a Pixmap. class XlibSurface(:class:`Surface`) diff --git a/src/cairomodule.c b/src/cairomodule.c index a83ba49..21b7b20 100644 --- a/src/cairomodule.c +++ b/src/cairomodule.c @@ -39,6 +39,11 @@ # include #endif +/* for XCB api */ +#if defined(CAIRO_HAS_XCB_SURFACE) && defined(HAVE_XPYB) +xpyb_CAPI_t *xpyb_CAPI; +PyObject *xpybVISUALTYPE_type; +#endif /* A module specific exception */ PyObject *CairoError = NULL; diff --git a/src/private.h b/src/private.h index 4bbf4fd..708f04c 100644 --- a/src/private.h +++ b/src/private.h @@ -96,6 +96,11 @@ extern PyTypeObject PycairoWin32Surface_Type; #if CAIRO_HAS_XCB_SURFACE extern PyTypeObject PycairoXCBSurface_Type; +#ifdef HAVE_XPYB +# include +extern xpyb_CAPI_t *xpyb_CAPI; +extern PyObject *xpybVISUALTYPE_type; +#endif #endif #if CAIRO_HAS_XLIB_SURFACE diff --git a/src/surface.c b/src/surface.c index 7a6fd2e..568aad7 100644 --- a/src/surface.c +++ b/src/surface.c @@ -1144,13 +1144,102 @@ PyTypeObject PycairoWin32Surface_Type = { #ifdef CAIRO_HAS_XCB_SURFACE #include +#ifdef HAVE_XPYB +/** Convert a Python object from xpyb to a C struct matching libxcb type. + * The object must be referenced if you want to keep returned data away from + * garbage collection. + * @param obj The object to convert. + * @param len The size of the object read by Python. + * @return A pointer to that data. + */ +const void * +xpyb2struct(PyObject *obj, Py_ssize_t *len) +{ + const void *data; + + if (PyObject_AsReadBuffer(obj, &data, len) < 0) + return NULL; + + return data; +} + +static int +have_xpyb(void) +{ + static int have_xpyb = -1; + if(have_xpyb == -1) { + /* Get type from xpyb */ + xpyb_IMPORT; + /* Some types are not defined in the CAPI */ + PyObject *xpyb_module = PyImport_ImportModule("xcb.xproto"); + if (xpyb_module) { + PyObject *dict = PyModule_GetDict(xpyb_module); + xpybVISUALTYPE_type = PyDict_GetItemString(dict, "VISUALTYPE"); + Py_DECREF(xpyb_module); + have_xpyb = 1; + } + else + have_xpyb = 0; + } + return have_xpyb; +} + +#endif + static PyObject * xcb_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { +#ifdef HAVE_XPYB + int width, height; + xcb_drawable_t drawable; + PyObject *visual; + xpybConn *conn; + + if(!have_xpyb()) + return NULL; + + if (!PyArg_ParseTuple(args, "O!IO!ii:XCBSurface.__new__", + xpyb_CAPI->xpybConn_type, &conn, + &drawable, + xpybVISUALTYPE_type, &visual, + &width, &height)) + return NULL; + + /* Convert Python object VISUALTYPE to a xcb_visualtype_t */ + Py_ssize_t length; + xcb_visualtype_t *visualtype = (xcb_visualtype_t *) xpyb2struct(visual, &length); + + if (length < sizeof(xcb_visualtype_t)) + return NULL; + + return PycairoSurface_FromSurface ( + cairo_xcb_surface_create (conn->conn, drawable, visualtype, + width, height), NULL); +#else PyErr_SetString(PyExc_TypeError, - "The XCBSurface type cannot be directly instantiated"); + "pycairo was not compiled with xpyb support"); return NULL; +#endif } +#ifdef HAVE_XPYB +static PyObject * +xcb_surface_set_size (PycairoXCBSurface *o, PyObject *args) { + int width, height; + + if (!PyArg_ParseTuple(args, "ii:XCBSurface.set_size", &width, &height)) + return NULL; + cairo_xcb_surface_set_size (o->surface, width, height); + Py_RETURN_NONE; +} +#endif + +static PyMethodDef xcb_surface_methods[] = { +#ifdef HAVE_XPYB + {"set_size", (PyCFunction)xcb_surface_set_size, METH_VARARGS }, +#endif + {NULL, NULL, 0, NULL}, +}; + PyTypeObject PycairoXCBSurface_Type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ @@ -1180,7 +1269,7 @@ PyTypeObject PycairoXCBSurface_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + xcb_surface_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ &PycairoSurface_Type, /* tp_base */ -- cgit v1.2.1