summaryrefslogtreecommitdiffstats
path: root/dcoppython/shell
diff options
context:
space:
mode:
Diffstat (limited to 'dcoppython/shell')
-rw-r--r--dcoppython/shell/Makefile.am25
-rw-r--r--dcoppython/shell/gen_marshal_code.py276
-rw-r--r--dcoppython/shell/importedmodules.cpp49
-rw-r--r--dcoppython/shell/importedmodules.h37
-rw-r--r--dcoppython/shell/marshal_funcs.data597
-rw-r--r--dcoppython/shell/marshal_funcs_doc.xsl40
-rw-r--r--dcoppython/shell/marshaller.cpp169
-rw-r--r--dcoppython/shell/marshaller.h71
-rw-r--r--dcoppython/shell/pcop.cpp770
-rw-r--r--dcoppython/shell/pcop.h202
10 files changed, 2236 insertions, 0 deletions
diff --git a/dcoppython/shell/Makefile.am b/dcoppython/shell/Makefile.am
new file mode 100644
index 00000000..3ec2906f
--- /dev/null
+++ b/dcoppython/shell/Makefile.am
@@ -0,0 +1,25 @@
+
+BUILT_SOURCES = marshal_funcs.h
+CLEANFILES = marshal_funcs.h marshal_funcs_doc.html marshal_funcs_doc.xml
+
+doc: marshal_funcs_doc.html
+
+marshal_funcs.h marshal_funcs.xml: $(srcdir)/marshal_funcs.data
+ $(PYTHON) $(srcdir)/gen_marshal_code.py $(srcdir)/marshal_funcs.data marshal_funcs.h marshal_funcs_doc.xml
+
+marshal_funcs_doc.html: $(srcdir)/marshal_funcs_doc.xsl marshal_funcs_doc.xml
+ $(XSLTPROC) $(srcdir)/marshal_funcs_doc.xsl marshal_funcs_doc.xml >marshal_funcs_doc.html
+
+INCLUDES = $(PYTHONINC) $(all_includes)
+
+pythlib_LTLIBRARIES = pcop.la
+pythlibdir = $(PYTHONMODDIR)/site-packages
+
+pcop_la_SOURCES = pcop.cpp marshaller.cpp importedmodules.cpp
+pcop_la_LDFLAGS = $(all_libraries) -module -avoid-version
+pcop_la_LIBADD = -lDCOP -lkdecore $(LIB_QT)
+
+noinst_HEADERS = pcop.h marshaller.h marshal_funcs.h importedmodules.h
+
+
+
diff --git a/dcoppython/shell/gen_marshal_code.py b/dcoppython/shell/gen_marshal_code.py
new file mode 100644
index 00000000..73cb1fd0
--- /dev/null
+++ b/dcoppython/shell/gen_marshal_code.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python
+# Julian Rockey 2003
+# Generate marshall/demarshal functions from marshal_funcs.data file
+
+import sys
+import re
+
+def cap_first(str):
+ """Capitalise first letter of string."""
+ return str[0].upper() + str[1:]
+
+def set_method(attr):
+ """Return the name for a QT class setter method for an attribute."""
+ return "set" + cap_first(attr)
+
+class DictMaker:
+ """Generate code for marshalling/demarshalling types using Python dictionaries."""
+
+ supported_types = ['string']
+ re_dictmap = re.compile("%dict\-map(.*)")
+ re_dictmap_constructor = re.compile("%constructor (.+)")
+
+ def __init__(self):
+ self.attr_list = []
+ self.current_type = None
+ self.operation = None
+ self.constructor = None
+
+ self.type_handlers = {}
+ for type in self.supported_types:
+ self.type_handlers[type] = (eval('self.handle_%s_marsh' % type),
+ eval('self.handle_%s_demarsh' % type))
+
+ def handle_string_marsh(self, attribute):
+ """Handle marshalling of string item from the dictionary."""
+ return ["if (%s && !PyString_Check(%s)) return false;" % (attribute, attribute),
+ "if (%s) { qobj.%s(QString(PyString_AsString(%s)));" % (attribute, set_method(attribute), attribute),
+ "PyDict_DelItemString(dict,(char*)\"%s\"); } " % (attribute)]
+
+ def handle_string_demarsh(self, attribute):
+ """Handle demarshalling of string items into the dictionary."""
+ return ["PyObject *%s = PyString_FromString(qobj.%s().utf8().data() );" % (attribute ,attribute),
+ "PyDict_SetItemString(dict, (char*)\"%s\", %s);" % (attribute, attribute)
+ ]
+
+ def pre_code_for(self, operation, attribute):
+
+ if operation==MARSHAL:
+ return ["PyObject *%s = PyDict_GetItemString(dict,(char*)\"%s\");" % (attribute, attribute) ]
+
+ return []
+
+ def post_code_for(self, operation, attribute):
+ return []
+
+ def code_for(self, operation, type, attribute):
+ if operation!=None and (type in self.type_handlers):
+ return self.pre_code_for(operation, attribute) + \
+ self.type_handlers[type][not not operation](attribute) + \
+ self.post_code_for(operation, attribute)
+
+ return []
+
+ def set_current_type(self, current_type):
+ self.current_type = current_type
+ self.constructor = "";
+
+ def set_operation(self, operation):
+ if operation in [None, MARSHAL, DEMARSHAL]:
+ self.operation = operation
+
+ def check_dictmap(self, line):
+
+ if self.operation not in [MARSHAL,DEMARSHAL]: return []
+
+ m=self.re_dictmap_constructor.match(line)
+ if m:
+ self.constructor = m.groups()[0]
+ return ['']
+
+ m=self.re_dictmap.match(line)
+ if not m: return []
+
+ if self.operation==MARSHAL:
+ result = ["{",
+ "if (!PyDict_Check(obj)) return false;",
+ "%s qobj%s;" % (self.current_type,self.constructor),
+ "PyObject *dict = PyDict_Copy(obj);"
+ ]
+ if self.operation==DEMARSHAL:
+ result = ["{",
+ "PyObject *dict = PyDict_New();",
+ "if (!dict) return NULL;",
+ "%s qobj%s;" % (self.current_type,self.constructor),
+ "(*str) >> qobj;"
+ ]
+
+ if m.groups()[0].strip():
+ self.attr_list = [tuple(x.split(':')) for x in m.groups()[0].strip().split(',') ]
+
+ for attribute, type in self.attr_list:
+ result += self.code_for(self.operation, type, attribute)
+
+ if self.operation==MARSHAL:
+ result += ["if (str) (*str) << qobj;",
+ "Py_DECREF(dict);",
+ "return true;",
+ "}"
+ ]
+ if self.operation==DEMARSHAL:
+ result += ["return dict;",
+ "}"
+ ]
+
+ return result
+
+class DocType:
+ """A class to hold documentation information for each type."""
+
+ def __init__(self, type):
+ self.type = type
+ self.demarshal_as = None
+ self.as = []
+ self.info = []
+
+ def add_as(self, as):
+ if self.demarshal_as == None: self.demarshal_as = as
+ self.as += [as]
+
+ def add_info(self,info):
+ self.info += [info]
+
+ def xml(self):
+ return ['<type dcoptype="%s">' % self.type,
+ ' <demarshal-as>%s</demarshal-as>' % self.demarshal_as] + \
+ [' <marshal-as>%s</marshal-as>' % as for as in self.as ] + \
+ [' <info>%s</info>' % info for info in self.info ] + \
+ ['</type>']
+
+
+MARSHAL, DEMARSHAL, TOPYOBJ, FROMPYOBJ = 0,1,2,3
+
+if len(sys.argv)!=4:
+ print "Use: gen_marshal_code.py <input file> <output file> <doc-xml-output file>"
+ raise RuntimeError
+
+nowt, in_name, code_name, doc_xml_name = tuple(sys.argv)
+
+##in_name, code_name, doc_xml_name = "marshal_funcs.data", "marshal_funcs.h", "marshal_funcs_doc.xml"
+
+gen_code_comments = ['/*',
+ ' * This code was generated by gen_marshal_code.py',
+ ' * Please do not modify, or it\'ll be overwritten!',
+ ' */',
+ ' ',
+ ]
+
+re_type = re.compile(r"type\: *([^\s]+).*")
+re_marshDemarsh = re.compile("%% *(de)?marshal *.*")
+re_tofromPyobj = re.compile("%% *(to|from)_pyobj *.*")
+re_defaultCode = re.compile("%defaultcode *.*")
+re_docInfo = re.compile("%doc *([^ ]+) *(.*)")
+
+in_file = open(in_name,"r")
+code = []
+
+types = {}
+doc_types = {}
+current_operation = None
+
+dict_maker = DictMaker()
+
+for l in in_file.readlines():
+ l=l[:-1]
+
+ # match a "type:" line
+ m=re_type.match(l)
+ if m:
+ current_type = m.groups()[0]
+ types[current_type]={}
+ doc_types[current_type] = DocType(current_type)
+ dict_maker.set_current_type(current_type)
+ continue
+
+ m=re_docInfo.match(l)
+ if m:
+ doc_cmd, rest = m.groups()
+ if doc_cmd=="as":
+ doc_types[current_type].add_as(rest)
+ if doc_cmd=="info":
+ doc_types[current_type].add_info(rest)
+ continue
+
+ # match a "%% marshal" or "%% demarshal" line
+ m=re_marshDemarsh.match(l)
+ if m:
+ if m.groups()[0]:
+ current_operation = DEMARSHAL
+ code.append("PyObject *demarshal_" + current_type + \
+ "(QDataStream *str)")
+ else:
+ current_operation = MARSHAL
+ code.append("bool marshal_" + current_type + \
+ "(PyObject *obj, QDataStream *str)")
+ dict_maker.set_operation(current_operation)
+ continue
+
+ m=re_tofromPyobj.match(l)
+ if m:
+ if m.groups()[0]=='to':
+ current_operation = TOPYOBJ
+ code += ["PyObject *toPyObject_%s(%s val)" % (current_type,current_type)]
+ elif m.groups()[0]=='from':
+ current_operation = FROMPYOBJ
+ code += ["%s fromPyObject_%s(PyObject *obj, bool *ok)" % (current_type,current_type)]
+ continue
+
+
+ if l.strip()=='%%':
+ current_operation = None
+ dict_maker.set_operation(current_operation)
+
+ if current_operation!=None:
+ types[current_type][current_operation]=1
+
+ dict_code = dict_maker.check_dictmap(l)
+ if dict_code:
+ code += dict_code
+ continue
+
+ m=re_defaultCode.match(l)
+ if m:
+ if current_operation==MARSHAL:
+ code += [
+ "{",
+ " bool ok;",
+ " %s qobj=fromPyObject_%s(obj,&ok);" % (current_type,current_type),
+ " if (ok && str) (*str) << qobj;",
+ " return ok;",
+ "}"
+ ]
+ continue
+ if current_operation==DEMARSHAL:
+ code += [
+ "{",
+ " %s qobj;" % current_type,
+ " (*str) >> qobj;",
+ " return toPyObject_%s(qobj);" % current_type,
+ "}"
+ ]
+ continue
+
+ code.append(l)
+
+in_file.close()
+
+code.append("void Marshaller::initFuncs() {")
+for t in types:
+ if MARSHAL in types[t]:
+ code.append("m_marsh_funcs[\"" + t + "\"]=marshal_" + t + ";")
+ if DEMARSHAL in types[t]:
+ code.append("m_demarsh_funcs[\"" + t + "\"]=demarshal_" + t + ";")
+code.append("}")
+
+out_file = open(code_name,"w")
+out_file.writelines([x + '\n' for x in gen_code_comments])
+out_file.writelines([x + '\n' for x in code])
+out_file.close()
+
+xml_file = file(doc_xml_name,"w")
+print >>xml_file, '<?xml version="1.0" ?>'
+print >>xml_file, '<!-- This file was auto-generated by gen_marshal_code.py. Changes will be lost! -->'
+print >>xml_file, "<types>"
+[ [xml_file.write(x+"\n") for x in doc.xml()] for doc in doc_types.values() ] # silly one-liner
+print >>xml_file, "</types>"
+xml_file.close()
diff --git a/dcoppython/shell/importedmodules.cpp b/dcoppython/shell/importedmodules.cpp
new file mode 100644
index 00000000..4b2a23bb
--- /dev/null
+++ b/dcoppython/shell/importedmodules.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey (kde@jrockey.com) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "importedmodules.h"
+
+#include <kdebug.h>
+
+namespace PythonDCOP {
+
+ ImportedModules *ImportedModules::m_instance = NULL;
+
+ ImportedModules::ImportedModules() : m_dcop_module(NULL)
+ {
+ m_dcop_module = PyImport_ImportModule( (char*)"pydcop" );
+ if ( !m_dcop_module )
+ kdDebug(70001) << "Could not import pydcop module" << endl;
+ }
+
+ ImportedModules::~ImportedModules()
+ {
+ }
+
+ PyObject* ImportedModules::createDCOPObject( const char* appname, const char* objname )
+ {
+ if ( !m_dcop_module )
+ return 0;
+
+ PyObject* dict = PyModule_GetDict( m_dcop_module );
+ if ( !dict )
+ return 0;
+
+ PyObject* cl = PyDict_GetItemString( dict, (char*)"DCOPObject" );
+ if ( !cl )
+ return 0;
+
+ PyObject* args = PyTuple_New( 2 );
+ PyTuple_SetItem( args, 0, PyString_FromString( appname ) );
+ PyTuple_SetItem( args, 1, PyString_FromString( objname ) );
+
+ return PyObject_CallObject( cl, args );
+ }
+
+}
diff --git a/dcoppython/shell/importedmodules.h b/dcoppython/shell/importedmodules.h
new file mode 100644
index 00000000..9d47f617
--- /dev/null
+++ b/dcoppython/shell/importedmodules.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey (kde@jrockey.com) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef __importedmodules_h__
+#define __importedmodules_h__
+
+#include <Python.h>
+
+namespace PythonDCOP {
+
+ /**
+ * Manages imported Python modules.
+ */
+ class ImportedModules {
+ public:
+ ImportedModules();
+ ~ImportedModules();
+ PyObject *createDCOPObject( const char* appname, const char* objname );
+ PyObject *dcop_module() const { return m_dcop_module; }
+
+ static ImportedModules *instance() { return m_instance; }
+ static void setInstance(ImportedModules *instance) { m_instance = instance; }
+
+ private:
+ PyObject *m_dcop_module;
+ static ImportedModules *m_instance;
+ };
+
+}
+
+#endif
diff --git a/dcoppython/shell/marshal_funcs.data b/dcoppython/shell/marshal_funcs.data
new file mode 100644
index 00000000..abb3a43e
--- /dev/null
+++ b/dcoppython/shell/marshal_funcs.data
@@ -0,0 +1,597 @@
+// This file contains the C++ code necessary marshal and demarshal
+// all the _simple_ types that dcoppython can understand.
+// "Simple" types are types that do not contain other types.
+// So, int and QString are simple types; QDict, QMap and QStringList are not.
+// This file is processed by gen_marshal_code.py to produce a header
+// file, which is included by marshaller.cpp
+//
+// Marshalling:
+// The code in the "marshal" section has the following variables available:
+// PyObject * obj; // the object to marshal
+// QDataStream *str; // the stream to marshal to
+// The function should return true if the object can be marshalled.
+// str may be NULL. If so, the function should ignore the actually marshalling
+// and merely return true or false, depending on whether the object _could_
+// be marshalled.
+//
+// Demarshalling:
+// The code in the "demarshal" section has the following variables available:
+// QDataStream *str; // the stream to demarshal from
+// The function should return a PyObject* which is a reference to the
+// newly created object. Ownership of the reference should be passed to
+// the caller. The function can return null if for any reason it
+// could not demarshal.
+
+type: void
+%% marshall
+{
+ Q_UNUSED(str); // stop warnings
+ Q_UNUSED(obj);
+ return true;
+}
+%% demarshal
+{
+ Q_UNUSED(str); // stop warnings
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+type: bool
+%doc as int b (1=True, 2=False)
+%doc info Any Python object is converted to bool by the standard Python truth test.
+%% from_pyobj
+ {
+ *ok=true;
+ return PyObject_IsTrue(obj);
+ }
+%% to_pyobj
+ {
+ return PyInt_FromLong(val ? 1 : 0);
+ }
+%% marshal
+ {
+ if (str) {
+ bool ok;
+ bool b = fromPyObject_bool(obj,&ok);
+ (*str) << (Q_INT8)b;
+ }
+ return true;
+ }
+%% demarshal
+ {
+ Q_INT8 i;
+ (*str) >> i;
+ return toPyObject_bool(i!=0);
+ }
+%%
+
+type:int
+%doc as int i
+%% marshal
+ {
+ if (!PyInt_Check(obj)) return false;
+ if (str) {
+ (*str) << (Q_INT32)PyInt_AsLong(obj);
+ }
+ return true;
+ }
+%% demarshal
+ {
+ Q_INT32 i;
+ (*str) >> i;
+ return PyInt_FromLong( (long)i );
+ }
+%%
+
+type:uint
+%doc as int i
+%% marshal
+ {
+ if (!PyInt_Check(obj)) return false;
+ if (str) {
+ (*str) << (Q_INT32)PyInt_AsLong(obj);
+ }
+ return true;
+ }
+%% demarshal
+ {
+ Q_INT32 i;
+ (*str) >> i;
+ return PyInt_FromLong( (long)i );
+ }
+%%
+
+type:double
+%doc as float i
+%% marshal
+ {
+ if (!PyFloat_Check(obj)) return false;
+ if (str) {
+ (*str) << PyFloat_AsDouble(obj);
+ }
+ return true;
+ }
+%% demarshal
+ {
+ double d;
+ (*str) >> d;
+ return PyFloat_FromDouble(d);
+ }
+%%
+
+type:uchar
+%doc as str c
+%doc as int c
+%% marshal
+ {
+ if (PyString_Check(obj) && PyString_Size(obj)==1) {
+ if (str) {
+ char *c = PyString_AsString(obj);
+ (*str) << (*c);
+ }
+ return true;
+ }
+
+ if (PyInt_Check(obj)) {
+ if (str) {
+ long l = PyInt_AsLong(obj);
+ Q_UINT8 c = (Q_UINT8)(l & 0xff);
+ (*str) << c;
+ }
+ return true;
+ }
+
+ return false;
+ }
+%%demarshal
+ {
+ Q_UINT8 c;
+ (*str) >> c;
+ return PyString_FromStringAndSize((const char *)(&c),1);
+ }
+%%
+
+type:char
+%doc as int c
+%% marshal
+ {
+ if (PyInt_Check(obj)) {
+ if (str) {
+ long l = PyInt_AsLong(obj);
+ Q_INT8 c = (Q_INT8)(l & 0xff);
+ (*str) << c;
+ }
+ return true;
+ }
+
+ return false;
+ }
+%%demarshal
+ {
+ Q_INT8 c;
+ (*str) >> c;
+ return PyInt_FromLong((long)c);
+ }
+%%
+
+
+type:QByteArray
+%% marshal
+ {
+ PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
+
+ if ( pb && pb->bf_getreadbuffer && pb->bf_getsegcount )
+ {
+ // Get the number of buffer segments
+ int seg_count = (pb->bf_getsegcount)(obj, 0);
+
+ if ( seg_count != 1 )
+ // Can't handle more (or less) than 1 buffer segment
+ // at the moment
+ return false;
+
+ // Get buffer size and data
+ void *data;
+ int size;
+
+ if ( (size = (pb->bf_getreadbuffer)(obj, 0, &data)) < 0 )
+ return false;
+
+ if (str) {
+ QByteArray a;
+ a.setRawData( (const char*)data, size );
+ (*str) << a;
+ a.resetRawData( (const char*)data, size );
+ }
+
+ return true;
+ }
+ else
+ // obj does not implement the buffer interface
+ return false;
+ }
+%% demarshal
+ {
+ // Demarshal to a writable buffer object
+ QByteArray a;
+ (*str) >> a;
+
+ uint size = a.size();
+ char *data = a.data();
+
+ // Create a new buffer object and copy the data.
+ // Don't use PyBuffer_FromMemory() and the likes since
+ // that wouldn't give correct allocation and deallocation.
+
+ PyObject *buffer_obj = PyBuffer_New( size );
+
+ if ( !buffer_obj )
+ return NULL;
+
+ PyBufferProcs *pb = buffer_obj->ob_type->tp_as_buffer;
+
+ void *buffer_data;
+
+ (pb->bf_getwritebuffer)( buffer_obj, 0, &buffer_data );
+
+ for ( uint i = 0; i < size; i++ )
+ ((char*)buffer_data)[i] = data[i];
+
+ return buffer_obj;
+ }
+%%
+
+type:QString
+%doc as str s
+%% marshal
+ {
+ if (!PyString_Check(obj)) return false;
+ if (str) {
+ QString s( PyString_AsString(obj) );
+ (*str) << s;
+ }
+ return true;
+ }
+%% demarshal
+ {
+ QString s;
+ (*str) >> s;
+ return PyString_FromString( s.utf8().data() );
+ }
+%%
+
+type:QCString
+%doc as str s
+%% marshal
+ {
+ if (!PyString_Check(obj)) return false;
+ if (str) {
+ QCString s( PyString_AsString(obj) );
+ (*str) << s;
+ }
+ return true;
+ }
+%% demarshal
+ {
+ QCString s;
+ (*str) >> s;
+ return PyString_FromString( s.data() );
+ }
+%%
+
+type:QRect
+%doc as ( (int x1, int y1), (int x2, int y2) )
+%doc as ( int x1, int y1, int x2, int y2 )
+%% from_pyobj
+{
+ int xp1, yp1, xp2, yp2;
+ QRect r;
+ *ok=false;
+ if (!PyTuple_Check(obj)) return r;
+ if (!PyArg_ParseTuple(obj, (char*)"(ii)(ii)", &xp1, &yp1, &xp2, &yp2) &&
+ !PyArg_ParseTuple(obj, (char*)"iiii", &xp1, &yp1, &xp2, &yp2))
+ return r;
+ r.setCoords( xp1, yp1, xp2, yp2 );
+ *ok=true;
+ return r;
+}
+%% to_pyobj
+{
+ int xp1, yp1, xp2, yp2;
+ val.coords(&xp1,&yp1,&xp2,&yp2);
+ return Py_BuildValue((char*)"(ii)(ii)", xp1, yp1, xp2, yp2);
+}
+
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+type:QPoint
+%doc as (int x, int y)
+%% from_pyobj
+{
+ int x,y;
+ QPoint p;
+ *ok=false;
+ if (!PyTuple_Check(obj)) return p;
+ if (!PyArg_ParseTuple(obj, (char*)"ii", &x, &y))
+ return p;
+ p.setX(x);
+ p.setY(y);
+ *ok=true;
+ return p;
+}
+%% to_pyobj
+{
+ return Py_BuildValue((char*)"ii", val.x(), val.y() );
+}
+%% marshall
+%defaultcode
+%% demarshall
+%defaultcode
+%%
+
+type:QSize
+%doc as (int width, int height)
+%% from_pyobj
+{
+ int w,h;
+ QSize sz;
+ *ok=false;
+ if (!PyTuple_Check(obj)) return sz;
+ if (!PyArg_ParseTuple(obj, (char*)"ii", &w, &h))
+ return sz;
+ sz.setWidth(w);
+ sz.setHeight(h);
+ *ok=true;
+ return sz;
+}
+%% to_pyobj
+{
+ return Py_BuildValue((char*)"ii", val.width(), val.height() );
+}
+%% marshall
+%defaultcode
+%% demarshall
+%defaultcode
+%%
+
+type:QColor
+%doc as (int red, int green, int blue)
+%% from_pyobj
+{
+ int r,g,b;
+ QColor c;
+ *ok=false;
+ if (!PyTuple_Check(obj)) return c;
+ if (!PyArg_ParseTuple(obj, (char*)"iii", &r, &g, &b))
+ return c;
+ c.setRgb(r,g,b);
+ *ok=true;
+ return c;
+}
+%% to_pyobj
+{
+ return Py_BuildValue((char*)"iii", val.red(), val.green(), val.blue() );
+}
+%% marshall
+%defaultcode
+%% demarshall
+%defaultcode
+%%
+
+type:QPointArray
+%doc as [ (int x, int y), (int x, int y), (int x, int y), ... ]
+%% from_pyobj
+{
+ *ok=false;
+ if (!PyList_Check(obj)) return QPointArray();
+ int size = PyList_Size(obj);
+ QPointArray pa(size);
+ for(int c=0;c<size;c++) {
+ QPoint p = fromPyObject_QPoint(PyList_GetItem(obj,c), ok);
+ if (!*ok) return false;
+ pa.setPoint(c,p);
+ }
+ *ok=true;
+ return pa;
+}
+%% to_pyobj
+{
+ PyObject *obj = PyList_New(val.size());
+ if (!obj) return NULL;
+ for(uint c=0;c<val.size();c++) {
+ PyObject *tuple = toPyObject_QPoint( val.point(c) );
+ PyList_SetItem(obj, c, tuple);
+// Py_DECREF(tuple);
+ }
+ return obj;
+}
+%% marshall
+%defaultcode
+%% demarshall
+%defaultcode
+%%
+
+type:QDate
+%doc as (int year, int month, int day)
+%% from_pyobj
+{
+ *ok=false;
+ if (!PyTuple_Check(obj)) return QDate();
+ int y,m,d;
+ if (!PyArg_ParseTuple(obj, (char*)"iii", &y, &m, &d))
+ return QDate();
+ *ok=true;
+ return QDate(y,m,d);
+}
+%% to_pyobj
+{
+ return Py_BuildValue((char*)"iii", val.year(), val.month(), val.day() );
+}
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+type:QTime
+%doc as (int hour, int minute, int second=0, int millisecond=0)
+%% from_pyobj
+{
+ *ok=false;
+ if (!PyTuple_Check(obj)) return QTime();
+ int h,m,s=0,ms=0;
+ if (!PyArg_ParseTuple(obj, (char*)"ii|ii", &h, &m, &s, &ms))
+ return QTime();
+ *ok=true;
+ return QTime(h,m,s,ms);
+}
+%% to_pyobj
+{
+ return Py_BuildValue((char*)"iiii", val.hour(), val.minute(), val.second(), val.msec() );
+}
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+type:QDateTime
+%doc as ( (int year, int month, int day), (int hour, int minute, int second=0, int millsecond=0) )
+%doc as long unixDate
+%% from_pyobj
+{
+ *ok=false;
+
+ if (PyLong_Check(obj)) {
+ *ok=true;
+ QDateTime dt;
+ dt.setTime_t( (uint)PyLong_AsLong(obj) );
+ return dt;
+ }
+
+ if (PyInt_Check(obj)) {
+ *ok=true;
+ QDateTime dt;
+ dt.setTime_t( (uint)PyInt_AsLong(obj) );
+ return dt;
+ }
+
+ PyObject *date_tuple, *time_tuple;
+ if (PyArg_ParseTuple(obj, (char*)"OO", &date_tuple, &time_tuple)) {
+ QDateTime dt;
+ dt.setTime( fromPyObject_QTime(time_tuple, ok) );
+ if (*ok) dt.setDate( fromPyObject_QDate(date_tuple, ok) );
+ return dt;
+ }
+
+ return QDateTime();
+}
+%% to_pyobj
+{
+ PyObject *date_tuple = toPyObject_QDate( val.date() );
+ PyObject *time_tuple = toPyObject_QTime( val.time() );
+ return Py_BuildValue((char*)"OO", date_tuple, time_tuple );
+}
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+type:KURL
+%doc as str url
+%% from_pyobj
+{
+ *ok=false;
+ if (!PyString_Check(obj)) return KURL();
+ *ok=true;
+ return KURL( QString(PyString_AsString(obj)) );
+}
+%% to_pyobj
+{
+ return PyString_FromString( val.prettyURL().utf8().data() );
+}
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+type:DCOPRef
+%% from_pyobj
+{
+ if (PyInstance_Check(obj) &&
+ PyObject_HasAttrString(obj, (char*)"appname") &&
+ PyObject_HasAttrString(obj, (char*)"name")) {
+ PyObject *appname = PyObject_GetAttrString(obj, (char*)"appname");
+ PyObject *name = PyObject_GetAttrString(obj, (char*)"name");
+ if (PyString_Check(appname) && PyString_Check(name)) {
+ char *c_appname = PyString_AsString(appname);
+ char *c_name = PyString_AsString(name);
+ DCOPRef ref;
+ ref.setRef(QCString(c_appname), QCString(c_name) );
+ Py_DECREF(appname);
+ Py_DECREF(name);
+ *ok=true;
+ return ref;
+ }
+ Py_DECREF(appname);
+ Py_DECREF(name);
+ }
+ *ok=false;
+ return DCOPRef();
+}
+%% to_pyobj
+{
+ if (val.isNull()) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return ImportedModules::instance()->createDCOPObject(val.app(), val.object() );
+}
+%% marshal
+%defaultcode
+%% demarshal
+%defaultcode
+%%
+
+
+// type:DCOPRef
+// %doc as (str app, str obj, str type)
+// %doc as (str app, str obj)
+// %% from_pyobj
+// {
+// *ok=false;
+// char *dcopref_app=NULL, *dcopref_obj=NULL, *dcopref_type=NULL;
+// if (PyArg_ParseTuple(obj,(char*)"ss|s", &dcopref_app, &dcopref_obj, &dcopref_type)) {
+// *ok=true;
+// if (dcopref_type) {
+// DCOPRef dr(QCString(dcopref_app), QCString(dcopref_obj), QCString(dcopref_type));
+// return dr;
+// }
+// DCOPRef dr(QCString(dcopref_app), QCString(dcopref_obj));
+// return dr;
+// }
+// return DCOPRef();
+// }
+// %% to_pyobj
+// {
+// return Py_BuildValue((char*)"sss", val.app().data(), val.obj().data(), val.type().data() );
+// }
+// %% marshal
+// %defaultcode
+// %% demarshal
+// %defaultcode
+// %%
+
+// type:QFont
+// %% marshal
+// %constructor ("default")
+// %dict-map family:string,rawName:string
+// %% demarshal
+// %dict-map
+// %%
diff --git a/dcoppython/shell/marshal_funcs_doc.xsl b/dcoppython/shell/marshal_funcs_doc.xsl
new file mode 100644
index 00000000..491c188c
--- /dev/null
+++ b/dcoppython/shell/marshal_funcs_doc.xsl
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+ <xsl:output method="html"/>
+
+ <xsl:template match="/">
+ <html>
+ <body>
+ <xsl:apply-templates/>
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="types">
+ <h1>DCOPPython supported types</h1>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="type">
+ <h2><xsl:value-of select="@dcoptype"/></h2>
+ <xsl:apply-templates select="demarshal-as"/>
+ <div>Argument of form:</div>
+ <div style="margin-left: 2cm">
+ <xsl:for-each select="marshal-as">
+ <b><xsl:value-of select="."/></b>
+ </xsl:for-each>
+ </div>
+ <xsl:apply-templates select="info"/>
+ </xsl:template>
+
+ <xsl:template match="demarshal-as">
+ <div>Returns as: <b><xsl:apply-templates/></b></div>
+ </xsl:template>
+
+ <xsl:template match="info">
+ <div><xsl:apply-templates/></div>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/dcoppython/shell/marshaller.cpp b/dcoppython/shell/marshaller.cpp
new file mode 100644
index 00000000..f2dd4d03
--- /dev/null
+++ b/dcoppython/shell/marshaller.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey *
+ * linux@jrockey.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "marshaller.h"
+
+#include "pcop.h"
+#include "importedmodules.h"
+
+#include <qdatastream.h>
+
+#include <qrect.h>
+#include <qfont.h>
+#include <qcolor.h>
+#include <qpointarray.h>
+#include <qdatetime.h>
+#include <dcopref.h>
+
+#include <kurl.h>
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#endif
+
+namespace PythonDCOP {
+
+#include "marshal_funcs.h"
+
+ Marshaller::Marshaller()
+ {
+ initFuncs();
+ }
+
+ Marshaller::~Marshaller()
+ {
+ }
+
+ bool Marshaller::marsh_private(const PCOPType &type,
+ PyObject *obj,
+ QDataStream *str) const
+ {
+
+ QString ty = type.type();
+
+ if (ty=="QStringList")
+ return marshalList(PCOPType("QString"), obj, str);
+ if (ty=="QCStringList")
+ return marshalList(PCOPType("QCString"), obj, str);
+ if (ty=="QValueList" && type.leftType())
+ return marshalList(*type.leftType(), obj, str);
+ if (ty=="QMap" && type.leftType() && type.rightType())
+ return marshalDict(*type.leftType(), *type.rightType(), obj, str);
+
+ if (!m_marsh_funcs.contains(ty)) return false;
+ return m_marsh_funcs[ty](obj,str);
+ }
+
+ PyObject *Marshaller::demarsh_private(const PCOPType &type,
+ QDataStream *str) const
+ {
+ QString ty = type.type();
+
+ if (ty=="QStringList")
+ return demarshalList(PCOPType("QString"), str);
+ if (ty=="QCStringList")
+ return demarshalList(PCOPType("QCString"), str);
+ if (ty=="QValueList" && type.leftType())
+ return demarshalList(*type.leftType(), str);
+ if (ty=="QMap" && type.leftType() && type.rightType())
+ return demarshalDict(*type.leftType(), *type.rightType(), str);
+
+ if (!m_demarsh_funcs.contains(ty)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ PyObject *result = m_demarsh_funcs[ty](str);
+ if (!result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return result;
+ }
+
+ bool Marshaller::marshalList(const PCOPType &list_type,
+ PyObject *obj,
+ QDataStream *str) const {
+ if (!PyList_Check(obj)) return false;
+
+ int count = PyList_Size(obj);
+
+ for(int c=0;c<count;c++)
+ if (!list_type.isMarshallable( PyList_GetItem(obj,c) ) )
+ return false;
+
+ if (str) {
+ (*str) << (Q_INT32)count;
+ for(int c=0; c<count; c++)
+ list_type.marshal( PyList_GetItem(obj,c), *str );
+ }
+
+ return true;
+ }
+
+ PyObject *Marshaller::demarshalList(const PCOPType &list_type,
+ QDataStream *str) const {
+ Q_UINT32 count;
+ (*str) >> count;
+
+ PyObject *obj = PyList_New(count);
+ for(Q_UINT32 c=0;c<count;c++) {
+ PyList_SetItem(obj, c, list_type.demarshal(*str));
+ }
+ return obj;
+ }
+
+ bool Marshaller::marshalDict(const PCOPType &key_type,
+ const PCOPType &value_type,
+ PyObject *obj,
+ QDataStream *str) const {
+ if (!PyDict_Check(obj)) return false;
+
+
+ Py_ssize_t c=0;
+ PyObject *key, *val;
+ while (PyDict_Next(obj, &c, &key, &val)==1)
+ if (!key_type.isMarshallable(key) ||
+ !value_type.isMarshallable(val))
+ return false;
+
+ if (str) {
+ Q_INT32 count = (Q_INT32)PyDict_Size(obj);
+ (*str) << count;
+ c=0;
+ while (PyDict_Next(obj, &c, &key, &val)==1) {
+ key_type.marshal(key,*str);
+ value_type.marshal(val,*str);
+ }
+ }
+ return true;
+ }
+
+ PyObject *Marshaller::demarshalDict(const PCOPType &key_type,
+ const PCOPType &value_type,
+ QDataStream *str) const {
+ PyObject *obj = PyDict_New();
+ Q_INT32 count;
+ (*str) >> count;
+ for(Q_INT32 c=0;c<count;c++) {
+ PyObject *key = key_type.demarshal(*str);
+ PyObject *value = value_type.demarshal(*str);
+ PyDict_SetItem(obj,key,value);
+ }
+ return obj;
+ }
+
+
+ Marshaller *Marshaller::m_instance = new Marshaller;
+
+
+}
+
diff --git a/dcoppython/shell/marshaller.h b/dcoppython/shell/marshaller.h
new file mode 100644
index 00000000..920afb05
--- /dev/null
+++ b/dcoppython/shell/marshaller.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey *
+ * linux@jrockey.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef __marshaller_h__
+#define __marshaller_h__
+
+#include <qmap.h>
+#include <Python.h>
+#include <qstring.h>
+
+class QDataStream;
+
+namespace PythonDCOP {
+// class Marshaller;
+ class PCOPType;
+
+ class Marshaller {
+ public:
+ Marshaller();
+ ~Marshaller();
+ bool marshal(const PCOPType &type, PyObject *obj, QDataStream &str) const
+ { return marsh_private(type,obj,&str); }
+ bool canMarshal(const PCOPType &type, PyObject *obj) const
+ { return marsh_private(type,obj,NULL); }
+ bool marshalList(const PCOPType &list_type, PyObject *obj, QDataStream *str) const;
+ PyObject *demarshal(const PCOPType &type, QDataStream &str) const
+ { return demarsh_private(type, &str); }
+ PyObject *demarshalList(const PCOPType &list_type, QDataStream *str) const;
+ bool marshalDict(const PCOPType &key_type, const PCOPType &value_type,
+ PyObject *obj, QDataStream *str) const;
+ PyObject *demarshalDict(const PCOPType &key_type,
+ const PCOPType &value_type,
+ QDataStream *str) const;
+ static Marshaller *instance() { return m_instance; }
+ protected:
+ QMap<QString,bool(*)(PyObject*,QDataStream*)> m_marsh_funcs;
+ QMap<QString,PyObject*(*)(QDataStream*)> m_demarsh_funcs;
+
+ static Marshaller *m_instance;
+
+ void initFuncs();
+ private:
+ bool marsh_private(const PCOPType &type,
+ PyObject *obj,
+ QDataStream *str) const;
+ PyObject *demarsh_private(const PCOPType &type,
+ QDataStream *str) const;
+
+
+
+ };
+
+// bool marshall_bool(PyObject *obj, QDataStream *str);
+// bool marshall_int(PyObject *obj, QDataStream *str);
+// bool marshall_uint(PyObject *obj, QDataStream *str);
+// bool marshall_double(PyObject *obj, QDataStream *str);
+// bool marshall_QByteArray(PyObject *obj, QDataStream *str);
+// bool marshall_QString(PyObject *obj, QDataStream *str);
+// bool marshall_QCString(PyObject *obj, QDataStream *str);
+
+
+}
+
+#endif
diff --git a/dcoppython/shell/pcop.cpp b/dcoppython/shell/pcop.cpp
new file mode 100644
index 00000000..d7c4adc6
--- /dev/null
+++ b/dcoppython/shell/pcop.cpp
@@ -0,0 +1,770 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey (linux@jrockey.com) *
+ * Original code by Torben Weis *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+
+#include "pcop.h"
+
+#include <kdebug.h>
+
+#include <qapplication.h>
+#include <qcstring.h>
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstring.h>
+
+#include <dcopclient.h>
+
+#include <assert.h>
+
+#include "marshaller.h"
+#include "importedmodules.h"
+
+namespace PythonDCOP {
+
+ PCOPObject::PCOPObject(PyObject *py_obj) :
+ DCOPObject(), m_py_obj(py_obj)
+ {
+ m_methods.setAutoDelete(true);
+ }
+
+ PCOPObject::PCOPObject(PyObject *py_obj, const char *objid) :
+ DCOPObject(QCString(objid)), m_py_obj(py_obj)
+ {
+ m_methods.setAutoDelete(true);
+ }
+
+ PCOPObject::~PCOPObject()
+ {
+ }
+
+ bool PCOPObject::process(const QCString &fun, const QByteArray &data,
+ QCString& replyType, QByteArray &replyData)
+ {
+ bool result = py_process(fun,data,replyType,replyData);
+ if (PyErr_Occurred()) {
+ kdDebug(70001) << "Error! About to print..." << endl;
+ PyErr_Print();
+ kdDebug(70001) << "About to clear..." << endl;
+ PyErr_Clear();
+ kdDebug(70001) << "Error handled." << endl;
+ }
+ return result;
+ }
+
+ bool PCOPObject::py_process(const QCString &fun, const QByteArray &data,
+ QCString& replyType, QByteArray &replyData)
+ {
+
+ kdDebug(70001) << "PCOPObject::process - fun=" << fun << " replyType=" << replyType << endl;
+
+ PCOPMethod *meth = matchMethod(fun);
+ if (!meth) {
+ kdDebug(70001) << "Could not match method name" << endl;
+ }
+
+ if (meth) {
+
+ kdDebug(70001) << "m_py_obj=" << m_py_obj << " meth->name=" << meth->name() << " meth->name.data=" << meth->name().data() << endl;
+ if (meth->name().isNull()) { kdDebug(70001) << "meth name is null" << endl; return false; }
+// if (!PyObject_HasAttrString(m_py_obj, meth->name().data())) {
+// kdDebug(70001) << "Method registered, but no python method found" << endl;
+// return false;
+// }
+
+ QDataStream str_arg(data, IO_ReadOnly);
+ PyObject *args = PyTuple_New( meth->paramCount() );
+ for(int c=0;c<meth->paramCount();c++) {
+ kdDebug(70001) << "Demarshalling type: " << meth->param(c)->signature() << endl;
+ PyObject *arg = meth->param(c)->demarshal(str_arg);
+ if (!arg) {
+ kdDebug(70001) << "Failed to demarshall an argument" << endl;
+ return false;
+ }
+ PyTuple_SetItem(args, c, arg );
+ }
+
+ kdDebug(70001) << "args is " << PyTuple_Size(args) << " long" << endl;
+
+// PyObject *method = PyObject_GetAttrString(m_py_obj, meth->name().data() );
+ PyObject *method = meth->pythonMethod();
+ if (!PyCallable_Check(method)) {
+ kdDebug(70001) << "Expected a callable object, but didn't get one!" << endl;
+ return false;
+ }
+
+// PyObject *function = PyMethod_Function(method);
+// PyObject *self = PyMethod_Self(method);
+// Py_INCREF(self);
+// PyTuple_SetItem(args, 0, self );
+// PyObject *result = PyObject_CallObject(function, args);
+
+// Py_DECREF(method);
+ if (PyMethod_Self(method)==NULL)
+ kdDebug(70001) << "Warning: self is null!" << endl;
+
+ kdDebug(70001) << "About to call object.." << endl;
+ PyObject *result = PyObject_CallObject(method, args);
+ kdDebug(70001) << "Finished calling object." << endl;
+
+ if (result) {
+ replyType = meth->type()->signature();
+ PCOPType repl(replyType);
+ if (repl.isMarshallable(result)) {
+ QDataStream str_repl(replyData, IO_WriteOnly);
+ repl.marshal(result,str_repl);
+ Py_DECREF(result);
+ return true;
+ } else {
+ Py_DECREF(result);
+ kdDebug(70001) << "Result of python method was not marshallable into " << replyType << endl;
+ return false;
+ }
+ }
+ else {
+ kdDebug(70001) << "null result from python method call" << endl;
+ return false;
+ }
+
+ }
+
+ return DCOPObject::process(fun,data,replyType,replyData);
+
+ }
+
+ bool PCOPObject::setMethodList(QAsciiDict<PyObject> meth_list) {
+ bool ok = true;
+
+ for(QAsciiDictIterator<PyObject> it(meth_list);
+ it.current(); ++it) {
+
+ PCOPMethod *meth = NULL;
+ if (ok) {
+ meth = new PCOPMethod(QCString(it.currentKey()));
+
+ if (!meth || !meth->setPythonMethod(it.current())) {
+ if (meth) delete meth;
+ meth=NULL;
+ m_methods.clear();
+ ok=false;
+ }
+
+ }
+
+// Py_DECREF(it.current());
+ if (meth) m_methods.insert(meth->signature(),meth);
+ }
+
+ return ok;
+ }
+
+ QCStringList PCOPObject::functions() {
+ QCStringList funcs = DCOPObject::functions();
+ for(QAsciiDictIterator<PCOPMethod> it(m_methods);
+ it.current(); ++it) {
+ PCOPMethod *meth = it.current();
+ QCString func = meth->type()->signature();
+ func += ' ';
+ func += meth->signature();
+ funcs << func;
+ }
+ return funcs;
+ }
+
+ /**
+ * For testing
+ */
+ PyObject *PCOPObject::methodList() {
+ PyObject *result = PyList_New(m_methods.count());
+ int c=0;
+ for(QAsciiDictIterator<PCOPMethod> it(m_methods);
+ it.current(); ++it, ++c) {
+ PyObject *tuple = PyTuple_New(2);
+ PyList_SetItem(result, c, tuple);
+ PyTuple_SetItem(tuple, 0, PyString_FromString(it.currentKey() ) );
+ PyTuple_SetItem(tuple, 1, it.current()->pythonMethod() );
+ }
+ return result;
+ }
+
+ PCOPMethod *PCOPObject::matchMethod(const QCString &fun) {
+ return m_methods.find(fun);
+ }
+
+
+ PCOPType::PCOPType( const QCString& type )
+ {
+ m_leftType = NULL;
+ m_rightType = NULL;
+
+ int pos = type.find( '<' );
+ if ( pos == -1 )
+ {
+ m_type = type;
+ return;
+ }
+
+ int pos2 = type.findRev( '>' );
+ if ( pos2 == -1 )
+ return;
+
+ m_type = type.left( pos );
+
+ // There may be no more than 2 types in the bracket
+ int komma = type.find( ',', pos + 1 );
+ if ( komma == -1 )
+ {
+ m_leftType = new PCOPType( type.mid( pos + 1, pos2 - pos - 1 ) );
+ }
+ else
+ {
+ m_leftType = new PCOPType( type.mid( pos + 1, komma - pos - 1 ) );
+ m_rightType = new PCOPType( type.mid( komma + 1, pos2 - komma - 1 ) );
+ }
+ }
+
+ PCOPType::~PCOPType()
+ {
+ if (m_leftType) delete m_leftType;
+ if (m_rightType) delete m_rightType;
+ }
+
+ QCString PCOPType::signature() const
+ {
+ QCString str = m_type;
+ if ( m_leftType )
+ {
+ str += "<";
+ str += m_leftType->signature();
+
+ if ( m_rightType )
+ {
+ str += ",";
+ str += m_rightType->signature();
+ }
+
+ str += ">";
+ }
+
+ return str;
+ }
+
+ bool PCOPType::marshal( PyObject* obj, QDataStream& str ) const
+ {
+ return Marshaller::instance()->marshal(*this, obj, str);
+ }
+
+ bool PCOPType::isMarshallable( PyObject *obj ) const
+ {
+ return Marshaller::instance()->canMarshal(*this, obj);
+ }
+
+ PyObject* PCOPType::demarshal( QDataStream& str ) const
+ {
+ return Marshaller::instance()->demarshal(*this, str);
+ }
+
+ PCOPMethod::PCOPMethod( const QCString& signature ) :
+ m_py_method(NULL)
+ {
+
+ m_type = 0;
+ m_params.setAutoDelete( TRUE );
+
+ // Find the space that separates the type from the name
+ int k = signature.find( ' ' );
+ if ( k == -1 )
+ return;
+
+ // Create the return type from the string
+ m_type = new PCOPType( signature.left( k ) );
+
+ // Find the brackets
+ int i = signature.find( '(' );
+ if ( i == -1 )
+ return;
+ int j = signature.find( ')' );
+ if ( j == -1 )
+ return;
+
+ // Extract the name
+ m_name = signature.mid( k + 1, i - k - 1 );
+
+ // Strip the parameters
+ QCString p = signature.mid( i + 1, j - i - 1 ).stripWhiteSpace();
+
+ if ( !p.isEmpty() ) {
+ // Make the algorithm terminate
+ p += ",";
+
+ // Iterate over the parameters
+ int level = 0;
+ int start = 0;
+ int len = p.length();
+ for( int i = 0; i < len; ++i )
+ {
+ // Found a comma? Then we reached the end of a parameter
+ if ( p[i] == ',' && level == 0 )
+ {
+ // Find the space that separates name from type.
+ int space = p.find( ' ', start );
+
+ if ( space == -1 || space > i ) // unnamed parameter
+ space = i;
+
+ PCOPType* type = new PCOPType( p.mid( start, space - start ) );
+ m_params.append( type );
+
+ // Start of the next parameter
+ start = i + 1;
+ }
+ else if ( p[i] == '<' )
+ ++level;
+ else if ( p[i] == '>' )
+ --level;
+ }
+ }
+
+ m_signature = m_name;
+ m_signature += "(";
+
+ QListIterator<PCOPType> it( m_params );
+ for( ; it.current(); ++it )
+ {
+ if ( !it.atFirst() )
+ m_signature += ',';
+ m_signature += it.current()->signature();
+ }
+
+ m_signature += ")";
+
+ }
+
+ PCOPMethod::~PCOPMethod()
+ {
+ delete m_type;
+ if (m_py_method) {
+ Py_DECREF(m_py_method);
+ }
+ }
+
+ bool PCOPMethod::setPythonMethod(PyObject *method) {
+ if (method && PyMethod_Check(method)) {
+
+ if (m_py_method) {
+ Py_DECREF(m_py_method);
+ }
+
+ m_py_method = method;
+ Py_INCREF(m_py_method);
+
+ return true;
+ }
+ return false;
+ }
+
+ int PCOPMethod::paramCount() const
+ {
+ return m_params.count();
+ }
+
+ PCOPType* PCOPMethod::param( int i )
+ {
+ return m_params.at( i );
+ }
+
+ const PCOPType* PCOPMethod::param( int i ) const
+ {
+ return ((PCOPMethod*)this)->m_params.at( i );
+ }
+
+ PCOPClass::PCOPClass( const QCStringList& methods )
+ {
+ m_methods.setAutoDelete( true );
+
+ QCStringList::ConstIterator it = methods.begin();
+ for( ; it != methods.end(); ++it )
+ {
+ PCOPMethod* m = new PCOPMethod( *it );
+ m_methods.insert( m->m_name, m );
+ }
+ }
+
+ PCOPClass::~PCOPClass()
+ {
+ }
+
+ const PCOPMethod* PCOPClass::method( const QCString &name, PyObject *argTuple )
+ {
+ if ( !argTuple )
+ return m_methods[ name ];
+
+ QAsciiDictIterator<PCOPMethod> it( m_methods );
+ for (; it.current(); ++it )
+ if ( it.currentKey() == name &&
+ it.current()->paramCount() == PyTuple_Size( argTuple ) )
+ {
+ // ok, name and argument count match, now check if the python
+ // can be marshalled to the qt/dcop type
+
+ PCOPMethod *m = it.current();
+
+ bool fullMatch = true;
+
+ for ( int i = 0; i < m->paramCount(); ++i )
+ if ( !m->param( i )->isMarshallable( PyTuple_GetItem( argTuple, i ) ) )
+ {
+ fullMatch = false;
+ break;
+ }
+
+ if ( fullMatch )
+ return m;
+ }
+
+ return 0;
+ }
+
+
+ // Client
+
+ Client::Client() : m_dcop(NULL), m_qapp(NULL)
+ {
+ ImportedModules::setInstance( new ImportedModules );
+ int argc = 0;
+ char **argv = NULL;
+ m_qapp = new QApplication(argc,argv,false);
+ }
+
+ Client::~Client()
+ {
+// if (m_qapp) delete m_qapp;
+ if (m_dcop) delete m_dcop;
+ }
+
+ void Client::processEvents() {
+ if (m_qapp) {
+// kdDebug(70001) << "Processing events..." << endl;
+ m_qapp->processEvents();
+ }
+ }
+
+ DCOPClient *Client::dcop() {
+ if ( !m_dcop ) {
+ m_dcop = new DCOPClient;
+ if ( !m_dcop->attach() )
+ kdWarning(70001) << "Could not attach to DCOP server";
+ }
+ return m_dcop;
+ }
+
+ Client *Client::instance() { return s_instance; }
+ Client *Client::s_instance = new Client;
+
+
+////////////////////////////////////////////////
+//
+// Methods accessed by python
+//
+////////////////////////////////////////////////
+
+ PyObject* dcop_call( PyObject* /*self*/, PyObject* args )
+ {
+ char *arg1;
+ char *arg2;
+ char *arg3;
+ PyObject* tuple;
+
+ if ( !PyArg_ParseTuple( args, (char*)"sssO", &arg1, &arg2, &arg3, &tuple ) )
+ return NULL;
+
+ if ( !PyTuple_Check( tuple ) )
+ return NULL;
+
+ QByteArray replyData;
+ QCString replyType;
+ QByteArray data;
+ QDataStream params( data, IO_WriteOnly );
+
+ QCString appname( arg1 );
+ QCString objname( arg2 );
+ QCString funcname( arg3 );
+
+ //
+ // Remove escape characters
+ //
+ if ( objname[0] == '_' )
+ objname = objname.mid( 1 );
+ if ( funcname[0] == '_' )
+ funcname = funcname.mid( 1 );
+
+ DCOPClient* dcop = Client::instance()->dcop();
+
+ //
+ // Determine which functions are available.
+ //
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( appname, objname, &ok );
+ if ( !ok )
+ {
+ PyErr_SetString( PyExc_RuntimeError, "Object is not accessible." );
+ return NULL;
+ }
+
+ // for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) {
+ // qDebug( "%s", (*it).data() );
+ // }
+
+ //
+ // Create a parse tree and search for the method
+ //
+ // ### Check wether that is sane
+ PCOPClass c( funcs );
+
+ // qDebug("Parsing done.");
+
+ // Does the requested method exist ?
+ const PCOPMethod* m = c.method( funcname, tuple );
+ if ( !m )
+ {
+ PyErr_SetString( PyExc_RuntimeError, "DCOP: Unknown method." );
+ return NULL;
+ }
+
+ QCString signature = m->signature();
+ kdDebug(70001) << "The signature is " << signature.data() << endl;
+
+ kdDebug(70001) << "The method takes " << m->paramCount() << " parameters" << endl;
+
+ //
+ // Marshal the parameters.
+ //
+
+ int param_count = m->paramCount();
+ for( int p = 0; p < param_count; ++p )
+ {
+ PyObject* o = PyTuple_GetItem( tuple, p );
+ // #### Check for errors
+ if ( !m->param( p )->marshal( o, params ) )
+ {
+ kdDebug(70001) << "QD: Could not marshal paramater %i" << p << endl;
+ PyErr_SetString( PyExc_RuntimeError, "DCOP: marshaling failed" );
+ return NULL;
+ }
+ }
+
+ kdDebug(70001) << "Calling " << appname.data() << " " << objname.data() << " " << signature.data() << endl;
+
+// ASSERT( Client::instance()->dcop() != 0 );
+ ASSERT(dcop);
+
+ if ( !dcop->call( appname, objname, signature, data, replyType, replyData ) )
+ {
+ PyErr_SetString( PyExc_RuntimeError, "DCOP: call failed" );
+ return NULL;
+ }
+
+ kdDebug(70001) << "The return type is " << replyType.data() << endl;
+
+ //
+ // Now decode the return type.
+ //
+ // ### Check wether that was sane
+ PCOPType type( replyType );
+ QDataStream reply(replyData, IO_ReadOnly);
+ return type.demarshal( reply );
+
+ }
+
+ PyObject* application_list( PyObject */*self*/, PyObject */*args*/ )
+ {
+ QCStringList apps = Client::instance()->dcop()->registeredApplications();
+
+ PyObject *l = PyList_New( apps.count() );
+
+ QCStringList::ConstIterator it = apps.begin();
+ QCStringList::ConstIterator end = apps.end();
+ unsigned int i = 0;
+ for (; it != end; ++it, i++ )
+ PyList_SetItem( l, i, PyString_FromString( (*it).data() ) );
+
+ return l;
+ }
+
+ PyObject *object_list( PyObject */*self*/, PyObject *args) {
+ const char *app;
+ if (PyArg_ParseTuple(args, (char*)"s", &app)) {
+ QCStringList objects = Client::instance()->dcop()->remoteObjects(QCString(app));
+ return make_py_list(objects);
+ }
+ return NULL;
+ }
+
+ PyObject *method_list( PyObject */*self*/, PyObject *args) {
+ const char *app, *obj;
+ if (PyArg_ParseTuple(args, (char*)"ss", &app, &obj)) {
+ QCStringList methods = Client::instance()->dcop()->remoteFunctions(QCString(app), QCString(obj) );
+ return make_py_list(methods);
+ }
+ return NULL;
+ }
+
+ PyObject *register_as( PyObject */*self*/, PyObject *args) {
+ const char *appid;
+ int add_pid = 1;
+ if (PyArg_ParseTuple(args, (char*)"s|i", &appid, &add_pid)) {
+ QCString actual_appid = Client::instance()->dcop()->registerAs(QCString(appid), add_pid!=0);
+ return PyString_FromString(actual_appid.data());
+ }
+ return NULL;
+ }
+
+ PyObject *create_dcop_object( PyObject */*self*/, PyObject *args) {
+ PyObject *py_dcop_object;
+ const char *objid = NULL;
+ if (PyArg_ParseTuple(args, (char*)"O|s", &py_dcop_object, &objid)) {
+ Py_INCREF(py_dcop_object);
+ PCOPObject *obj = objid ? new PCOPObject(py_dcop_object, objid) : new PCOPObject(py_dcop_object);
+ return PyCObject_FromVoidPtr( (void*)obj, delete_dcop_object );
+ }
+ return NULL;
+ }
+
+ /**
+ * pcop.set_method_list( <dcopobject cobject>, <method list> )
+ * where <method list> is a list of tuples
+ * [ ('method signature', python method), ... ]
+ */
+ PyObject *set_method_list( PyObject */*self*/, PyObject *args) {
+ PyObject *c_obj;
+ PyObject *method_list;
+ if (PyArg_ParseTuple(args, (char*)"OO", &c_obj, &method_list) &&
+ PyCObject_Check(c_obj) &&
+ PyList_Check(method_list)) {
+
+ // extract each tuple from the list, aborting if any is invalid
+ QAsciiDict<PyObject> meth_list;
+ int size = PyList_Size(method_list);
+ for(int c=0;c<size;c++) {
+ PyObject *tuple = PyList_GetItem(method_list,c);
+ const char *method_signature = NULL;
+ PyObject *py_method = NULL;
+ if (!PyArg_ParseTuple(tuple, (char*)"sO", &method_signature, &py_method))
+ return NULL;
+ Py_INCREF(py_method);
+ meth_list.insert(method_signature, py_method);
+ }
+
+ PCOPObject *obj = (PCOPObject*)PyCObject_AsVoidPtr(c_obj);
+ if (obj) {
+ if (!obj->setMethodList(meth_list)) return NULL;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return NULL;
+ }
+
+ PyObject *get_method_list(PyObject */*self*/, PyObject *args) {
+ PyObject *c_obj;
+ if (PyArg_ParseTuple(args, (char*)"O", &c_obj)) {
+ if (PyCObject_Check(c_obj)) {
+ PCOPObject *obj = (PCOPObject*)PyCObject_AsVoidPtr(c_obj);
+ return obj->methodList();
+ }
+ }
+ return NULL;
+ }
+
+ PyObject *connect_DCOP_Signal( PyObject */*self*/, PyObject *args) {
+ const char *sender;
+ const char *senderObj;
+ const char *signal;
+ const char *receiverObj;
+ const char *slot;
+
+ int volint = 0;
+ if (PyArg_ParseTuple(args, (char*)"sssss|i", &sender, &senderObj, &signal, &receiverObj, &slot, &volint)) {
+ bool success = Client::instance()->dcop()->connectDCOPSignal(QCString(sender), QCString(senderObj), QCString(signal), QCString(receiverObj), QCString(slot), (volint == 1)?true:false);
+ return Py_BuildValue("i", success?1:0);
+ }
+ return NULL;
+ }
+
+ PyObject *disconnect_DCOP_Signal( PyObject *self, PyObject *args) {
+ const char *sender;
+ const char *senderObj;
+ const char *signal;
+ const char *receiverObj;
+ const char *slot;
+
+ if (PyArg_ParseTuple(args, (char*)"sssss", &sender, &senderObj, &signal, &receiverObj, &slot)) {
+ bool success = Client::instance()->dcop()->disconnectDCOPSignal(QCString(sender), QCString(senderObj), QCString(signal), QCString(receiverObj), QCString(slot));
+ return Py_BuildValue("i", success?1:0);
+ }
+ return NULL;
+
+ }
+
+
+
+ void delete_dcop_object(void *vp) {
+ if (vp) {
+ PCOPObject *obj = (PCOPObject*)vp;
+ delete obj;
+ }
+ }
+
+ PyObject *process_events( PyObject */*self*/, PyObject */*args*/) {
+ Client::instance()->processEvents();
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ // helpers
+
+ PyObject *make_py_list( const QCStringList &qt_list) {
+ PyObject *l = PyList_New(qt_list.count());
+ uint c=0;
+ for(QCStringList::ConstIterator it = qt_list.begin();
+ it!=qt_list.end();
+ ++it,c++)
+ PyList_SetItem(l, c, PyString_FromString( (*it).data() ) );
+ return l;
+ }
+
+}
+
+
+PyMethodDef PCOPMethods[] = {
+ { (char*)"dcop_call", PythonDCOP::dcop_call, METH_VARARGS, (char*)"Make a call to DCOP." },
+ { (char*)"app_list", PythonDCOP::application_list, METH_VARARGS, (char*)"Return a list of DCOP registered application." },
+ { (char*)"obj_list", PythonDCOP::object_list, METH_VARARGS, (char*)"Return a list of objects for a DCOP registered application."},
+ { (char*)"method_list", PythonDCOP::method_list, METH_VARARGS, (char*)"Return a list of methods for a DCOP object."},
+ { (char*)"register_as", PythonDCOP::register_as, METH_VARARGS, (char*)"Register the application with DCOP."},
+ { (char*)"create_dcop_object", PythonDCOP::create_dcop_object, METH_VARARGS, (char*)"Creates a DCOP Object instance."},
+ { (char*)"process_events", PythonDCOP::process_events, METH_VARARGS, (char*)"Processes QT events."},
+ { (char*)"set_method_list", PythonDCOP::set_method_list, METH_VARARGS, (char*)"Set the list of methods for a DCOP server object."},
+ { (char*)"connect_dcop_signal", PythonDCOP::connect_DCOP_Signal, METH_VARARGS, (char*)"Connect a dcop signal."},
+ { (char*)"disconnect_dcop_signal", PythonDCOP::disconnect_DCOP_Signal, METH_VARARGS, (char*)"Disconnect a dcop signal."},
+ { NULL, NULL, 0, NULL } /* Sentinel */
+};
+
+extern "C"
+{
+
+ void initpcop()
+ {
+ (void) Py_InitModule( (char*)"pcop", PCOPMethods );
+ }
+
+}
+
+
diff --git a/dcoppython/shell/pcop.h b/dcoppython/shell/pcop.h
new file mode 100644
index 00000000..ecfe0f65
--- /dev/null
+++ b/dcoppython/shell/pcop.h
@@ -0,0 +1,202 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Julian Rockey (linux@jrockey.com) *
+ * Original code by Torben Weis *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef __pcop_h__
+#define __pcop_h__
+
+#include <Python.h>
+
+#include <qcstring.h>
+#include <qlist.h>
+#include <qasciidict.h>
+
+#include <dcopclient.h>
+#include <dcopobject.h>
+
+class QDataStream;
+
+namespace PythonDCOP {
+ class Client;
+ class PCOPMethod;
+ class ImportedModules;
+
+ // Python interface
+ PyObject *dcop_call( PyObject* self, PyObject* args );
+ PyObject *application_list( PyObject *self, PyObject *args );
+ PyObject *object_list(PyObject *self, PyObject *args );
+ PyObject *method_list(PyObject *self, PyObject *args );
+ PyObject *register_as( PyObject *self, PyObject *args);
+ PyObject *create_dcop_object( PyObject *self, PyObject *args);
+ PyObject *set_method_list( PyObject *self, PyObject *args);
+ PyObject *connect_DCOP_Signal( PyObject *self, PyObject *args);
+ PyObject *disconnect_DCOP_Signal( PyObject *self, PyObject *args);
+
+
+ // helpers...
+ void delete_dcop_object(void *vp);
+ PyObject *make_py_list(const QCStringList &qt_list);
+
+ /**
+ * Used by the Python interface to talk to DCOP
+ */
+ class Client {
+ public:
+ Client();
+ ~Client();
+ void processEvents();
+ DCOPClient *dcop();
+// ImportedModules *module() const { return m_module; }
+ static Client *instance();
+ protected:
+ DCOPClient *m_dcop;
+// ImportedModules *m_module;
+ static Client *s_instance;
+ QApplication *m_qapp;
+ };
+
+ /**
+ * Class representing a DCOPObject.
+ * This class represents a DCOP object in a "server" capacity.
+ */
+ class PCOPObject : public DCOPObject
+ {
+ public:
+ /**
+ * Construct from a pointer to the Python object holding this CObject.
+ */
+ PCOPObject(PyObject *py_obj);
+
+ /**
+ * Construct from a pointer to the Python object holding this CObject and
+ * a DCOP object ID.
+ */
+ PCOPObject(PyObject *py_obj, const char *objid);
+
+ virtual ~PCOPObject();
+
+ /**
+ * Process method fun, whose arguments are marshalled in data.
+ * Set replyType to be the reply type and marshall the reply data into replyData.
+ */
+ virtual bool process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData);
+
+ /**
+ * Return list of supported functions (methods).
+ */
+ virtual QCStringList functions();
+
+ /**
+ * Set the list of methods that this object handles.
+ * The key of the QT dictionary is the method signature; the data in
+ * the dictionary is a pointer to the python method to which it corresponds.
+ */
+ virtual bool setMethodList(QAsciiDict<PyObject> meth_list);
+
+ /**
+ * Returns the current list of methods, as set by setMethodList.
+ */
+ virtual PyObject *methodList();
+
+ /**
+ * Matches an 'incoming' method signature (fun) and returns a PCOPMethod pointer,
+ * or NULL if none match.
+ */
+ PCOPMethod *matchMethod(const QCString &fun);
+
+ private:
+ virtual bool py_process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData);
+
+ /**
+ * The Python object holding this CObject.
+ */
+ PyObject *m_py_obj;
+
+ /**
+ * The list of methods this object supports.
+ */
+ QAsciiDict<PCOPMethod> m_methods;
+
+ };
+
+ /**
+ * Class representing a data type, with methods for DCOP marshalling and unmarshalling.
+ */
+ class PCOPType
+ {
+ public:
+ PCOPType( const QCString& dcop_representation);
+ ~PCOPType();
+
+ QCString signature() const;
+
+ PyObject* demarshal( QDataStream& str ) const;
+ bool marshal( PyObject* obj, QDataStream& str ) const;
+
+ // checks if the given PyObject can be marshalled as this PCOPType
+ bool isMarshallable( PyObject *obj ) const;
+
+ const QCString &type() const { return m_type; }
+ const PCOPType *leftType() const { return m_leftType; }
+ const PCOPType *rightType() const { return m_rightType; }
+
+ // TODO: make these private
+ QCString m_type;
+ PCOPType* m_leftType;
+ PCOPType* m_rightType;
+
+ };
+
+ /**
+ * Class representing a DCOP method
+ */
+ class PCOPMethod
+ {
+ public:
+ PCOPMethod( const QCString& dcop_signature );
+ ~PCOPMethod();
+
+ int paramCount() const;
+// QCString signature() const;
+// QCString name() const;
+ PCOPType* param( int );
+ const PCOPType* param( int ) const;
+
+ bool setPythonMethod(PyObject *py_method);
+ PyObject *pythonMethod() const { return m_py_method; }
+ const QCString &signature() const { return m_signature; }
+ const QCString &name() const { return m_name; }
+ const PCOPType *type() const { return m_type; }
+
+ QCString m_signature;
+ QCString m_name;
+ PCOPType* m_type;
+ QList<PCOPType> m_params;
+ private:
+ PyObject *m_py_method;
+ };
+
+ /**
+ * Class representing a DCOP class.
+ */
+ class PCOPClass
+ {
+ public:
+ PCOPClass( const QCStringList& dcop_style_methods);
+ ~PCOPClass();
+
+ const PCOPMethod* method( const QCString &name, PyObject *argTuple = 0 );
+
+ QCStringList m_ifaces;
+ QAsciiDict<PCOPMethod> m_methods;
+ };
+
+}
+
+#endif