summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Davis <loafier@gmail.com>2006-07-03 06:00:18 +0000
committerChristopher Davis <loafier@gmail.com>2006-07-03 06:00:18 +0000
commit34cdeaae9369af5dce3ce3a4a7756c033bc44cc5 (patch)
treee6d1c6e41fa734e0ac40ef5f3c68aff689631017
parenta329fa4675852886ba2bbc9637cebcac882f1575 (diff)
downloadirssi-python-34cdeaae9369af5dce3ce3a4a7756c033bc44cc5.tar.gz
irssi-python-34cdeaae9369af5dce3ce3a4a7756c033bc44cc5.tar.xz
irssi-python-34cdeaae9369af5dce3ce3a4a7756c033bc44cc5.zip
worked on formats. working on themes now; testing adding functions and methods to objects
git-svn-id: http://svn.irssi.org/repos/irssi-python@4295 dbcabf3a-b0e7-0310-adc4-f8d773084564
-rw-r--r--Makefile3
-rw-r--r--constants.awk7
-rw-r--r--constants.txt7
-rw-r--r--irssi.py17
-rw-r--r--objects/base-objects.h2
-rw-r--r--objects/pyscript-object.c362
-rw-r--r--objects/pyscript-object.h4
-rw-r--r--objects/textdest-object.c129
-rw-r--r--objects/textdest-object.h1
-rw-r--r--objects/window-item-object.c3
-rw-r--r--pyconstants.h7
-rw-r--r--pycore.c3
-rw-r--r--pyirssi.h3
-rw-r--r--pyloader.c59
-rw-r--r--pyloader.h2
-rw-r--r--pymodule.c474
-rw-r--r--pysignals.c37
-rw-r--r--pysource.c166
-rw-r--r--pysource.h7
-rw-r--r--pythemes.c238
-rw-r--r--pythemes.h13
21 files changed, 1310 insertions, 234 deletions
diff --git a/Makefile b/Makefile
index fc70984..fbed8e1 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,8 @@ CFLAGS = -fpic -ggdb -Wall -I$(PYTHON) -I$(IRSSI) -I$(IRSSI)/src \
LDFLAGS = -fpic /usr/lib/libpython2.4.so
-OBJ = pycore.o pyutils.o pymodule.o pyloader.o pysignals.o pysource.o
+OBJ = pycore.o pyutils.o pymodule.o pyloader.o pysignals.o pysource.o \
+pythemes.o
pyirssi: pyobjects.a $(OBJ)
$(CC) -shared -o libirssi_python.so $(OBJ) objects/pyobjects.a $(LDFLAGS)
diff --git a/constants.awk b/constants.awk
index c9395c1..18f8002 100644
--- a/constants.awk
+++ b/constants.awk
@@ -3,7 +3,12 @@ BEGIN {
}
{
- printf(" {\"%s\", %25s},\n", $1,$1);
+ if (NF >= 2)
+ constant = $2;
+ else
+ constant = $1;
+
+ printf(" {\"%s\", %25s},\n", $1, constant);
}
END {
diff --git a/constants.txt b/constants.txt
index 3baff40..c65b779 100644
--- a/constants.txt
+++ b/constants.txt
@@ -1,5 +1,8 @@
-G_INPUT_READ
-G_INPUT_WRITE
+IO_IN G_IO_IN
+IO_OUT G_IO_OUT
+IO_PRI G_IO_PRI
+IO_ERR G_IO_ERR
+IO_HUP G_IO_HUP
IRSSI_GUI_GNOME
IRSSI_GUI_GTK
IRSSI_GUI_KDE
diff --git a/irssi.py b/irssi.py
index 68a7074..dfd391c 100644
--- a/irssi.py
+++ b/irssi.py
@@ -39,6 +39,23 @@ def command_bind(*args, **kwargs):
""" see Script.command_bind """
get_script().command_bind(*args, **kwargs)
+def command_unbind(*args, **kwargs):
+ """ see Script.command_unbind """
+ get_script().command_unbind(*args, **kwargs)
+
def signal_add(*args, **kwargs):
""" see Script.signal_add """
get_script().signal_add(*args, **kwargs)
+
+def signal_remove(*args, **kwargs):
+ """ see Script.signal_remove """
+ get_script().signal_remove(*args, **kwargs)
+
+def timeout_add(*args, **kwargs):
+ """ see Script.timeout_add """
+ get_script().timeout_add(*args, **kwargs)
+
+def io_add_watch(*args, **kwargs):
+ """ see Script.io_add_watch """
+ get_script().io_add_watch(*args, **kwargs)
+
diff --git a/objects/base-objects.h b/objects/base-objects.h
index ed2edfc..5351ead 100644
--- a/objects/base-objects.h
+++ b/objects/base-objects.h
@@ -27,7 +27,7 @@ typedef struct
void *data;
} PyIrssiObject;
-#define DATA(obj) (((PyIrssiObject *)obj)->data)
+#define DATA(obj) (obj? ((PyIrssiObject *)obj)->data : NULL)
/* base for classes with a type */
typedef struct
diff --git a/objects/pyscript-object.c b/objects/pyscript-object.c
index 2ab7b88..d51761b 100644
--- a/objects/pyscript-object.c
+++ b/objects/pyscript-object.c
@@ -5,6 +5,7 @@
#include "pysignals.h"
#include "pymodule.h"
#include "pysource.h"
+#include "pythemes.h"
/* handle cycles...
Can't think of any reason why the user would put script into one of the lists
@@ -40,31 +41,29 @@ static void PyScript_dealloc(PyScript* self)
static PyObject *PyScript_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyScript *self;
- PyObject *argv, *modules;
+ PyObject *argv = NULL, *modules = NULL;
argv = PyList_New(0);
if (!argv)
- return NULL;
+ goto error;
modules = PyDict_New();
if (!modules)
- {
- Py_DECREF(argv);
- return NULL;
- }
+ goto error;
self = (PyScript *)type->tp_alloc(type, 0);
if (!self)
- {
- Py_DECREF(argv);
- Py_DECREF(modules);
- return NULL;
- }
-
+ goto error;
+
self->argv = argv;
self->modules = modules;
return (PyObject *)self;
+
+error:
+ Py_XDECREF(argv);
+ Py_XDECREF(modules);
+ return NULL;
}
PyDoc_STRVAR(PyScript_command_bind_doc,
@@ -268,55 +267,70 @@ static PyObject *PyScript_signal_unregister(PyScript *self, PyObject *args, PyOb
}
PyDoc_STRVAR(PyScript_timeout_add_doc,
- "timeout_add(msecs, func, data=None, once=False) -> int source handle\n"
+ "timeout_add(msecs, func, data=None) -> int source tag\n"
+ "\n"
+ "Add a timeout handler called every 'msecs' milliseconds until func\n"
+ "returns False or the source is removed with source_remove().\n"
+ "\n"
+ "func is called as func(data) or func(), depending on whether data\n"
+ "is specified or not.\n"
);
static PyObject *PyScript_timeout_add(PyScript *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"msecs", "func", "data", "once", NULL};
+ static char *kwlist[] = {"msecs", "func", "data", NULL};
int msecs = 0;
PyObject *func = NULL;
PyObject *data = NULL;
- int once = 0;
int ret;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO|Oi", kwlist,
- &msecs, &func, &data, &once))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO|O", kwlist,
+ &msecs, &func, &data))
return NULL;
if (msecs < 10)
return PyErr_Format(PyExc_ValueError, "msecs must be at least 10");
- ret = pysource_timeout_add_list(&self->sources, msecs, func, data, once);
+ if (!PyCallable_Check(func))
+ return PyErr_Format(PyExc_TypeError, "func not callable");
+
+ ret = pysource_timeout_add_list(&self->sources, msecs, func, data);
return PyInt_FromLong(ret);
}
-PyDoc_STRVAR(PyScript_input_add_doc,
- "input_add(fd, func, data=None, once=False, condition=G_INPUT_READ) -> int source tag\n"
+PyDoc_STRVAR(PyScript_io_add_watch_doc,
+ "io_add_watch(fd, func, data=None, condition=IO_IN|IO_PRI) -> int source tag\n"
);
-static PyObject *PyScript_input_add(PyScript *self, PyObject *args, PyObject *kwds)
+static PyObject *PyScript_io_add_watch(PyScript *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"fd", "func", "data", "once", "condition", NULL};
+ static char *kwlist[] = {"fd", "func", "data", "condition", NULL};
int fd = 0;
+ PyObject *pyfd = NULL;
PyObject *func = NULL;
PyObject *data = NULL;
- int once = 0;
- int condition = G_INPUT_READ;
+ int condition = G_IO_IN | G_IO_PRI;
int ret;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO|Oii", kwlist,
- &fd, &func, &data, &once, &condition))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|Oi", kwlist,
+ &pyfd, &func, &data, &condition))
return NULL;
- ret = pysource_input_add_list(&self->sources, fd, condition, func, data, once);
+ fd = PyObject_AsFileDescriptor(pyfd);
+ if (fd < 0)
+ return NULL;
+
+ if (!PyCallable_Check(func))
+ return PyErr_Format(PyExc_TypeError, "func not callable");
+
+ ret = pysource_io_add_watch_list(&self->sources, fd, condition, func, data);
return PyInt_FromLong(ret);
}
PyDoc_STRVAR(PyScript_source_remove_doc,
- "source_remove(tag) -> None\n"
+ "source_remove(tag) -> bool\n"
"\n"
- "Remove IO or timeout source by tag\n"
+ "Remove IO or timeout source by tag. Return True if tag found and removed.\n"
);
static PyObject *PyScript_source_remove(PyScript *self, PyObject *args, PyObject *kwds)
{
@@ -327,8 +341,204 @@ static PyObject *PyScript_source_remove(PyScript *self, PyObject *args, PyObject
&tag))
return NULL;
- if (!pysource_remove_tag(&self->sources, tag))
- return PyErr_Format(PyExc_KeyError, "source tag not found");
+ /* the destroy notify func will remove the list link, but first
+ check that the tag exists in this Script object */
+ if (g_slist_find(self->sources, GINT_TO_POINTER(tag)))
+ return PyBool_FromLong(g_source_remove(tag));
+
+ Py_RETURN_FALSE;
+}
+
+static int py_settings_add(PyScript *self, const char *name)
+{
+ GSList *node;
+
+ node = gslist_find_icase_string(self->settings, name);
+ if (node)
+ return 0;
+
+ self->settings = g_slist_append(self->settings, g_strdup(name));
+
+ return 1;
+}
+
+static int py_settings_remove(PyScript *self, const char *name)
+{
+ GSList *node;
+
+ node = gslist_find_icase_string(self->settings, name);
+ if (!node)
+ return 0;
+
+ settings_remove(node->data);
+ g_free(node->data);
+
+ self->settings = g_slist_delete_link(self->settings, node);
+
+ return 1;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_str_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_str(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ char *def = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_str_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_int_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_int(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ int def = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ssi", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_int_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_bool_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_bool(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ int def = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ssi", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_bool_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_time_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_time(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ char *def = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_time_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_level_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_level(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ char *def = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_level_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_add_size_doc,
+ ""
+);
+static PyObject *PyScript_settings_add_size(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"section", "key", "def", NULL};
+ char *section = "";
+ char *key = "";
+ char *def = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss", kwlist,
+ &section, &key, &def))
+ return NULL;
+
+ if (!py_settings_add(self, key))
+ return PyErr_Format(PyExc_ValueError, "key, %s, already added by script", key);
+
+ settings_add_size_module(MODULE_NAME"/scripts", section, key, def);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PyScript_settings_remove_doc,
+ "settings_remove(key) -> bool\n"
+);
+static PyObject *PyScript_settings_remove(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyBool_FromLong(py_settings_remove(self, key));
+}
+
+PyDoc_STRVAR(PyScript_theme_register_doc,
+ "theme_register(list) -> None\n"
+);
+static PyObject *PyScript_theme_register(PyScript *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"list", NULL};
+ PyObject *list = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist,
+ &list))
+ return NULL;
+
+ if (!pythemes_register(pyscript_get_name(self), list))
+ return NULL;
Py_RETURN_NONE;
}
@@ -349,10 +559,26 @@ static PyMethodDef PyScript_methods[] = {
PyScript_signal_unregister_doc},
{"timeout_add", (PyCFunction)PyScript_timeout_add, METH_VARARGS | METH_KEYWORDS,
PyScript_timeout_add_doc},
- {"input_add", (PyCFunction)PyScript_input_add, METH_VARARGS | METH_KEYWORDS,
- PyScript_input_add_doc},
+ {"io_add_watch", (PyCFunction)PyScript_io_add_watch, METH_VARARGS | METH_KEYWORDS,
+ PyScript_io_add_watch_doc},
{"source_remove", (PyCFunction)PyScript_source_remove, METH_VARARGS | METH_KEYWORDS,
PyScript_source_remove_doc},
+ {"settings_add_str", (PyCFunction)PyScript_settings_add_str, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_str_doc},
+ {"settings_add_int", (PyCFunction)PyScript_settings_add_int, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_int_doc},
+ {"settings_add_bool", (PyCFunction)PyScript_settings_add_bool, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_bool_doc},
+ {"settings_add_time", (PyCFunction)PyScript_settings_add_time, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_time_doc},
+ {"settings_add_level", (PyCFunction)PyScript_settings_add_level, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_level_doc},
+ {"settings_add_size", (PyCFunction)PyScript_settings_add_size, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_add_size_doc},
+ {"settings_remove", (PyCFunction)PyScript_settings_remove, METH_VARARGS | METH_KEYWORDS,
+ PyScript_settings_remove_doc},
+ {"theme_register", (PyCFunction)PyScript_theme_register, METH_VARARGS | METH_KEYWORDS,
+ PyScript_theme_register_doc},
{NULL} /* Sentinel */
};
@@ -363,7 +589,7 @@ static PyMemberDef PyScript_members[] = {
{NULL} /* Sentinel */
};
-static PyTypeObject PyScriptType = {
+PyTypeObject PyScriptType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Script", /*tp_name*/
@@ -408,7 +634,7 @@ static PyTypeObject PyScriptType = {
/* PyScript factory function */
PyObject *pyscript_new(PyObject *module, char **argv)
{
- PyObject *script = NULL;
+ PyObject *script;
script = PyObject_CallFunction((PyObject*)&PyScriptType, "()");
@@ -418,17 +644,20 @@ PyObject *pyscript_new(PyObject *module, char **argv)
while (*argv)
{
- PyObject *str = PyString_FromString(*argv);
- if (!str)
+ if (**argv != '\0')
{
- /* The destructor should DECREF argv */
- Py_DECREF(script);
- return NULL;
+ PyObject *str = PyString_FromString(*argv);
+ if (!str)
+ {
+ /* The destructor should DECREF argv */
+ Py_DECREF(script);
+ return NULL;
+ }
+
+ PyList_Append(scr->argv, str);
+ Py_DECREF(str);
}
- PyList_Append(scr->argv, str);
- Py_DECREF(str);
-
*argv++;
}
@@ -466,15 +695,47 @@ void pyscript_remove_signals(PyObject *script)
void pyscript_remove_sources(PyObject *script)
{
+ GSList *node;
+ PyScript *self;
+
+ g_return_if_fail(pyscript_check(script));
+
+ self = (PyScript *) script;
+
+ node = self->sources;
+ while (node)
+ {
+ /* the notify func will destroy the link so save next */
+ GSList *next = node->next;
+ g_source_remove(GPOINTER_TO_INT(node->data));
+ node = next;
+ }
+
+ g_return_if_fail(self->sources == NULL);
+}
+
+void pyscript_remove_settings(PyObject *script)
+{
PyScript *self;
g_return_if_fail(pyscript_check(script));
self = (PyScript *) script;
- pysource_remove_list(self->sources);
- g_slist_free(self->sources);
- self->sources = NULL;
+ g_slist_foreach(self->settings, (GFunc)settings_remove, NULL);
+ g_slist_foreach(self->settings, (GFunc)g_free, NULL);
+ g_slist_free(self->settings);
+}
+
+void pyscript_remove_themes(PyObject *script)
+{
+ PyScript *self;
+
+ g_return_if_fail(pyscript_check(script));
+
+ self = (PyScript *) script;
+
+ pythemes_unregister(pyscript_get_name(script));
}
void pyscript_clear_modules(PyObject *script)
@@ -488,6 +749,15 @@ void pyscript_clear_modules(PyObject *script)
PyDict_Clear(self->modules);
}
+void pyscript_cleanup(PyObject *script)
+{
+ pyscript_remove_signals(script);
+ pyscript_remove_sources(script);
+ pyscript_remove_settings(script);
+ pyscript_remove_themes(script);
+ pyscript_clear_modules(script);
+}
+
int pyscript_init(void)
{
if (PyType_Ready(&PyScriptType) < 0)
diff --git a/objects/pyscript-object.h b/objects/pyscript-object.h
index fafa94b..644571d 100644
--- a/objects/pyscript-object.h
+++ b/objects/pyscript-object.h
@@ -11,6 +11,7 @@ typedef struct {
GSList *signals; /* list of bound signals and commands */
GSList *registered_signals; /* list of signal names registered */
GSList *sources; /* list of io and timeout sources */
+ GSList *settings; /* list of settings from settings_add_*() */
} PyScript;
extern PyTypeObject PyScriptType;
@@ -19,7 +20,10 @@ int pyscript_init(void);
PyObject *pyscript_new(PyObject *module, char **argv);
void pyscript_remove_signals(PyObject *script);
void pyscript_remove_sources(PyObject *script);
+void pyscript_remove_settings(PyObject *script);
+void pyscript_remove_themes(PyObject *script);
void pyscript_clear_modules(PyObject *script);
+void pyscript_cleanup(PyObject *script);
#define pyscript_check(op) PyObject_TypeCheck(op, &PyScriptType)
#define pyscript_get_name(scr) PyModule_GetName(((PyScript*)scr)->module)
#define pyscript_get_filename(scr) PyModule_GetFilename(((PyScript*)scr)->module)
diff --git a/objects/textdest-object.c b/objects/textdest-object.c
index 9dd94d6..2ad6523 100644
--- a/objects/textdest-object.c
+++ b/objects/textdest-object.c
@@ -5,13 +5,20 @@
#include "factory.h"
#include "pycore.h"
-/* XXX: no cleanup signal for textdest */
+static int pytextdest_setup(PyTextDest *pytdest, void *td, int owned);
+/* XXX: no cleanup signal for textdest */
static void PyTextDest_dealloc(PyTextDest *self)
{
Py_XDECREF(self->window);
Py_XDECREF(self->server);
-
+
+ if (self->owned)
+ {
+ g_free((char*)self->data->target);
+ g_free(self->data);
+ }
+
self->ob_type->tp_free((PyObject*)self);
}
@@ -26,6 +33,57 @@ static PyObject *PyTextDest_new(PyTypeObject *type, PyObject *args, PyObject *kw
return (PyObject *)self;
}
+/* init function to create the textdest */
+PyDoc_STRVAR(PyTextDest_doc,
+ "__init__(target, level=MSGLEVEL_CLIENTNOTICE, server=None, window=None)\n"
+ "\n"
+ "Create a TextDest\n"
+);
+static int PyTextDest_init(PyTextDest *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"target", "level", "server", "window", NULL};
+ char *target;
+ int level = MSGLEVEL_CLIENTNOTICE;
+ PyObject *server = NULL, *window = NULL;
+ TEXT_DEST_REC *dest;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|ioo", kwlist,
+ &target, &level, &server, &window))
+ return -1;
+
+ if (server == Py_None)
+ server = NULL;
+ if (window == Py_None)
+ window = NULL;
+
+ if (server && !pyserver_check(server))
+ {
+ PyErr_Format(PyExc_TypeError, "arg 3 isnt server");
+ return -1;
+ }
+
+ if (window && !pywindow_check(window))
+ {
+ PyErr_Format(PyExc_TypeError, "arg 4 isnt window");
+ return -1;
+ }
+
+ if (self->data)
+ {
+ PyErr_Format(PyExc_RuntimeError, "TextDest already wrapped");
+ return -1;
+ }
+
+ dest = g_new0(TEXT_DEST_REC, 1);
+ format_create_dest(dest, DATA(server), g_strdup(target), level, DATA(window));
+
+ if (!pytextdest_setup(self, dest, 1))
+ return -1;
+
+ return 0;
+}
+
+/* Getters */
PyDoc_STRVAR(PyTextDest_window_doc,
"Window where the text will be written"
);
@@ -97,8 +155,32 @@ static PyGetSetDef PyTextDest_getseters[] = {
{NULL}
};
+/* Methods */
+PyDoc_STRVAR(PyTextDest_prnt_doc,
+ "prnt(str) -> None\n"
+ "\n"
+ "Print str to TextDest\n"
+);
+static PyObject *PyTextDest_prnt(PyTextDest *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"str", NULL};
+ char *str = "";
+
+ RET_NULL_IF_INVALID(self->data);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &str))
+ return NULL;
+
+ printtext_dest(self->data, "%s", str);
+
+ Py_RETURN_NONE;
+}
+
/* Methods for object */
static PyMethodDef PyTextDest_methods[] = {
+ {"prnt", (PyCFunction)PyTextDest_prnt, METH_VARARGS | METH_KEYWORDS,
+ PyTextDest_prnt_doc},
{NULL} /* Sentinel */
};
@@ -124,7 +206,7 @@ PyTypeObject PyTextDestType = {
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- "PyTextDest objects", /* tp_doc */
+ PyTextDest_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
@@ -139,38 +221,53 @@ PyTypeObject PyTextDestType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
- 0, /* tp_init */
+ (initproc)PyTextDest_init, /* tp_init */
0, /* tp_alloc */
PyTextDest_new, /* tp_new */
};
-
-/* TextDest factory function */
-PyObject *pytextdest_new(void *td)
+static int pytextdest_setup(PyTextDest *pytdest, void *td, int owned)
{
PyObject *window, *server;
- PyTextDest *pytdest;
TEXT_DEST_REC *tdest = td;
- window = py_irssi_chat_new(tdest->window, 1);
- if (!window)
- return NULL;
+ if (tdest->window)
+ {
+ window = pywindow_new(tdest->window);
+ if (!window)
+ return 0;
+ }
server = py_irssi_chat_new(tdest->server, 1);
if (!server)
{
Py_DECREF(window);
- return NULL;
+ return 0;
}
- pytdest = py_inst(PyTextDest, PyTextDestType);
- if (!pytdest)
- return NULL;
-
pytdest->data = td;
pytdest->window = window;
pytdest->server = server;
+ pytdest->owned = owned;
+ return 1;
+}
+
+/* TextDest factory function */
+PyObject *pytextdest_new(void *td)
+{
+ PyTextDest *pytdest;
+
+ pytdest = py_inst(PyTextDest, PyTextDestType);
+ if (!pytdest)
+ return NULL;
+
+ if (!pytextdest_setup(pytdest, td, 0))
+ {
+ Py_DECREF(pytdest);
+ return NULL;
+ }
+
return (PyObject *)pytdest;
}
diff --git a/objects/textdest-object.h b/objects/textdest-object.h
index 366914a..3e273e6 100644
--- a/objects/textdest-object.h
+++ b/objects/textdest-object.h
@@ -12,6 +12,7 @@ typedef struct
PyIrssiFinal_HEAD(struct _TEXT_DEST_REC)
PyObject *window;
PyObject *server;
+ int owned;
} PyTextDest;
extern PyTypeObject PyTextDestType;
diff --git a/objects/window-item-object.c b/objects/window-item-object.c
index 6494d48..7acb075 100644
--- a/objects/window-item-object.c
+++ b/objects/window-item-object.c
@@ -69,6 +69,7 @@ static PyGetSetDef PyWindowItem_getseters[] = {
{NULL}
};
+/* Methods */
PyDoc_STRVAR(PyWindowItem_prnt_doc,
"Print to window item"
);
@@ -106,8 +107,6 @@ static PyObject *PyWindowItem_command(PyWindowItem *self, PyObject *args, PyObje
Py_RETURN_NONE;
}
-/* Methods */
-
PyDoc_STRVAR(PyWindowItem_window_doc,
"Return parent window for window item"
);
diff --git a/pyconstants.h b/pyconstants.h
index 4cf6407..e196236 100644
--- a/pyconstants.h
+++ b/pyconstants.h
@@ -1,6 +1,9 @@
static PY_CONSTANT_REC py_constants[] = {
- {"INPUT_READ", INPUT_READ},
- {"INPUT_WRITE", INPUT_WRITE},
+ {"IO_IN", G_IO_IN},
+ {"IO_OUT", G_IO_OUT},
+ {"IO_PRI", G_IO_PRI},
+ {"IO_ERR", G_IO_ERR},
+ {"IO_HUP", G_IO_HUP},
{"IRSSI_GUI_GNOME", IRSSI_GUI_GNOME},
{"IRSSI_GUI_GTK", IRSSI_GUI_GTK},
{"IRSSI_GUI_KDE", IRSSI_GUI_KDE},
diff --git a/pycore.c b/pycore.c
index 6963076..cce5fb2 100644
--- a/pycore.c
+++ b/pycore.c
@@ -7,6 +7,7 @@
#include "pyloader.h"
#include "pymodule.h"
#include "pysignals.h"
+#include "pythemes.h"
#include "factory.h"
/*XXX: copy parse into utils */
@@ -118,7 +119,7 @@ void irssi_python_init(void)
Py_InitializeEx(0);
pysignals_init();
- if (!pyloader_init() || !pymodule_init() || !factory_init())
+ if (!pyloader_init() || !pymodule_init() || !factory_init() || !pythemes_init())
{
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Failed to load Python");
return;
diff --git a/pyirssi.h b/pyirssi.h
index 0313354..b4fb17c 100644
--- a/pyirssi.h
+++ b/pyirssi.h
@@ -6,6 +6,7 @@
#include "common.h"
#include "modules.h"
#include "commands.h"
+#include "settings.h"
#include "printtext.h"
#include "window-items.h"
#include "window-activity.h"
@@ -18,9 +19,11 @@
#include "chatnets.h"
#include "servers-reconnect.h"
#include "masks.h"
+#include "misc.h"
#include "rawlog.h"
#include "log.h"
#include "ignore.h"
#include "fe-exec.h"
+#include "pidwait.h"
#endif
diff --git a/pyloader.c b/pyloader.c
index 6b3fd82..03b5150 100644
--- a/pyloader.c
+++ b/pyloader.c
@@ -1,4 +1,5 @@
#include <Python.h>
+#include <frameobject.h>
#include <string.h>
#include "pyirssi.h"
#include "pyloader.h"
@@ -70,7 +71,7 @@ static char *py_find_script(const char *name)
fname = (char *)name;
/*XXX: use case insensitive path search? */
- for (node = script_paths; node != NULL && !path; node = node->next)
+ for (node = script_paths; node && !path; node = node->next)
{
path = g_strdup_printf("%s/%s", (char *)node->data, fname);
@@ -113,31 +114,32 @@ int pyloader_load_script_argv(char **argv)
name = file_get_filename(path);
module = PyModule_New(name);
g_free(name);
-
if (!module)
goto error;
script = pyscript_new(module, argv);
Py_DECREF(module);
-
if (!script)
goto error;
/* insert script obj into module dict, load file */
- if (PyModule_AddObject(module, "_script", script) < 0)
+ if (PyModule_AddObject(module, "_script", script) != 0)
goto error;
+
Py_INCREF(script);
if (!py_load_module(module, path))
goto error;
- PyList_Append(script_modules, script);
- Py_DECREF(script);
- g_free(path);
+ if (PyList_Append(script_modules, script) != 0)
+ goto error;
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "loaded script %s", argv[0]);
/* PySys_WriteStdout("load %s, script -> 0x%x\n", argv[0], script); */
- printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "loaded script %s", argv[0]);
+ Py_DECREF(script);
+ g_free(path);
+
return 1;
error:
@@ -200,9 +202,7 @@ int pyloader_unload_script(const char *name)
PySys_WriteStdout("unload %s, script -> 0x%x\n", name, script);
- pyscript_remove_signals(script);
- pyscript_remove_sources(script);
- pyscript_clear_modules(script);
+ pyscript_cleanup(script);
if (PySequence_DelItem(script_modules, id) < 0)
{
@@ -218,6 +218,39 @@ int pyloader_unload_script(const char *name)
return 1;
}
+/* Traverse stack backwards to find the nearest valid _script object in globals */
+PyObject *pyloader_find_script_obj(void)
+{
+ PyFrameObject *frame;
+
+ for (frame = PyEval_GetFrame(); frame != NULL; frame = frame->f_back)
+ {
+ g_return_val_if_fail(frame->f_globals != NULL, NULL);
+ PyObject *script = PyDict_GetItemString(frame->f_globals, "_script");
+ if (script && pyscript_check(script))
+ {
+ /*
+ PySys_WriteStdout("Found script at %s in %s, script -> 0x%x\n",
+ PyString_AS_STRING(frame->f_code->co_name),
+ PyString_AS_STRING(frame->f_code->co_filename), script);
+ */
+ return script;
+ }
+ }
+
+ return NULL;
+}
+
+char *pyloader_find_script_name(void)
+{
+ PyObject *script = pyloader_find_script_obj();
+
+ if (!script)
+ return NULL;
+
+ return pyscript_get_name(script);
+}
+
GSList *pyloader_list(void)
{
int i;
@@ -296,9 +329,7 @@ static void py_clear_scripts()
for (i = 0; i < PyList_Size(script_modules); i++)
{
PyObject *scr = PyList_GET_ITEM(script_modules, i);
- pyscript_remove_signals(scr);
- pyscript_remove_sources(scr);
- pyscript_clear_modules(scr);
+ pyscript_cleanup(scr);
}
Py_DECREF(script_modules);
diff --git a/pyloader.h b/pyloader.h
index f7e19fb..b7befd3 100644
--- a/pyloader.h
+++ b/pyloader.h
@@ -11,6 +11,8 @@ void pyloader_add_script_path(const char *path);
int pyloader_load_script_argv(char **argv);
int pyloader_load_script(char *name);
int pyloader_unload_script(const char *name);
+PyObject *pyloader_find_script_obj(void);
+char *pyloader_find_script_name(void);
GSList *pyloader_list(void);
void pyloader_list_destroy(GSList **list);
diff --git a/pymodule.c b/pymodule.c
index ac78186..d0d17f7 100644
--- a/pymodule.c
+++ b/pymodule.c
@@ -1,17 +1,18 @@
#include <Python.h>
-#include <frameobject.h>
#include "pymodule.h"
#include "pyirssi_irc.h"
#include "pyscript-object.h"
#include "factory.h"
#include "pyutils.h"
#include "pysignals.h"
+#include "pyloader.h"
+#include "pythemes.h"
/*
* This module is some what different than the Perl's.
* Script specific operations are handled by the Script object
* instead of by a function in this module. command_bind,
- * signal_bind, etc require data to be saved about the script
+ * signal_add, etc require data to be saved about the script
* for cleanup purposes, so I moved those functions to the script
* object.
*/
@@ -19,8 +20,6 @@
/* Main embedded module */
PyObject *py_module = NULL;
-static PyObject *find_script(void);
-
/* Module functions */
/*XXX: prefix PY to avoid ambiguity with py_command function */
PyDoc_STRVAR(PY_command_doc,
@@ -64,7 +63,7 @@ PyDoc_STRVAR(py_get_script_doc,
);
static PyObject *py_get_script(PyObject *self, PyObject *args)
{
- PyObject *ret = find_script();
+ PyObject *ret = pyloader_find_script_obj();
/* XXX: type check */
@@ -949,6 +948,411 @@ static PyObject *py_signal_get_emitted_id(PyObject *self, PyObject *args)
return PyInt_FromLong(signal_get_emitted_id());
}
+PyDoc_STRVAR(py_settings_get_str_doc,
+ "settings_get_str(key) -> str\n"
+ "\n"
+ "Get value for setting.\n"
+);
+static PyObject *py_settings_get_str(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ RET_AS_STRING_OR_NONE(settings_get_str(key));
+}
+
+PyDoc_STRVAR(py_settings_get_int_doc,
+ "settings_get_int(key) -> int\n"
+ "\n"
+ "Get value for setting."
+);
+static PyObject *py_settings_get_int(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyInt_FromLong(settings_get_int(key));
+}
+
+PyDoc_STRVAR(py_settings_get_bool_doc,
+ "settings_get_bool(key) -> bool\n"
+ "\n"
+ "Get value for setting.\n"
+);
+static PyObject *py_settings_get_bool(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyBool_FromLong(settings_get_bool(key));
+}
+
+PyDoc_STRVAR(py_settings_get_time_doc,
+ "settings_get_time(key) -> long\n"
+ "\n"
+ "Get value for setting.\n"
+);
+static PyObject *py_settings_get_time(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyLong_FromLong(settings_get_time(key));
+}
+
+PyDoc_STRVAR(py_settings_get_level_doc,
+ "settings_get_level(key) -> int\n"
+ "\n"
+ "Get value for setting.\n"
+);
+static PyObject *py_settings_get_level(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyInt_FromLong(settings_get_level(key));
+}
+
+PyDoc_STRVAR(py_settings_get_size_doc,
+ "settings_get_size(key) -> long\n"
+ "\n"
+ "Get value for setting.\n"
+);
+static PyObject *py_settings_get_size(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", NULL};
+ char *key = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &key))
+ return NULL;
+
+ return PyLong_FromLong(settings_get_size(key));
+}
+
+PyDoc_STRVAR(py_settings_set_str_doc,
+ "settings_set_str(key, value) -> None\n"
+ "\n"
+ "Set string value for setting\n"
+);
+static PyObject *py_settings_set_str(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ char *value = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+ &key, &value))
+ return NULL;
+
+ settings_set_str(key, value);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_settings_set_int_doc,
+ "settings_set_int(key, value) -> None\n"
+ "\n"
+ "Set int value for setting"
+);
+static PyObject *py_settings_set_int(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ int value = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "si", kwlist,
+ &key, &value))
+ return NULL;
+
+ settings_set_int(key, value);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_settings_set_bool_doc,
+ "settings_set_bool(key, value) -> None\n"
+ "\n"
+ "Set bool value for setting\n"
+);
+static PyObject *py_settings_set_bool(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ int value = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "si", kwlist,
+ &key, &value))
+ return NULL;
+
+ settings_set_bool(key, value);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_settings_set_time_doc,
+ "settings_set_time(key, value) -> bool\n"
+ "\n"
+ "Set string value for setting\n"
+);
+static PyObject *py_settings_set_time(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ char *value = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+ &key, &value))
+ return NULL;
+
+ return PyBool_FromLong(settings_set_time(key, value));
+}
+
+PyDoc_STRVAR(py_settings_set_level_doc,
+ "settings_set_level(key, value) -> bool\n"
+ "\n"
+ "Set string value for setting\n"
+);
+static PyObject *py_settings_set_level(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ char *value = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+ &key, &value))
+ return NULL;
+
+ return PyBool_FromLong(settings_set_level(key, value));
+}
+
+PyDoc_STRVAR(py_settings_set_size_doc,
+ "settings_set_size(key, value) -> bool\n"
+ "\n"
+ "Set string value for setting\n"
+);
+static PyObject *py_settings_set_size(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"key", "value", NULL};
+ char *key = "";
+ char *value = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+ &key, &value))
+ return NULL;
+
+ return PyBool_FromLong(settings_set_size(key, value));
+}
+
+PyDoc_STRVAR(py_pidwait_add_doc,
+ "pidwait_add(pid) -> None\n"
+ "\n"
+ "Add pid to wait list\n"
+);
+static PyObject *py_pidwait_add(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"pid", NULL};
+ int pid = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist,
+ &pid))
+ return NULL;
+
+ pidwait_add(pid);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_pidwait_remove_doc,
+ "pidwait_remove(pid) -> None\n"
+ "\n"
+ "Remove pid from wait list\n"
+);
+static PyObject *py_pidwait_remove(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"pid", NULL};
+ int pid = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist,
+ &pid))
+ return NULL;
+
+ pidwait_remove(pid);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_format_get_length_doc,
+ "format_get_length(str) -> int length\n"
+);
+static PyObject *py_format_get_length(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"str", NULL};
+ char *str = "";
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &str))
+ return NULL;
+
+ return PyInt_FromLong(format_get_length(str));
+}
+
+PyDoc_STRVAR(py_format_real_length_doc,
+ "format_real_length(str, len) -> int length\n"
+);
+static PyObject *py_format_real_length(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"str", "len", NULL};
+ char *str = "";
+ int len;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sl", kwlist,
+ &str, &len))
+ return NULL;
+
+ return PyInt_FromLong(format_real_length(str, len));
+}
+
+PyDoc_STRVAR(py_strip_codes_doc,
+ "strip_codes(input) -> str\n"
+);
+static PyObject *py_strip_codes(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"input", NULL};
+ char *input = "";
+ char *ret;
+ PyObject *pyret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &input))
+ return NULL;
+
+ ret = strip_codes(input);
+ if (ret)
+ {
+ pyret = PyString_FromString(ret);
+ g_free(ret);
+ return pyret;
+ }
+
+ Py_RETURN_NONE;
+}
+
+#if 0
+PyDoc_STRVAR(py_format_get_text_doc,
+ "format_get_text(textdest, module, formatnum, ...) -> str\n"
+ "\n"
+ "Return a substituted format string from module and formatnum.\n"
+ "module is a string.\n"
+ "\n"
+ "Example:\n"
+ "TODO\n"
+);
+static PyObject *py_format_get_text(PyObject *self, PyObject *varargs)
+{
+ PyTextDest *textdest = NULL;
+ char *module = "";
+ unsigned int formatnum = 0;
+ PyObject *args = NULL, *pycharargs = NULL;
+ THEME_REC *theme;
+ MODULE_THEME_REC *modtheme;
+ char **charargs = NULL;
+ char *ret;
+ int i;
+
+ args = PySequence_GetSlice(varargs, 0, 3);
+ if (!args)
+ goto error;
+
+ pycharargs = PySequence_GetSlice(varargs, 3, PyTuple_Size(varargs));
+ if (!pycharargs)
+ goto error;
+
+ if (!PyArg_ParseTuple(args, "OsI",
+ &textdest, &module, &formatnum))
+ goto error;
+
+ if (!pytextdest_check((PyObject *)textdest))
+ {
+ PyErr_Format(PyExc_TypeError, "arg 1 must be TextDest");
+ goto error;
+ }
+
+ /* Bleh, check that formatnum is within range */
+ theme = window_get_theme(textdest->data->window);
+
+ /* FIXME: how to boundscheck formatnum ?? */
+
+ /* size + 1 for terminating NULL ptr */
+ charargs = g_new0(char *, PyTuple_Size(pycharargs) + 1);
+
+ for (i = 0; i < PyTuple_Size(pycharargs); i++)
+ {
+ PyObject *obj = PyTuple_GET_ITEM(pycharargs, i);
+ char *str;
+
+ if (!PyString_Check(obj))
+ {
+ PyErr_Format(PyExc_TypeError,
+ "non string in string argument list (arg %d)",
+ i + 4);
+ goto error;
+ }
+
+ str = PyString_AsString(obj);
+ if (!str)
+ goto error;
+
+ charargs[i] = str;
+ }
+
+ /* return string, or if string is NULL, return None */
+ ret = format_get_text_theme_charargs(theme, module, DATA(textdest), formatnum, charargs);
+ Py_DECREF(args);
+ Py_DECREF(pycharargs);
+ g_free(charargs);
+
+ if (ret)
+ {
+ PyObject *pyret;
+
+ pyret = PyString_FromString(ret);
+ g_free(ret);
+
+ return pyret;
+ }
+
+ Py_RETURN_NONE;
+
+error:
+ Py_XDECREF(args);
+ Py_XDECREF(pycharargs);
+ g_free(charargs);
+
+ return NULL;
+}
+#endif
+
static PyMethodDef ModuleMethods[] = {
{"prnt", (PyCFunction)py_prnt, METH_VARARGS | METH_KEYWORDS,
py_prnt_doc},
@@ -1066,33 +1470,45 @@ static PyMethodDef ModuleMethods[] = {
py_signal_get_emitted_id_doc},
{"signal_continue", (PyCFunction)py_signal_continue, METH_VARARGS,
py_signal_continue_doc},
+ {"settings_get_str", (PyCFunction)py_settings_get_str, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_str_doc},
+ {"settings_get_int", (PyCFunction)py_settings_get_int, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_int_doc},
+ {"settings_get_bool", (PyCFunction)py_settings_get_bool, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_bool_doc},
+ {"settings_get_time", (PyCFunction)py_settings_get_time, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_time_doc},
+ {"settings_get_level", (PyCFunction)py_settings_get_level, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_level_doc},
+ {"settings_get_size", (PyCFunction)py_settings_get_size, METH_VARARGS | METH_KEYWORDS,
+ py_settings_get_size_doc},
+ {"settings_set_str", (PyCFunction)py_settings_set_str, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_str_doc},
+ {"settings_set_int", (PyCFunction)py_settings_set_int, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_int_doc},
+ {"settings_set_bool", (PyCFunction)py_settings_set_bool, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_bool_doc},
+ {"settings_set_time", (PyCFunction)py_settings_set_time, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_time_doc},
+ {"settings_set_level", (PyCFunction)py_settings_set_level, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_level_doc},
+ {"settings_set_size", (PyCFunction)py_settings_set_size, METH_VARARGS | METH_KEYWORDS,
+ py_settings_set_size_doc},
+ {"pidwait_add", (PyCFunction)py_pidwait_add, METH_VARARGS | METH_KEYWORDS,
+ py_pidwait_add_doc},
+ {"pidwait_remove", (PyCFunction)py_pidwait_remove, METH_VARARGS | METH_KEYWORDS,
+ py_pidwait_remove_doc},
+ {"format_get_length", (PyCFunction)py_format_get_length, METH_VARARGS | METH_KEYWORDS,
+ py_format_get_length_doc},
+ {"format_real_length", (PyCFunction)py_format_real_length, METH_VARARGS | METH_KEYWORDS,
+ py_format_real_length_doc},
+ {"strip_codes", (PyCFunction)py_strip_codes, METH_VARARGS | METH_KEYWORDS,
+ py_strip_codes_doc},
+ /*{"format_get_text", (PyCFunction)py_format_get_text, METH_VARARGS,
+ py_format_get_text_doc},*/
{NULL, NULL, 0, NULL} /* Sentinel */
};
-/*XXX: move to pyloader.c??*/
-/* Traverse stack backwards to find the nearest _script object in globals */
-static PyObject *find_script(void)
-{
- PyFrameObject *frame;
-
- for (frame = PyEval_GetFrame(); frame != NULL; frame = frame->f_back)
- {
- g_return_val_if_fail(frame->f_globals != NULL, NULL);
- PyObject *script = PyDict_GetItemString(frame->f_globals, "_script");
- if (script)
- {
- /*
- PySys_WriteStdout("Found script at %s in %s, script -> 0x%x\n",
- PyString_AS_STRING(frame->f_code->co_name),
- PyString_AS_STRING(frame->f_code->co_filename), script);
- */
- return script;
- }
- }
-
- return NULL;
-}
-
int pymodule_init(void)
{
g_return_val_if_fail(py_module == NULL, 0);
diff --git a/pysignals.c b/pysignals.c
index 4e6d4ee..95718aa 100644
--- a/pysignals.c
+++ b/pysignals.c
@@ -6,12 +6,13 @@
/* NOTE:
* There are two different records used to store signal related data:
* PY_SIGNAL_SPEC_REC and PY_SIGNAL_REC. Each SPEC_REC declares a "plain"
- * signal, or a type of "variable" signal.
+ * signal, or a type of "variable" signal. Each PY_SIGNAL_REC stores data
+ * about a handler for a signal.
*
- * Plain signals are emitted by Irssi the same way every time, using the
- * same text. They are never extended or altered in any way. Plain signals
- * make up the vast majority of Irssi signals. These include (some random
- * examples): "beep", "printtext", "log new", "ban new", etc.
+ * Plain signals are emitted using the same text every time. They are never
+ * extended or altered in any way. Plain signals make up the vast majority
+ * of Irssi signals. These include (some random examples): "beep",
+ * "printtext", "log new", "ban new", etc.
*
* Variable signals are emitted by joining a common prefix with text that
* varies from emit to emit. These are signals that have a "<cmd>" suffix
@@ -21,23 +22,23 @@
* user types /nick yournick at the prompt.
*
* While PY_SIGNAL_SPEC_REC stores data about each individual signal,
- * PY_SIGNAL_REC stores data about each consumer of a signal (or command).
+ * PY_SIGNAL_REC stores data about each handler of a signal (or command).
* A listing of SPEC_REC entries is stored globally in this module for each
- * signal known to irssi-python. Each Script holds a list PY_SIGNAL_REC entries
- * to remember signals and commands bound by the script. This allows for easy
- * cleanup when the script is unloaded. The PY_SIGNAL_REC data includes
- * references to a callable PyObject and a PY_SIGNAL_SPEC_REC entry for the
- * signal.
+ * signal known to irssi-python. Each Script holds a list of PY_SIGNAL_REC
+ * entries to remember signals and commands bound by the script. The
+ * PY_SIGNAL_REC data includes references to a callable PyObject and a
+ * PY_SIGNAL_SPEC_REC entry for the argument type list of the signal.
*
* Signals must be registered to be accessible to Python scripts.
* Registering a dynamic signal adds a new SPEC_REC with a refcount of 1.
- * If another script registers the same signal, refcount is incremented.
- * Binding to the signal also increments its reference count. Likewise,
- * unregistering or unbinding a dynamic signal will decrement its refcount.
- * When refcount hits 0, the dynamic signal is removed from the list, and
- * scripts can no longer bind to it. Built-in signals in the sigmap are
- * never removed; it is an error for the refcount of any such signal entry
- * to drop to 0.
+ * If another script registers the same signal, the original entry's refcount
+ * is incremented. Binding to the signal also increments its reference count.
+ * Likewise, unregistering or unbinding a dynamic signal will decrement its
+ * refcount. When refcount hits 0, the dynamic signal is removed from the list,
+ * and scripts can no longer bind to or emit the signal untill it is
+ * re-registered. Built-in signals in the sigmap are not from the heap and are
+ * never removed; it is an error for the refcount of any such signal entry to
+ * drop to 0.
*/
typedef struct _PY_SIGNAL_SPEC_REC
diff --git a/pysource.c b/pysource.c
index f3a0663..413ab2c 100644
--- a/pysource.c
+++ b/pysource.c
@@ -4,153 +4,127 @@
typedef struct _PY_SOURCE_REC
{
- int once;
int tag;
+ GSList **tag_list;
int fd;
- GSList **container; /* "container" points to a list owned by a Script object */
- PyObject *handler;
+ PyObject *func;
PyObject *data;
} PY_SOURCE_REC;
-static PY_SOURCE_REC *py_source_new(GSList **list, int once, PyObject *handler, PyObject *data)
+static PY_SOURCE_REC *py_source_rec_new(GSList **tag_list, int fd, PyObject *func, PyObject *data)
{
PY_SOURCE_REC *rec;
rec = g_new0(PY_SOURCE_REC, 1);
- rec->once = once;
- rec->fd = -1;
- rec->handler = handler;
+ rec->tag_list = tag_list;
+ rec->fd = fd;
+ rec->func = func;
rec->data = data;
- rec->container = list;
- Py_INCREF(handler);
- Py_XINCREF(data);
+ Py_INCREF(func);
+ Py_XINCREF(data);
return rec;
}
+static int py_remove_tag(GSList **list, int handle)
+{
+ GSList *node;
+
+ node = g_slist_find(*list, GINT_TO_POINTER(handle));
+ if (!node)
+ return 0;
+
+ *list = g_slist_delete_link(*list, node);
+
+ return 1;
+}
+
static void py_source_destroy(PY_SOURCE_REC *rec)
{
- g_source_remove(rec->tag);
- Py_DECREF(rec->handler);
+ g_return_if_fail(py_remove_tag(rec->tag_list, rec->tag) == 1);
+ Py_DECREF(rec->func);
Py_XDECREF(rec->data);
g_free(rec);
}
-static int py_source_proxy(PY_SOURCE_REC *rec)
+static int py_handle_ret(PyObject *ret)
{
- char args[3] = {0,0,0};
- int fd;
- PyObject *ret;
- PyObject *handler, *data;
-
- /* Copy data out of the rec (there's not much). The rec may be deleted in
- the if block below or by the Python code executed. Protect handler & data
- with INCREF.
- */
+ int res;
- fd = rec->fd;
- handler = rec->handler;
- data = rec->data;
- Py_INCREF(handler);
- Py_XINCREF(data);
-
- if (rec->once)
+ if (!ret)
{
- *rec->container = g_slist_remove(*rec->container, rec);
- py_source_destroy(rec);
+ PyErr_Print();
+ res = FALSE;
+ }
+ else
+ {
+ res = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
}
- /* call python function with fd and/or data if available.
- IO handler will be called with either "iO" or "i".
- Timeout with "O" or "".
- */
+ return res;
+}
- if (fd >= 0)
- {
- /* IO handler */
- args[0] = 'i';
- if (data)
- args[1] = 'O';
+static int py_timeout_proxy(PY_SOURCE_REC *rec)
+{
+ PyObject *ret;
- ret = PyObject_CallFunction(handler, args, fd, data);
- }
+ g_return_val_if_fail(rec != NULL, FALSE);
+
+ if (rec->data)
+ ret = PyObject_CallFunction(rec->func, "O", rec->data);
else
- {
- /* Timeout handler */
- if (data)
- args[0] = 'O';
+ ret = PyObject_CallFunction(rec->func, "");
- ret = PyObject_CallFunction(handler, args, data);
- }
+ return py_handle_ret(ret);
+}
- if (!ret)
- PyErr_Print();
+static int py_io_proxy(GIOChannel *src, GIOCondition condition, PY_SOURCE_REC *rec)
+{
+ PyObject *ret;
+
+ g_return_val_if_fail(rec != NULL, FALSE);
+
+ if (rec->data)
+ ret = PyObject_CallFunction(rec->func, "iiO", rec->fd, condition, rec->data);
else
- Py_DECREF(ret);
+ ret = PyObject_CallFunction(rec->func, "ii", rec->fd, condition);
- Py_DECREF(handler);
- Py_XDECREF(data);
-
- return 1;
+ return py_handle_ret(ret);
}
-int pysource_timeout_add_list(GSList **list, int msecs, PyObject *func, PyObject *data, int once)
+int pysource_timeout_add_list(GSList **list, int msecs, PyObject *func, PyObject *data)
{
PY_SOURCE_REC *rec;
g_return_val_if_fail(func != NULL, -1);
- rec = py_source_new(list, once, func, data);
- rec->tag = g_timeout_add(msecs, (GSourceFunc)py_source_proxy, rec);
-
- *list = g_slist_append(*list, rec);
-
+ rec = py_source_rec_new(list, -1, func, data);
+ rec->tag = g_timeout_add_full(G_PRIORITY_DEFAULT, msecs,
+ (GSourceFunc)py_timeout_proxy, rec,
+ (GDestroyNotify)py_source_destroy);
+
+ *list = g_slist_append(*list, GINT_TO_POINTER(rec->tag));
+
return rec->tag;
}
-int pysource_input_add_list(GSList **list, int fd, int cond, PyObject *func, PyObject *data, int once)
+int pysource_io_add_watch_list(GSList **list, int fd, int cond, PyObject *func, PyObject *data)
{
PY_SOURCE_REC *rec;
GIOChannel *channel;
g_return_val_if_fail(func != NULL, 1);
- rec = py_source_new(list, once, func, data);
- rec->fd = fd;
+
+ rec = py_source_rec_new(list, fd, func, data);
channel = g_io_channel_unix_new(fd);
- rec->tag = g_input_add(channel, cond, (GInputFunction)py_source_proxy, rec);
+ rec->tag = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
+ (GIOFunc)py_io_proxy, rec,
+ (GDestroyNotify)py_source_destroy);
g_io_channel_unref(channel);
- *list = g_slist_append(*list, rec);
+ *list = g_slist_append(*list, GINT_TO_POINTER(rec->tag));
return rec->tag;
}
-
-int pysource_remove_tag(GSList **list, int handle)
-{
- GSList *node;
-
- for (node = *list; node != NULL; node = node->next)
- {
- PY_SOURCE_REC *rec = node->data;
-
- if (rec->tag == handle)
- {
- py_source_destroy(rec);
- *list = g_slist_delete_link(*list, node);
-
- return 1;
- }
- }
-
- return 0;
-}
-
-void pysource_remove_list(GSList *list)
-{
- GSList *node;
-
- for (node = list; node != NULL; node = node->next)
- py_source_destroy(node->data);
-}
-
diff --git a/pysource.h b/pysource.h
index 23903d5..78b55ec 100644
--- a/pysource.h
+++ b/pysource.h
@@ -4,10 +4,7 @@
#include <Python.h>
/* condition is G_INPUT_READ or G_INPUT_WRITE */
-int pysource_input_add_list(GSList **list, int fd, int cond, PyObject *func, PyObject *data, int once);
-int pysource_timeout_add_list(GSList **list, int msecs, PyObject *func, PyObject *data, int once);
-
-int pysource_remove_tag(GSList **list, int handle);
-void pysource_remove_list(GSList *list);
+int pysource_io_add_watch_list(GSList **list, int fd, int cond, PyObject *func, PyObject *data);
+int pysource_timeout_add_list(GSList **list, int msecs, PyObject *func, PyObject *data);
#endif
diff --git a/pythemes.c b/pythemes.c
new file mode 100644
index 0000000..009c2ab
--- /dev/null
+++ b/pythemes.c
@@ -0,0 +1,238 @@
+#include <Python.h>
+#include "pythemes.h"
+#include "pyirssi.h"
+#include "factory.h"
+#include "pymodule.h"
+#include "pyloader.h"
+
+/* Edited from Perl Themes.xs */
+int pythemes_printformat(TEXT_DEST_REC *dest, const char *script, const char *format, PyObject *argtup)
+{
+ char *arglist[MAX_FORMAT_PARAMS + 1];
+ THEME_REC *theme;
+ char *str;
+ int formatnum;
+ int i;
+
+ formatnum = format_find_tag(script, format);
+ if (formatnum < 0) {
+ PyErr_Format(PyExc_KeyError, "unregistered format '%s'", format);
+ return 0;
+ }
+
+ memset(arglist, 0, sizeof arglist);
+ for (i = 0; i < MAX_FORMAT_PARAMS && i < PyTuple_Size(argtup); i++) {
+ PyObject *obj = PyTuple_GET_ITEM(argtup, i);
+ char *str;
+
+ if (!PyString_Check(obj)) {
+ PyErr_Format(PyExc_TypeError, "format argument list contains non-string data");
+ return 0;
+ }
+
+ str = PyString_AsString(obj);
+ if (!str)
+ return 0;
+
+ arglist[i] = str;
+ }
+
+ theme = window_get_theme(dest->window);
+ signal_emit("print format", 5, theme, script,
+ dest, GINT_TO_POINTER(formatnum), arglist);
+
+ str = format_get_text_theme_charargs(theme, script, dest, formatnum, arglist);
+ if (*str != '\0') printtext_dest(dest, "%s", str);
+ g_free(str);
+
+ return 1;
+}
+
+static void py_destroy_format_list(FORMAT_REC *recs)
+{
+ int i;
+
+ for (i = 0; recs[i].def; i++)
+ {
+ g_free(recs[i].def);
+ g_free(recs[i].tag);
+ }
+
+ g_free(recs);
+}
+
+/* register a list of formats in this format:
+ * [ (name, format), ... ]
+ */
+int pythemes_register(const char *script, PyObject *list)
+{
+ FORMAT_REC *formatrecs;
+ int i;
+
+ if (!PyList_Check(list))
+ {
+ PyErr_Format(PyExc_TypeError, "arg must be list");
+ return 0;
+ }
+
+ if (PyList_Size(list) == 0)
+ {
+ PyErr_Format(PyExc_TypeError, "cannot register empty list");
+ return 0;
+ }
+
+ if (g_hash_table_lookup(default_formats, script))
+ {
+ PyErr_Format(PyExc_KeyError, "format list already registered by script");
+ return 0;
+ }
+
+ formatrecs = g_new0(FORMAT_REC, PyList_Size(list) + 2);
+ formatrecs[0].tag = g_strdup(script);
+ formatrecs[0].tag = g_strdup("Python script");
+
+ for (i = 0; i < PyList_Size(list); i++)
+ {
+ FORMAT_REC *rec;
+ PyObject *item;
+ char *key, *value;
+
+ rec = &formatrecs[i + 1];
+ item = PyList_GET_ITEM(list, i);
+ if (!PyArg_ParseTuple(item, "ss", &key, &value))
+ {
+ if (PyErr_ExceptionMatches(PyExc_TypeError))
+ {
+ PyErr_Clear();
+ PyErr_Format(PyExc_TypeError, "format list must contain tuples of two strings");
+ }
+ py_destroy_format_list(formatrecs);
+ return 0;
+ }
+
+ rec->tag = g_strdup(key);
+ rec->def = g_strdup(value);
+ rec->params = MAX_FORMAT_PARAMS;
+ }
+
+ theme_register_module(script, formatrecs);
+
+ return 1;
+}
+
+void pythemes_unregister(const char *script)
+{
+ FORMAT_REC *formats;
+
+ formats = g_hash_table_lookup(default_formats, script);
+ if (!formats)
+ return;
+
+ py_destroy_format_list(formats);
+ theme_unregister_module(script);
+}
+
+PyDoc_STRVAR(py_printformat_doc,
+ "printformat(level, format, ...) -> None\n"
+);
+static PyObject *py_printformat(PyObject *self, PyObject *all)
+{
+ int level = 0;
+ char *format = "";
+ PyObject *args = NULL, *varargs = NULL;
+ TEXT_DEST_REC dest;
+ char *script;
+
+ args = PySequence_GetSlice(all, 0, 2);
+ if (!args)
+ goto error;
+
+ varargs = PySequence_GetSlice(all, 2, PyTuple_Size(all));
+ if (!varargs)
+ goto error;
+
+ if (!PyArg_ParseTuple(args, "is", &level, &format))
+ goto error;
+
+ script = pyloader_find_script_name();
+ if (!script)
+ {
+ PyErr_Format(PyExc_RuntimeError, "No script found");
+ goto error;
+ }
+
+ format_create_dest(&dest, NULL, NULL, level, NULL);
+ if (!pythemes_printformat(&dest, script, format, varargs))
+ goto error;
+
+ Py_DECREF(args);
+ Py_DECREF(varargs);
+
+ Py_RETURN_NONE;
+
+error:
+ Py_XDECREF(args);
+ Py_XDECREF(varargs);
+
+ return NULL;
+}
+
+static int py_add_module_func(PyMethodDef *mdef)
+{
+ PyObject *func;
+
+ g_return_val_if_fail(py_module != NULL, 0);
+
+ func = PyCFunction_New(mdef, NULL);
+ if (!func)
+ return 0;
+
+ if (PyModule_AddObject(py_module, mdef->ml_name, func) != 0)
+ {
+ Py_DECREF(func);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int py_add_method(PyTypeObject *type, PyMethodDef *mdef)
+{
+ int ret;
+ PyObject *func;
+
+ g_return_val_if_fail(type->tp_dict != NULL, 0);
+
+ func = PyDescr_NewMethod(type, mdef);
+ if (!func)
+ return 0;
+
+ ret = PyDict_SetItemString(type->tp_dict, mdef->ml_name, func);
+ Py_DECREF(func);
+ if (ret != 0)
+ return 0;
+
+ return 1;
+}
+
+int pythemes_init(void)
+{
+ static PyMethodDef pfdef = {"printformat", (PyCFunction)py_printformat,
+ METH_VARARGS, py_printformat_doc};
+
+ /* add function to main module and as member some types */
+
+ if (!py_add_module_func(&pfdef))
+ return 0;
+
+ if (!py_add_method(&PyServerType, &pfdef))
+ return 0;
+
+ if (!py_add_method(&PyWindowType, &pfdef))
+ return 0;
+
+ if (!py_add_method(&PyWindowItemType, &pfdef))
+ return 0;
+
+ return 1;
+}
diff --git a/pythemes.h b/pythemes.h
new file mode 100644
index 0000000..92af965
--- /dev/null
+++ b/pythemes.h
@@ -0,0 +1,13 @@
+#ifndef _PYTHEMES_H_
+#define _PYTHEMES_H_
+
+#include <Python.h>
+
+struct _TEXT_DEST_REC;
+
+int pythemes_printformat(struct _TEXT_DEST_REC *dest, const char *script, const char *format, PyObject *argtup);
+int pythemes_register(const char *script, PyObject *list);
+void pythemes_unregister(const char *script);
+int pythemes_init(void);
+
+#endif