Modules/fmmodule.c
/* Font Manager module */

#include "Python.h"

#include <gl.h>
#include <device.h>
#include <fmclient.h>


/* Font Handle object implementation */

typedef struct {
    PyObject_HEAD
    fmfonthandle fh_fh;
} fhobject;

static PyTypeObject Fhtype;

#define is_fhobject(v)          ((v)->ob_type == &Fhtype)

static PyObject *
newfhobject(fmfonthandle fh)
{
    fhobject *fhp;
    if (fh == NULL) {
        PyErr_SetString(PyExc_RuntimeError,
                        "error creating new font handle");
        return NULL;
    }
    fhp = PyObject_New(fhobject, &Fhtype);
    if (fhp == NULL)
        return NULL;
    fhp->fh_fh = fh;
    return (PyObject *)fhp;
}

/* Font Handle methods */

static PyObject *
fh_scalefont(fhobject *self, PyObject *args)
{
    double size;
    if (!PyArg_ParseTuple(args, "d", &size))
        return NULL;
    return newfhobject(fmscalefont(self->fh_fh, size));
}

/* XXX fmmakefont */

static PyObject *
fh_setfont(fhobject *self)
{
    fmsetfont(self->fh_fh);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
fh_getfontname(fhobject *self)
{
    char fontname[256];
    int len;
    len = fmgetfontname(self->fh_fh, sizeof fontname, fontname);
    if (len < 0) {
        PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontname");
        return NULL;
    }
    return PyString_FromStringAndSize(fontname, len);
}

static PyObject *
fh_getcomment(fhobject *self)
{
    char comment[256];
    int len;
    len = fmgetcomment(self->fh_fh, sizeof comment, comment);
    if (len < 0) {
        PyErr_SetString(PyExc_RuntimeError, "error in fmgetcomment");
        return NULL;
    }
    return PyString_FromStringAndSize(comment, len);
}

static PyObject *
fh_getfontinfo(fhobject *self)
{
    fmfontinfo info;
    if (fmgetfontinfo(self->fh_fh, &info) < 0) {
        PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontinfo");
        return NULL;
    }
    return Py_BuildValue("(llllllll)",
                         info.printermatched,
                         info.fixed_width,
                         info.xorig,
                         info.yorig,
                         info.xsize,
                         info.ysize,
                         info.height,
                         info.nglyphs);
}

#if 0
static PyObject *
fh_getwholemetrics(fhobject *self, PyObject *args)
{
}
#endif

static PyObject *
fh_getstrwidth(fhobject *self, PyObject *args)
{
    char *str;
    if (!PyArg_ParseTuple(args, "s", &str))
        return NULL;
    return PyInt_FromLong(fmgetstrwidth(self->fh_fh, str));
}

static PyMethodDef fh_methods[] = {
    {"scalefont",       (PyCFunction)fh_scalefont,   METH_VARARGS},
    {"setfont",         (PyCFunction)fh_setfont,     METH_NOARGS},
    {"getfontname",     (PyCFunction)fh_getfontname, METH_NOARGS},
    {"getcomment",      (PyCFunction)fh_getcomment,  METH_NOARGS},
    {"getfontinfo",     (PyCFunction)fh_getfontinfo, METH_NOARGS},
#if 0
    {"getwholemetrics",         (PyCFunction)fh_getwholemetrics, METH_VARARGS},
#endif
    {"getstrwidth",     (PyCFunction)fh_getstrwidth, METH_VARARGS},
    {NULL,              NULL}           /* sentinel */
};

static PyObject *
fh_getattr(fhobject *fhp, char *name)
{
    return Py_FindMethod(fh_methods, (PyObject *)fhp, name);
}

static void
fh_dealloc(fhobject *fhp)
{
    fmfreefont(fhp->fh_fh);
    PyObject_Del(fhp);
}

static PyTypeObject Fhtype = {
    PyObject_HEAD_INIT(&PyType_Type)
    0,                                  /*ob_size*/
    "fm.font handle",                   /*tp_name*/
    sizeof(fhobject),                   /*tp_size*/
    0,                                  /*tp_itemsize*/
    /* methods */
    (destructor)fh_dealloc,             /*tp_dealloc*/
    0,                                  /*tp_print*/
    (getattrfunc)fh_getattr,            /*tp_getattr*/
    0,                                  /*tp_setattr*/
    0,                                  /*tp_compare*/
    0,                                  /*tp_repr*/
};


/* Font Manager functions */

static PyObject *
fm_init(PyObject *self)
{
    fminit();
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
fm_findfont(PyObject *self, PyObject *args)
{
    char *str;
    if (!PyArg_ParseTuple(args, "s", &str))
        return NULL;
    return newfhobject(fmfindfont(str));
}

static PyObject *
fm_prstr(PyObject *self, PyObject *args)
{
    char *str;
    if (!PyArg_ParseTuple(args, "s", &str))
        return NULL;
    fmprstr(str);
    Py_INCREF(Py_None);
    return Py_None;
}

/* XXX This uses a global variable as temporary! Not re-entrant! */

static PyObject *fontlist;

static void
clientproc(char *fontname)
{
    int err;
    PyObject *v;
    if (fontlist == NULL)
        return;
    v = PyString_FromString(fontname);
    if (v == NULL)
        err = -1;
    else {
        err = PyList_Append(fontlist, v);
        Py_DECREF(v);
    }
    if (err != 0) {
        Py_DECREF(fontlist);
        fontlist = NULL;
    }
}

static PyObject *
fm_enumerate(PyObject *self)
{
    PyObject *res;
    fontlist = PyList_New(0);
    if (fontlist == NULL)
        return NULL;
    fmenumerate(clientproc);
    res = fontlist;
    fontlist = NULL;
    return res;
}

static PyObject *
fm_setpath(PyObject *self, PyObject *args)
{
    char *str;
    if (!PyArg_ParseTuple(args, "s", &str))
        return NULL;
    fmsetpath(str);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
fm_fontpath(PyObject *self)
{
    return PyString_FromString(fmfontpath());
}

static PyMethodDef fm_methods[] = {
    {"init",            fm_init,      METH_NOARGS},
    {"findfont",        fm_findfont,  METH_VARARGS},
    {"enumerate",       fm_enumerate, METH_NOARGS},
    {"prstr",           fm_prstr,     METH_VARARGS},
    {"setpath",         fm_setpath,   METH_VARARGS},
    {"fontpath",        fm_fontpath,  METH_NOARGS},
    {NULL,              NULL}           /* sentinel */
};


void
initfm(void)
{

    if (PyErr_WarnPy3k("the fm module has been removed in "
                       "Python 3.0", 2) < 0)
    return;

    Py_InitModule("fm", fm_methods);
    if (m == NULL)
        return;
    fminit();
}