summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Davis <loafier@gmail.com>2006-07-14 10:02:13 +0000
committerChristopher Davis <loafier@gmail.com>2006-07-14 10:02:13 +0000
commit5eaed0dbf78fca2bcf185da0abf1dbf41722deb2 (patch)
tree2ff9c8bc5c8d206f2b7a852609d1eac6bd377d27
parent34cdeaae9369af5dce3ce3a4a7756c033bc44cc5 (diff)
downloadirssi-python-5eaed0dbf78fca2bcf185da0abf1dbf41722deb2.tar.gz
irssi-python-5eaed0dbf78fca2bcf185da0abf1dbf41722deb2.tar.xz
irssi-python-5eaed0dbf78fca2bcf185da0abf1dbf41722deb2.zip
finished up themes. time for textui stuff
git-svn-id: http://svn.irssi.org/repos/irssi-python@4297 dbcabf3a-b0e7-0310-adc4-f8d773084564
-rw-r--r--objects/Makefile3
-rw-r--r--objects/factory.c3
-rw-r--r--objects/factory.h1
-rw-r--r--objects/theme-object.c195
-rw-r--r--objects/theme-object.h18
-rw-r--r--pyloader.c9
-rw-r--r--pymodule.c24
-rw-r--r--pythemes.c75
8 files changed, 313 insertions, 15 deletions
diff --git a/objects/Makefile b/objects/Makefile
index 8ebf7c1..39f6195 100644
--- a/objects/Makefile
+++ b/objects/Makefile
@@ -15,7 +15,8 @@ chatnet-object.o reconnect-object.o window-object.o textdest-object.o \
rawlog-object.o log-object.o logitem-object.o ignore-object.o \
dcc-object.o dcc-chat-object.o dcc-get-object.o dcc-send-object.o \
netsplit-object.o netsplit-server-object.o netsplit-channel-object.o \
-notifylist-object.o process-object.o command-object.o factory.o
+notifylist-object.o process-object.o command-object.o theme-object.o \
+factory.o
pyobjects.a: $(OBJ)
ar r pyobjects.a $(OBJ)
diff --git a/objects/factory.c b/objects/factory.c
index 5b77427..bfc19ab 100644
--- a/objects/factory.c
+++ b/objects/factory.c
@@ -119,6 +119,9 @@ static int init_objects(void)
if (!command_object_init())
return 0;
+ if (!theme_object_init())
+ return 0;
+
return 1;
}
diff --git a/objects/factory.h b/objects/factory.h
index 14a3b7c..b7eb0e7 100644
--- a/objects/factory.h
+++ b/objects/factory.h
@@ -32,6 +32,7 @@
#include "notifylist-object.h"
#include "process-object.h"
#include "command-object.h"
+#include "theme-object.h"
int factory_init(void);
void factory_deinit(void);
diff --git a/objects/theme-object.c b/objects/theme-object.c
new file mode 100644
index 0000000..0f12217
--- /dev/null
+++ b/objects/theme-object.c
@@ -0,0 +1,195 @@
+#include <Python.h>
+#include "pyirssi.h"
+#include "pymodule.h"
+#include "theme-object.h"
+#include "factory.h"
+#include "pycore.h"
+
+/* monitor "theme destroyed" signal */
+static void theme_cleanup(THEME_REC *rec)
+{
+ PyTheme *pytheme = signal_get_user_data();
+ if (pytheme->data == rec)
+ {
+ pytheme->data = NULL;
+ pytheme->cleanup_installed = 0;
+ signal_remove_data("theme destroyed", theme_cleanup, pytheme);
+ }
+}
+
+static void PyTheme_dealloc(PyTheme *self)
+{
+ if (self->cleanup_installed)
+ signal_remove_data("theme destroyed", theme_cleanup, self);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *PyTheme_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyTheme *self;
+
+ self = (PyTheme *)type->tp_alloc(type, 0);
+ if (!self)
+ return NULL;
+
+ return (PyObject *)self;
+}
+
+/* Getters */
+/* specialized getters/setters */
+static PyGetSetDef PyTheme_getseters[] = {
+ {NULL}
+};
+
+/* Methods */
+PyDoc_STRVAR(PyTheme_format_expand_doc,
+ "format_expand(format, flags=0) -> str or None\n"
+);
+static PyObject *PyTheme_format_expand(PyTheme *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"format", "flags", NULL};
+ char *format = "";
+ int flags = 0;
+ char *ret;
+ PyObject *pyret;
+
+ RET_NULL_IF_INVALID(self->data);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist,
+ &format, &flags))
+ return NULL;
+
+ if (flags == 0)
+ ret = theme_format_expand(self->data, format);
+ else
+ ret = theme_format_expand_data(self->data, (const char **)&format, 'n', 'n',
+ NULL, NULL, EXPAND_FLAG_ROOT | flags);
+
+ if (ret)
+ {
+ pyret = PyString_FromString(ret);
+ g_free(ret);
+ return pyret;
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyTheme_get_format_doc,
+ "get_format(module, tag) -> str\n"
+);
+static PyObject *PyTheme_get_format(PyTheme *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"module", "tag", NULL};
+ char *module = "";
+ char *tag = "";
+ THEME_REC *theme = self->data;
+ FORMAT_REC *formats;
+ MODULE_THEME_REC *modtheme;
+ int i;
+
+ RET_NULL_IF_INVALID(self->data);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+ &module, &tag))
+ return NULL;
+
+ formats = g_hash_table_lookup(default_formats, module);
+ if (!formats)
+ return PyErr_Format(PyExc_KeyError, "unknown module, %s", module);
+
+ for (i = 0; formats[i].def; i++)
+ {
+ if (formats[i].tag && !g_strcasecmp(formats[i].tag, tag))
+ {
+ modtheme = g_hash_table_lookup(theme->modules, module);
+ if (modtheme && modtheme->formats[i])
+ return PyString_FromString(modtheme->formats[i]);
+ else
+ return PyString_FromString(formats[i].def);
+ }
+ }
+
+ return PyErr_Format(PyExc_KeyError, "unknown format tag, %s", tag);
+}
+
+/* Methods for object */
+static PyMethodDef PyTheme_methods[] = {
+ {"format_expand", (PyCFunction)PyTheme_format_expand, METH_VARARGS | METH_KEYWORDS,
+ PyTheme_format_expand_doc},
+ {"get_format", (PyCFunction)PyTheme_get_format, METH_VARARGS | METH_KEYWORDS,
+ PyTheme_get_format_doc},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject PyThemeType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "Theme", /*tp_name*/
+ sizeof(PyTheme), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)PyTheme_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PyTheme_methods, /* tp_methods */
+ 0, /* tp_members */
+ PyTheme_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyTheme_new, /* tp_new */
+};
+
+/* Theme factory function */
+PyObject *pytheme_new(void *td)
+{
+ PyTheme *pytheme;
+
+ pytheme = py_inst(PyTheme, PyThemeType);
+ if (!pytheme)
+ return NULL;
+
+ pytheme->data = td;
+ signal_add_last_data("theme destroyed", theme_cleanup, pytheme);
+ pytheme->cleanup_installed = 1;
+
+ return (PyObject *)pytheme;
+}
+
+int theme_object_init(void)
+{
+ g_return_val_if_fail(py_module != NULL, 0);
+
+ if (PyType_Ready(&PyThemeType) < 0)
+ return 0;
+
+ Py_INCREF(&PyThemeType);
+ PyModule_AddObject(py_module, "Theme", (PyObject *)&PyThemeType);
+
+ return 1;
+}
diff --git a/objects/theme-object.h b/objects/theme-object.h
new file mode 100644
index 0000000..299d54d
--- /dev/null
+++ b/objects/theme-object.h
@@ -0,0 +1,18 @@
+#ifndef _THEME_OBJECT_H_
+#define _THEME_OBJECT_H_
+
+#include <Python.h>
+#include "base-objects.h"
+
+typedef struct
+{
+ PyIrssiFinal_HEAD(void)
+} PyTheme;
+
+extern PyTypeObject PyThemeType;
+
+int theme_object_init(void);
+PyObject *pytheme_new(void *td);
+#define pytheme_check(op) PyObject_TypeCheck(op, &PyThemeType)
+
+#endif
diff --git a/pyloader.c b/pyloader.c
index 03b5150..a087827 100644
--- a/pyloader.c
+++ b/pyloader.c
@@ -148,7 +148,14 @@ error:
else
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "error loading script %s", argv[0]);
- Py_XDECREF(script);
+ if (script)
+ {
+ /* make sure to clean up any formats, signals, commands that may have been
+ attached before the exception took place */
+ pyscript_cleanup(script);
+ Py_DECREF(script);
+ }
+
g_free(path);
return 0;
diff --git a/pymodule.c b/pymodule.c
index d0d17f7..34413a5 100644
--- a/pymodule.c
+++ b/pymodule.c
@@ -1353,6 +1353,26 @@ error:
}
#endif
+PyDoc_STRVAR(py_themes_reload_doc,
+ "themes_reload() -> None\n"
+);
+static PyObject *py_themes_reload(PyObject *self, PyObject *args)
+{
+ themes_reload();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_current_theme_doc,
+ "current_theme() -> Theme object\n"
+);
+static PyObject *py_current_theme(PyObject *self, PyObject *args)
+{
+ if (current_theme)
+ return pytheme_new(current_theme);
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef ModuleMethods[] = {
{"prnt", (PyCFunction)py_prnt, METH_VARARGS | METH_KEYWORDS,
py_prnt_doc},
@@ -1506,6 +1526,10 @@ static PyMethodDef ModuleMethods[] = {
py_strip_codes_doc},
/*{"format_get_text", (PyCFunction)py_format_get_text, METH_VARARGS,
py_format_get_text_doc},*/
+ {"themes_reload", (PyCFunction)py_themes_reload, METH_NOARGS,
+ py_themes_reload_doc},
+ {"current_theme", (PyCFunction)py_current_theme, METH_NOARGS,
+ py_current_theme_doc},
{NULL, NULL, 0, NULL} /* Sentinel */
};
diff --git a/pythemes.c b/pythemes.c
index 009c2ab..1e03f10 100644
--- a/pythemes.c
+++ b/pythemes.c
@@ -5,15 +5,23 @@
#include "pymodule.h"
#include "pyloader.h"
+static void py_get_mod(char *full, int fullsz, const char *script)
+{
+ g_snprintf(full, fullsz, "irssi_python/%s.py", script);
+}
+
/* Edited from Perl Themes.xs */
-int pythemes_printformat(TEXT_DEST_REC *dest, const char *script, const char *format, PyObject *argtup)
+int pythemes_printformat(TEXT_DEST_REC *dest, const char *name, const char *format, PyObject *argtup)
{
char *arglist[MAX_FORMAT_PARAMS + 1];
THEME_REC *theme;
char *str;
+ char script[256];
int formatnum;
int i;
-
+
+ py_get_mod(script, sizeof script, name);
+
formatnum = format_find_tag(script, format);
if (formatnum < 0) {
PyErr_Format(PyExc_KeyError, "unregistered format '%s'", format);
@@ -64,11 +72,14 @@ static void py_destroy_format_list(FORMAT_REC *recs)
/* register a list of formats in this format:
* [ (name, format), ... ]
*/
-int pythemes_register(const char *script, PyObject *list)
+int pythemes_register(const char *name, PyObject *list)
{
+ char script[256];
FORMAT_REC *formatrecs;
int i;
+ py_get_mod(script, sizeof script, name);
+
if (!PyList_Check(list))
{
PyErr_Format(PyExc_TypeError, "arg must be list");
@@ -89,7 +100,7 @@ int pythemes_register(const char *script, PyObject *list)
formatrecs = g_new0(FORMAT_REC, PyList_Size(list) + 2);
formatrecs[0].tag = g_strdup(script);
- formatrecs[0].tag = g_strdup("Python script");
+ formatrecs[0].def = g_strdup("Python script");
for (i = 0; i < PyList_Size(list); i++)
{
@@ -120,10 +131,13 @@ int pythemes_register(const char *script, PyObject *list)
return 1;
}
-void pythemes_unregister(const char *script)
+void pythemes_unregister(const char *name)
{
+ char script[256];
FORMAT_REC *formats;
+ py_get_mod(script, sizeof script, name);
+
formats = g_hash_table_lookup(default_formats, script);
if (!formats)
return;
@@ -132,27 +146,48 @@ void pythemes_unregister(const char *script)
theme_unregister_module(script);
}
+/* XXX: test binding a PyCFunction to different sources. Not sure
+ if this is a good thing or not, but it seems to work */
PyDoc_STRVAR(py_printformat_doc,
+ "for Server objects:\n"
+ "printformat(target, level, format, ...) -> None\n"
+ "\n"
+ "For all else:\n"
"printformat(level, format, ...) -> None\n"
);
static PyObject *py_printformat(PyObject *self, PyObject *all)
{
- int level = 0;
- char *format = "";
+ int level;
+ char *format;
+ char *target;
PyObject *args = NULL, *varargs = NULL;
TEXT_DEST_REC dest;
char *script;
+ int formatstart;
- args = PySequence_GetSlice(all, 0, 2);
+ if (self && pyserver_check(self))
+ formatstart = 3;
+ else
+ formatstart = 2;
+
+ args = PySequence_GetSlice(all, 0, formatstart);
if (!args)
goto error;
- varargs = PySequence_GetSlice(all, 2, PyTuple_Size(all));
+ varargs = PySequence_GetSlice(all, formatstart, PyTuple_Size(all));
if (!varargs)
goto error;
-
- if (!PyArg_ParseTuple(args, "is", &level, &format))
- goto error;
+
+ if (self && pyserver_check(self))
+ {
+ if (!PyArg_ParseTuple(args, "sis", &target, &level, &format))
+ goto error;
+ }
+ else
+ {
+ if (!PyArg_ParseTuple(args, "is", &level, &format))
+ goto error;
+ }
script = pyloader_find_script_name();
if (!script)
@@ -161,7 +196,20 @@ static PyObject *py_printformat(PyObject *self, PyObject *all)
goto error;
}
- format_create_dest(&dest, NULL, NULL, level, NULL);
+ /* create the text dest depending on whether this function is called from
+ module level or as a method of one of the objects */
+ if (self == NULL) /* module */
+ format_create_dest(&dest, NULL, NULL, level, NULL);
+ else if (pyserver_check(self))
+ format_create_dest(&dest, DATA(self), target, level, NULL);
+ else if (pywindow_check(self))
+ format_create_dest(&dest, NULL, NULL, level, DATA(self));
+ else if (pywindow_item_check(self))
+ {
+ PyWindowItem *pywi = (PyWindowItem *)self;
+ format_create_dest(&dest, pywi->data->server, pywi->data->visible_name, level, NULL);
+ }
+
if (!pythemes_printformat(&dest, script, format, varargs))
goto error;
@@ -177,6 +225,7 @@ error:
return NULL;
}
+/* XXX: these funcs could be moved to pyutils.c */
static int py_add_module_func(PyMethodDef *mdef)
{
PyObject *func;