summaryrefslogtreecommitdiffstats
path: root/dcoppython
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit90825e2392b2d70e43c7a25b8a3752299a933894 (patch)
treee33aa27f02b74604afbfd0ea4f1cfca8833d882a /dcoppython
downloadtdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz
tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'dcoppython')
-rw-r--r--dcoppython/Makefile.am3
-rw-r--r--dcoppython/README66
-rw-r--r--dcoppython/TODO7
-rw-r--r--dcoppython/configure.in.in9
-rw-r--r--dcoppython/lib/Makefile.am4
-rw-r--r--dcoppython/lib/pydcop.py122
-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
-rw-r--r--dcoppython/test/Makefile.am3
-rw-r--r--dcoppython/test/README-server19
-rwxr-xr-xdcoppython/test/automate_presentation.py30
-rw-r--r--dcoppython/test/dcopserver/Makefile.am36
-rw-r--r--dcoppython/test/dcopserver/README8
-rw-r--r--dcoppython/test/dcopserver/gen.py46
-rw-r--r--dcoppython/test/dcopserver/hi16-app-kdedcoptest.pngbin0 -> 1033 bytes
-rw-r--r--dcoppython/test/dcopserver/hi32-app-kdedcoptest.pngbin0 -> 2749 bytes
-rw-r--r--dcoppython/test/dcopserver/kdedcoptest.cpp27
-rw-r--r--dcoppython/test/dcopserver/kdedcoptest.desktop6
-rw-r--r--dcoppython/test/dcopserver/kdedcoptest.h38
-rw-r--r--dcoppython/test/dcopserver/kdedcoptestui.rc8
-rw-r--r--dcoppython/test/dcopserver/main.cpp54
-rw-r--r--dcoppython/test/dcopserver/mainclass.cpp20
-rw-r--r--dcoppython/test/dcopserver/mainclass.h23
-rw-r--r--dcoppython/test/server.py48
-rw-r--r--dcoppython/test/signal.py41
-rw-r--r--dcoppython/test/test.py15
-rw-r--r--dcoppython/test/test2.py28
-rw-r--r--dcoppython/test/test3.py14
-rw-r--r--dcoppython/test/test4.py24
37 files changed, 2935 insertions, 0 deletions
diff --git a/dcoppython/Makefile.am b/dcoppython/Makefile.am
new file mode 100644
index 00000000..194e4691
--- /dev/null
+++ b/dcoppython/Makefile.am
@@ -0,0 +1,3 @@
+
+SUBDIRS = shell lib
+
diff --git a/dcoppython/README b/dcoppython/README
new file mode 100644
index 00000000..e5b8c3e8
--- /dev/null
+++ b/dcoppython/README
@@ -0,0 +1,66 @@
+PYTHON bindings for DCOP
+========================
+
+These are the new-style Python DCOP bindings. The way in which the bindings are
+implemented has changed since KDE 3.1.1.
+
+
+How they work
+=============
+
+The code is divided into two parts:
+
+pcop.cpp - the C++ interface between Python and DCOP - generates shared library pcop.so
+ which can be imported by Python
+
+pydcop.py - the Python interface to pcop.cpp
+
+pcop.cpp includes a header file marshal_funcs.h, which is generated from
+a data file called marshal_funcs.data by a converter script, gen_marshal_funcs.py
+
+marshal_funcs.data contains the basic code necessary to marshal and demarshal the different
+types that DCOP can handle. For example, it codes how to convert a QString for use by Python
+(in this case, a Python string) and the reverse - what the user may supply in Python when
+DCOP requires a QString. In addition to the fundemental types, more complex QT classes are
+coded, such as QRect (which converts to a Python tuple ( (x1,y1), (x2,y2) ) ).
+
+Documentation is auto-generated out of marshal_funcs.data, creating file marshal_funcs_doc.html,
+which details how each DCOP type (e.g. QString, QRect, int, QCStringList) is represented in Python.
+
+In this implementation, each DCOP type is represented by a basic Python type - numeric, tuple, etc.
+There are no "QT bindings" necessary.
+
+These bindings allow you to code Python to act as a DCOP client (querying and/or controlling
+other DCOP applications), or as a DCOP server. This means that you can DCOP-enable Python applications
+even if they are not QT based.
+
+If you want to use DCOP in the context of a Python QT application, then there are DCOP bindings included in
+the PyQT and PyKDE bindings available from:
+
+http://www.riverbankcomputing.co.uk/
+
+Examples
+========
+
+There are some example Python programs in the test directory.
+
+Known problems
+=============
+
+There is currently a bug which means you must import both pcop and pydcop in your Python programs.
+This means that a Python program using dcoppython must include:
+
+import pcop
+import pydcop
+
+In that order. If you don't import pcop, a seg fault occurs when the interpreter exits. This, of course, will be
+fixed once I find out what the hell's going on.
+
+Authors
+=======
+
+The original Python DCOP bindings were written by Torben Weis (weis@kde.org).
+The current implementation, based on Torben's worked, was written by Julian Rockey (kde@jrockey.com).
+Julian is also the current maintainer.
+
+
diff --git a/dcoppython/TODO b/dcoppython/TODO
new file mode 100644
index 00000000..3da5fda9
--- /dev/null
+++ b/dcoppython/TODO
@@ -0,0 +1,7 @@
+dcoppython todo..
+
+ Enable/disable debugs
+ Check _object_ and _method_ naming convention
+ Signals
+ ASYNC
+ Threaded server
diff --git a/dcoppython/configure.in.in b/dcoppython/configure.in.in
new file mode 100644
index 00000000..2f645818
--- /dev/null
+++ b/dcoppython/configure.in.in
@@ -0,0 +1,9 @@
+KDE_CHECK_PYTHON(1.5)
+if test -z "$LIBPYTHON" || test -z "$PYTHONINC"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE dcoppython"
+fi
+
+AC_ARG_VAR([XSLTPROC])
+AC_ARG_VAR([PYTHON])
+AC_PATH_PROG([XSLTPROC],[xsltproc],[echo])
+AC_PATH_PROG([PYTHON],[python])
diff --git a/dcoppython/lib/Makefile.am b/dcoppython/lib/Makefile.am
new file mode 100644
index 00000000..99dbac94
--- /dev/null
+++ b/dcoppython/lib/Makefile.am
@@ -0,0 +1,4 @@
+
+pyt_DATA = pydcop.py
+pytdir = $(PYTHONMODDIR)
+
diff --git a/dcoppython/lib/pydcop.py b/dcoppython/lib/pydcop.py
new file mode 100644
index 00000000..0333b742
--- /dev/null
+++ b/dcoppython/lib/pydcop.py
@@ -0,0 +1,122 @@
+import pcop
+
+def registeredApplications():
+ """Return a list of current DCOP registered applications."""
+ return pcop.app_list()
+
+def apps():
+ """Return a list of current DCOP registered applications."""
+ return pcop.app_list()
+
+def anyAppCalled(appName):
+ """Return any application instance called appName, or None if none currently registered."""
+ for app in apps():
+ if appName==app or appName+'-'==app[:len(appName)+1]:
+ return DCOPApplication(app)
+ return None
+
+def registerAs(appid, addpid=1):
+ """Register the application with DCOP and return the ID. This is needed in order to receive DCOP requests."""
+ return pcop.register_as(appid,addpid)
+
+def processEvents():
+ """Process any waiting QT events, then return."""
+ pcop.process_events()
+
+def connectDCOPSignal(sender,senderObj,signal,receiverObj,slot,vol=1):
+ """Connect a dcop signal"""
+ return pcop.connect_dcop_signal(sender,senderObj,signal,receiverObj,slot,vol)
+
+def disconnectDCOPSignal(sender,senderObj,signal,receiverObj,slot):
+ """Connect a dcop signal"""
+ return pcop.disconnect_dcop_signal(sender,senderObj,signal,receiverObj,slot)
+
+class DCOPApplication(object):
+ def __init__( self, name ):
+ self.name = name
+
+ def __getattr__( self, item ):
+ if item == "__repr__":
+ return object.__repr__
+ if item == "__str__":
+ return object.__str__
+ if item == "__call__":
+ return object.__call__
+ if item == "_objects_":
+ return pcop.obj_list(self.name)
+ return DCOPObject( self.name, item )
+
+ def _object_(self, object):
+ return DCOPObject( self.name, object )
+
+class DCOPObject(object):
+ def __init__( self, appname, name ):
+ self.appname = appname
+ self.name = name
+
+ def __repr__( self ):
+ return "DCOPObject(%s,%s)" % ( self.appname, self.name )
+
+ def __str__( self ):
+ return "DCOPObject(%s,%s)" % ( self.appname, self.name )
+
+ def __getattr__( self, item ):
+ if item == "__repr__":
+ return object.__repr__
+ if item == "__str__":
+ return object.__str__
+ if item == "__call__":
+ return object.__call__
+ if item == "_methods_":
+ return pcop.method_list( self.appname, self.name )
+ return DCOPMethod( self.appname, self.name, item )
+
+ def _method_(self, method):
+ return DCOPMethod( self.appname, self.name, method )
+
+class DCOPMethod(object):
+ def __init__( self, appname, objname, name ):
+ self.appname = appname
+ self.objname = objname
+ self.name = name
+
+ def __repr__( self ):
+ return "DCOPMethod(%s,%s,%s)" % ( self.appname, self.objname, self.name )
+
+ def __str__( self ):
+ return "DCOPMethod(%s,%s,%s)" % ( self.appname, self.objname, self.name )
+
+ def __call__( self, *args ):
+ return pcop.dcop_call( self.appname, self.objname, self.name, args )
+
+class DCOPServer(object):
+ def __init__( self, appid, addpid = 1):
+ self.app_id = pcop.register_as(appid, addpid)
+
+
+class DCOPServerObject:
+ """Inherit from this class to DCOP enabled your object.
+
+ Remember to call the base class constructor, and in your own constructor
+ you should called setMethods to set the methods to DCOP enable.
+ """
+
+ def __init__(self, objName=None):
+ """objName is the name of the object. If omitted, it will default to a hex
+ address. It is best to supply it."""
+ if objName:
+ self.dcop_obj = pcop.create_dcop_object(self, objName)
+ else:
+ self.dcop_obj = pcop.create_dcop_object(self)
+
+ def setMethods(self, methods):
+ """Set the method list for this object.
+
+ methods is a list of tuple pairs. Each pair consists of the
+ method signature and the Python method that handles it.
+
+ For example, setMethods([ ('QString cheeseType()', self.cheese_type),
+ ('void setGreatWines(bool perthPink, bool hobartMuddy, bool chateauChunder)')
+ """
+ pcop.set_method_list(self.dcop_obj, methods)
+
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
diff --git a/dcoppython/test/Makefile.am b/dcoppython/test/Makefile.am
new file mode 100644
index 00000000..35deee5d
--- /dev/null
+++ b/dcoppython/test/Makefile.am
@@ -0,0 +1,3 @@
+
+subdirs = dcopserver
+
diff --git a/dcoppython/test/README-server b/dcoppython/test/README-server
new file mode 100644
index 00000000..3d2528b8
--- /dev/null
+++ b/dcoppython/test/README-server
@@ -0,0 +1,19 @@
+The file server.py contains an example of using the DCOP bindings to run a DCOP server in Python.
+
+Run python server.py, then in another console:
+
+[julian] julian$ dcop `dcop | grep petshop`
+qt
+parrot
+[julian] julian$ dcop `dcop | grep petshop` parrot
+QCStringList interfaces()
+QCStringList functions()
+QString squawk(QString)
+void setAge(int)
+int age()
+[julian] julian$ dcop `dcop | grep petshop` parrot setAge 5
+[julian] julian$ dcop petshop-29530 parrot squawk 'How many volts for a vrooom?'
+This parrot, 5 months old, squawks: How many volts for a vrooom?
+[julian] julian$
+
+
diff --git a/dcoppython/test/automate_presentation.py b/dcoppython/test/automate_presentation.py
new file mode 100755
index 00000000..0c75e108
--- /dev/null
+++ b/dcoppython/test/automate_presentation.py
@@ -0,0 +1,30 @@
+# Python version of David Faure's <faure@kde.org> dcop presentation automation script for kpresenter
+#
+# Simon Hausmann <hausmann@kde.org>
+from time import sleep
+import pcop
+import pydcop
+
+app = pydcop.anyAppCalled( "kpresenter" )
+
+if not app: raise RuntimeError, "Couldn't find a running KPresenter"
+
+doc = app.KoApplicationIface.getDocuments()[0]
+view = doc.view(0)
+
+startAction = view.action( "screen_start" )
+
+print "Starting Presentation %s" % doc.url()
+
+startAction.activate()
+
+sleep( 5 )
+
+act = view.action( "screen_next" )
+while startAction.enabled() == 0:
+ sleep( 10 )
+ if startAction.enabled() == 0:
+ act.activate()
+
+view.screenStop()
+print "Presentation finished."
diff --git a/dcoppython/test/dcopserver/Makefile.am b/dcoppython/test/dcopserver/Makefile.am
new file mode 100644
index 00000000..61610ae5
--- /dev/null
+++ b/dcoppython/test/dcopserver/Makefile.am
@@ -0,0 +1,36 @@
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kdedcoptest.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kdedcoptest.pot
+
+KDE_ICON = kdedcoptest
+
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kdedcoptest
+
+# the application source, library search path, and link libraries
+kdedcoptest_SOURCES = main.cpp kdedcoptest.cpp kdedcoptest_iface.skel mainclass.cpp
+kdedcoptest_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kdedcoptest_LDADD = $(LIB_KDEUI)
+
+# this is where the desktop file will go
+shelldesktopdir = $(kde_appsdir)/Utilities
+shelldesktop_DATA = kdedcoptest.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kdedcoptest
+shellrc_DATA = kdedcoptestui.rc
+
+h_inc.h: gen.py
+ python gen.py
diff --git a/dcoppython/test/dcopserver/README b/dcoppython/test/dcopserver/README
new file mode 100644
index 00000000..47e69273
--- /dev/null
+++ b/dcoppython/test/dcopserver/README
@@ -0,0 +1,8 @@
+What's this doing here? It's here to help if you're developing the Python DCOP bindings themselves. You don't need it if you just want to _use_ the bindings.
+
+It's a simple DCOP server in C++, that can be used to conveniently test the Python DCOP interface (or any other DCOP binding, for that matter). The script gen.py generates simple get/set DCOP methods for a variety of types.
+
+Note that gen.py is _not_ automatically invoked from the Makefile, so you should run it yourself before doing make.
+
+Julian Rockey
+kde@jrockey.com
diff --git a/dcoppython/test/dcopserver/gen.py b/dcoppython/test/dcopserver/gen.py
new file mode 100644
index 00000000..ae2947af
--- /dev/null
+++ b/dcoppython/test/dcopserver/gen.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+type_list = ['KURL', 'QDate', 'QTime', 'QDateTime', 'QRect', 'QString', 'int', 'QFont', 'QSize', 'QPoint', 'QPointArray' ]
+
+inc_exceptions = {'QDate': None, 'QTime': None, 'KURL' : 'kurl'}
+
+iface_inc_list = ['dcopobject']
+
+iface_inc_list += [ t.lower() for t in type_list if t[0]=='Q' and t not in inc_exceptions ]
+iface_inc_list += inc_exceptions.values()
+
+iface_inc_1 = ['class DCOPDemoIface : virtual public DCOPObject {',
+ ' K_DCOP',
+ ' k_dcop:']
+h_inc = []
+cpp_inc = []
+
+for t in type_list:
+ iface_inc_1.append("virtual void set%sVal(const %s &val) = 0; " % (t,t) )
+ iface_inc_1.append("virtual %s %sVal() const = 0;" % (t,t) )
+
+ h_inc.append("virtual void set%sVal(const %s &val); " % (t,t) )
+ h_inc.append("virtual %s %sVal() const;" % (t,t) )
+ h_inc.append("%s m_%sValue;" % (t,t) )
+
+ cpp_inc.append("void MainClass::set%sVal(const %s & val) {" % (t,t) )
+ cpp_inc.append(" m_%sValue = val; }" % t)
+ cpp_inc.append("%s MainClass::%sVal() const {" % (t,t) )
+ cpp_inc.append(" return m_%sValue; }" % t)
+
+iface_inc = []
+for inc in iface_inc_list:
+ if inc: iface_inc.append("#include <%s.h>" % inc)
+iface_inc += iface_inc_1
+iface_inc.append("};")
+
+files = {'kdedcoptest_iface.h': iface_inc,
+ 'h_inc.h': h_inc,
+ 'cpp_inc.h': cpp_inc
+ }
+
+for (fname,data) in files.items():
+ outf = file(fname,'w')
+ for d in data:
+ outf.write(d+'\n')
+ outf.close()
diff --git a/dcoppython/test/dcopserver/hi16-app-kdedcoptest.png b/dcoppython/test/dcopserver/hi16-app-kdedcoptest.png
new file mode 100644
index 00000000..4ed606c1
--- /dev/null
+++ b/dcoppython/test/dcopserver/hi16-app-kdedcoptest.png
Binary files differ
diff --git a/dcoppython/test/dcopserver/hi32-app-kdedcoptest.png b/dcoppython/test/dcopserver/hi32-app-kdedcoptest.png
new file mode 100644
index 00000000..45ae1a11
--- /dev/null
+++ b/dcoppython/test/dcopserver/hi32-app-kdedcoptest.png
Binary files differ
diff --git a/dcoppython/test/dcopserver/kdedcoptest.cpp b/dcoppython/test/dcopserver/kdedcoptest.cpp
new file mode 100644
index 00000000..3046eaac
--- /dev/null
+++ b/dcoppython/test/dcopserver/kdedcoptest.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003 Julian Rockey <kde@jrockey.com>
+ */
+
+#include "kdedcoptest.h"
+
+#include <qlabel.h>
+
+#include <kmainwindow.h>
+#include <klocale.h>
+
+KDEDcopTest::KDEDcopTest()
+ : KMainWindow( 0, "KDEDcopTest" )
+{
+ // set the shell's ui resource file
+ //setXMLFile("kdedcoptestui.rc");
+
+ //new QLabel( "Hello World", this, "hello label" );
+ m_mainClass = new MainClass();
+}
+
+KDEDcopTest::~KDEDcopTest()
+{
+ if (m_mainClass) delete m_mainClass;
+}
+
+#include "kdedcoptest.moc"
diff --git a/dcoppython/test/dcopserver/kdedcoptest.desktop b/dcoppython/test/dcopserver/kdedcoptest.desktop
new file mode 100644
index 00000000..beee065d
--- /dev/null
+++ b/dcoppython/test/dcopserver/kdedcoptest.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Name=KDEDcopTest
+Exec=kdedcoptest
+Icon=kdedcoptest
+Type=Application
+Comment=A simple KDE Application
diff --git a/dcoppython/test/dcopserver/kdedcoptest.h b/dcoppython/test/dcopserver/kdedcoptest.h
new file mode 100644
index 00000000..42a54da6
--- /dev/null
+++ b/dcoppython/test/dcopserver/kdedcoptest.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003 Julian Rockey <kde@jrockey.com>
+ */
+
+#ifndef _KDEDCOPTEST_H_
+#define _KDEDCOPTEST_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kmainwindow.h>
+
+#include "mainclass.h"
+
+/**
+ * @short Application Main Window
+ * @author Julian Rockey <kde@jrockey.com>
+ * @version 0.1
+ */
+class KDEDcopTest : public KMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ KDEDcopTest();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~KDEDcopTest();
+private:
+ MainClass *m_mainClass;
+};
+
+#endif // _KDEDCOPTEST_H_
diff --git a/dcoppython/test/dcopserver/kdedcoptestui.rc b/dcoppython/test/dcopserver/kdedcoptestui.rc
new file mode 100644
index 00000000..7f6ee828
--- /dev/null
+++ b/dcoppython/test/dcopserver/kdedcoptestui.rc
@@ -0,0 +1,8 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kdedcoptest" version="1">
+<MenuBar>
+ <Menu name="custom"><text>C&amp;ustom</text>
+ <Action name="custom_action" />
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/dcoppython/test/dcopserver/main.cpp b/dcoppython/test/dcopserver/main.cpp
new file mode 100644
index 00000000..5335ffe9
--- /dev/null
+++ b/dcoppython/test/dcopserver/main.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2003 Julian Rockey <kde@jrockey.com>
+ */
+
+#include "kdedcoptest.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char *description =
+ I18N_NOOP("A KDE KPart Application");
+
+static const char *version = "0.1";
+
+static KCmdLineOptions options[] =
+{
+// { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ { 0, 0, 0 }
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kdedcoptest", I18N_NOOP("KDEDcopTest"), version, description,
+ KAboutData::License_GPL, "(C) 2003 Julian Rockey", 0, 0, "kde@jrockey.com");
+ about.addAuthor( "Julian Rockey", 0, "kde@jrockey.com" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+ KDEDcopTest *mainWin = 0;
+
+ if (app.isRestored())
+ {
+ RESTORE(KDEDcopTest);
+ }
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ // TODO: do something with the command line args here
+
+ mainWin = new KDEDcopTest();
+ app.setMainWidget( mainWin );
+ mainWin->show();
+
+ args->clear();
+ }
+
+ int ret = app.exec();
+
+ delete mainWin;
+ return ret;
+}
diff --git a/dcoppython/test/dcopserver/mainclass.cpp b/dcoppython/test/dcopserver/mainclass.cpp
new file mode 100644
index 00000000..d74b7f10
--- /dev/null
+++ b/dcoppython/test/dcopserver/mainclass.cpp
@@ -0,0 +1,20 @@
+/***************************************************************************
+ * 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 "mainclass.h"
+
+
+MainClass::MainClass()
+ : DCOPDemoIface(), DCOPObject("test")
+{}
+
+MainClass::~MainClass()
+{}
+
+#include "cpp_inc.h"
diff --git a/dcoppython/test/dcopserver/mainclass.h b/dcoppython/test/dcopserver/mainclass.h
new file mode 100644
index 00000000..7d4f7f4e
--- /dev/null
+++ b/dcoppython/test/dcopserver/mainclass.h
@@ -0,0 +1,23 @@
+
+#ifndef MAINCLASS_H
+#define MAINCLASS_H
+
+
+#include "kdedcoptest_iface.h"
+
+/**
+ *
+ * Julian Rockey
+ **/
+class MainClass : virtual public DCOPDemoIface
+{
+public:
+ MainClass();
+
+ ~MainClass();
+
+#include "h_inc.h"
+
+};
+
+#endif
diff --git a/dcoppython/test/server.py b/dcoppython/test/server.py
new file mode 100644
index 00000000..479b0236
--- /dev/null
+++ b/dcoppython/test/server.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# This is an example of a DCOP serving application written in Python, using
+# the dcoppython KDE bindings.
+
+# something goes wrong if you don't import pcop first.
+# Have to do this till I find out why...
+import pcop
+import pydcop
+
+class ParrotObject(pydcop.DCOPServerObject):
+ """DCOP server object"""
+
+ def __init__(self, id='parrot'):
+ pydcop.DCOPServerObject.__init__(self, id)
+
+ # DCOP needs types, so we need to initialise the object with the methods that
+ # it's going to provide.
+ self.setMethods( [
+ ('int age()', self.get_age),
+ ('void setAge(int)', self.set_age),
+ ('QString squawk(QString)', self.squawk),
+ ])
+
+ # set up object variables
+ self.parrot_age = 7
+
+ def get_age(self):
+ return self.parrot_age
+
+ def set_age(self,age):
+ self.parrot_age = age
+
+ def squawk(self, what_to_squawk):
+ return "This parrot, %i months old, squawks: %s" % (self.parrot_age, what_to_squawk)
+
+
+appid = pydcop.registerAs('petshop')
+print "Server: %s starting" % appid
+
+parrot = ParrotObject()
+another_parrot = ParrotObject('polly')
+
+# Enter event loop
+while 1:
+ pydcop.processEvents()
+
+
diff --git a/dcoppython/test/signal.py b/dcoppython/test/signal.py
new file mode 100644
index 00000000..f9d087c6
--- /dev/null
+++ b/dcoppython/test/signal.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# This is an example of how to use DCOP Signals with
+# the dcoppython KDE bindings.
+
+# something goes wrong if you don't import pcop first.
+# Have to do this till I find out why...
+import pcop
+import pydcop
+
+class MyObject(pydcop.DCOPServerObject):
+ """DCOP server object"""
+
+ def __init__(self, id='pythontest'):
+ pydcop.DCOPServerObject.__init__(self, id)
+
+ # DCOP needs types, so we need to initialise the object with the methods that
+ # it's going to provide.
+ self.setMethods( [('void test(QString)', self.test)])
+
+ def test(self, data):
+ print "New Weather for " + data
+
+appid = pydcop.registerAs('dcopSignalTest')
+print "Server: %s starting" % appid
+
+pytest = MyObject()
+
+sender = "KWeatherService"
+senderObj = "WeatherService"
+signal = "fileUpdate(QString)"
+receiverObj = "pythontest"
+slot = "test(QString)"
+volatile = 1
+
+pydcop.connectDCOPSignal(sender,senderObj,signal,receiverObj,slot,volatile)
+# Enter event loop
+while 1:
+ pydcop.processEvents()
+
+
diff --git a/dcoppython/test/test.py b/dcoppython/test/test.py
new file mode 100644
index 00000000..5ead172a
--- /dev/null
+++ b/dcoppython/test/test.py
@@ -0,0 +1,15 @@
+import pcop
+import pydcop
+
+#res = pcop.dcop_call( "kspread", "default", "getDocuments", () )
+
+res = pydcop.anyAppCalled("kspread").default.getDocuments()
+print res
+print res[0].appname
+print res[0].name
+
+m = res[0].map()
+
+print m.tableNames()
+
+print "done"
diff --git a/dcoppython/test/test2.py b/dcoppython/test/test2.py
new file mode 100644
index 00000000..1a56f917
--- /dev/null
+++ b/dcoppython/test/test2.py
@@ -0,0 +1,28 @@
+
+import pcop
+import pydcop
+
+app = pydcop.anyAppCalled( "kspread" );
+
+res = app.default.getDocuments()
+
+print res
+print res[0].appname
+print res[0].name
+
+m = res[0].map()
+
+print m.tableNames()
+
+x = m.table('Sheet2')
+
+if x:
+ print x
+ print "===================="
+ print x._name
+ print "===================="
+ print x._name()
+ print "===================="
+else: print "Could not find sheet called Sheet2"
+
+print "done"
diff --git a/dcoppython/test/test3.py b/dcoppython/test/test3.py
new file mode 100644
index 00000000..aa13ed8b
--- /dev/null
+++ b/dcoppython/test/test3.py
@@ -0,0 +1,14 @@
+
+import pcop
+import pydcop
+
+app = pydcop.anyAppCalled("kspread")
+
+table = app.default.getViews()[0]
+
+table.setSelection( ( 2, 2, 4, 6 ) )
+
+table.setSelectionBgColor( (100, 100, 240) )
+print rect
+
+print "done"
diff --git a/dcoppython/test/test4.py b/dcoppython/test/test4.py
new file mode 100644
index 00000000..b87a071f
--- /dev/null
+++ b/dcoppython/test/test4.py
@@ -0,0 +1,24 @@
+
+import pcop
+import pydcop
+
+app = pydcop.anyAppCalled("kspread")
+
+doc = app.default.getDocuments()[0]
+
+table = doc.map().tables()[0]
+
+table.cell( 1, 1 ).setValue( 1 )
+
+x = 2
+
+while x < 5:
+ y = 2
+ while y < 5:
+ previousCell = table.cell( x - 1, y - 1 )
+ cell = table.cell( x, y )
+ cell.setValue( previousCell.value() + 1.0 )
+ y = y + 1
+ x = x + 1
+
+