initial import of "dbus" skeleton
authorHavoc Pennington <hp@redhat.com>
Thu, 21 Nov 2002 16:41:33 +0000 (16:41 +0000)
committerHavoc Pennington <hp@redhat.com>
Thu, 21 Nov 2002 16:41:33 +0000 (16:41 +0000)
20 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.in [new file with mode: 0644]
dbus-1.0.pc.in [new file with mode: 0644]
dbus/Makefile.am [new file with mode: 0644]
dbus/dbus-hash.c [new file with mode: 0644]
dbus/dbus-message.c [new file with mode: 0644]
dbus/dbus.h [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/dcop-howto.txt [new file with mode: 0644]
server/Makefile.am [new file with mode: 0644]
server/main.c [new file with mode: 0644]
test/Makefile.am [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..3bc119c
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Havoc Pennington <hp@redhat.com>
\ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..79037fa
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,121 @@
+               Academic Free License
+               Version 1.2
+
+This Academic Free License applies to any original work of authorship 
+(the "Original Work") whose owner (the "Licensor") has placed the 
+following notice immediately following the copyright notice for the 
+Original Work:
+
+Licensed under the Academic Free License version 1.2
+
+Grant of License. Licensor hereby grants to any person obtaining a 
+copy of the Original Work ("You") a world-wide, royalty-free, 
+non-exclusive, perpetual, non-sublicenseable license (1) to use, copy, 
+modify, merge, publish, perform, distribute and/or sell copies of the 
+Original Work and derivative works thereof, and (2) under patent claims 
+owned or controlled by the Licensor that are embodied in the Original 
+Work as furnished by the Licensor, to make, use, sell and offer for 
+sale the Original Work and derivative works thereof, subject to the 
+following conditions.
+
+Attribution Rights. You must retain, in the Source Code of any 
+Derivative Works that You create, all copyright, patent or trademark 
+notices from the Source Code of the Original Work, as well as any 
+notices of licensing and any descriptive text identified therein as an 
+"Attribution Notice." You must cause the Source Code for any Derivative 
+Works that You create to carry a prominent Attribution Notice reasonably 
+calculated to inform recipients that You have modified the Original Work.
+
+Exclusions from License Grant. Neither the names of Licensor, nor the 
+names of any contributors to the Original Work, nor any of their 
+trademarks or service marks, may be used to endorse or promote products 
+derived from this Original Work without express prior written permission 
+of the Licensor.
+
+Warranty and Disclaimer of Warranty. Licensor warrants that the copyright 
+in and to the Original Work is owned by the Licensor or that the Original 
+Work is distributed by Licensor under a valid current license from the 
+copyright owner. Except as expressly stated in the immediately proceeding 
+sentence, the Original Work is provided under this License on an "AS IS" 
+BASIS and WITHOUT WARRANTY, either express or implied, including, without 
+limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS 
+FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL 
+WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part 
+of this License. No license to Original Work is granted hereunder except 
+under this disclaimer.
+
+Limitation of Liability. Under no circumstances and under no legal theory, 
+whether in tort (including negligence), contract, or otherwise, shall the 
+Licensor be liable to any person for any direct, indirect, special, 
+incidental, or consequential damages of any character arising as a result 
+of this License or the use of the Original Work including, without 
+limitation, damages for loss of goodwill, work stoppage, computer failure 
+or malfunction, or any and all other commercial damages or losses. This 
+limitation of liability shall not apply to liability for death or personal 
+injury resulting from Licensor's negligence to the extent applicable law 
+prohibits such limitation. Some jurisdictions do not allow the exclusion or 
+limitation of incidental or consequential damages, so this exclusion and 
+limitation may not apply to You.
+
+License to Source Code. The term "Source Code" means the preferred form of 
+the Original Work for making modifications to it and all available 
+documentation describing how to modify the Original Work. Licensor hereby 
+agrees to provide a machine-readable copy of the Source Code of the Original 
+Work along with each copy of the Original Work that Licensor distributes. 
+Licensor reserves the right to satisfy this obligation by placing a 
+machine-readable copy of the Source Code in an information repository 
+reasonably calculated to permit inexpensive and convenient access by You for 
+as long as Licensor continues to distribute the Original Work, and by 
+publishing the address of that information repository in a notice immediately 
+following the copyright notice that applies to the Original Work.
+
+Mutual Termination for Patent Action. This License shall terminate 
+automatically and You may no longer exercise any of the rights granted to You 
+by this License if You file a lawsuit in any court alleging that any OSI 
+Certified open source software that is licensed under any license containing 
+this "Mutual Termination for Patent Action" clause infringes any patent 
+claims that are essential to use that software.
+
+Right to Use. You may use the Original Work in all ways not otherwise 
+restricted or conditioned by this License or by law, and Licensor promises 
+not to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2002 Lawrence E. Rosen. All rights reserved. 
+Permission is hereby granted to copy and distribute this license without 
+modification. This license may not be modified without the express written 
+permission of its copyright owner.
+
+-- 
+END OF LICENSE. The following is intended to describe the essential 
+differences between the Academic Free License (AFL) version 1.0 and other 
+open source licenses:
+
+The Academic Free License is similar to the BSD, MIT, UoI/NCSA and Apache 
+licenses in many respects but it is intended to solve a few problems with 
+those licenses.
+    
+* The AFL is written so as to make it clear what software is being 
+licensed (by the inclusion of a statement following the copyright notice 
+in the software). This way, the license functions better than a template 
+license. The BSD, MIT and UoI/NCSA licenses apply to unidentified software.
+    
+* The AFL contains a complete copyright grant to the software. The BSD 
+and Apache licenses are vague and incomplete in that respect.
+    
+* The AFL contains a complete patent grant to the software. The BSD, MIT, 
+UoI/NCSA and Apache licenses rely on an implied patent license and contain 
+no explicit patent grant.
+    
+* The AFL makes it clear that no trademark rights are granted to the 
+licensor's trademarks. The Apache license contains such a provision, but the 
+BSD, MIT and UoI/NCSA licenses do not.
+    
+* The AFL includes the warranty by the licensor that it either owns the 
+copyright or that it is distributing the software under a license. None of 
+the other licenses contain that warranty. All other warranties are disclaimed, 
+as is the case for the other licenses.
+
+* The AFL is itself copyrighted (with the right granted to copy and distribute 
+without modification). This ensures that the owner of the copyright to the 
+license will control changes. The Apache license contains a copyright notice, 
+but the BSD, MIT and UoI/NCSA licenses do not. 
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..aa6579d
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,4 @@
+2002-11-21  Havoc Pennington  <hp@redhat.com>
+
+       * Initial module creation
+
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..e35a6de
--- /dev/null
@@ -0,0 +1,3 @@
+
+SUBDIRS=dbus server test doc
+
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..047ccd0
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+No news.
\ No newline at end of file
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7ce279d
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+D-BUS is a simple IPC library based on messages.
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..e100ec2
--- /dev/null
@@ -0,0 +1,10 @@
+#undef PACKAGE
+#undef VERSION
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_LC_MESSAGES
+#undef HAVE_STPCPY
+#undef ENABLE_NLS
+#undef HAVE_PTHREAD_H
+#undef GETTEXT_PACKAGE
+#undef SANE_MALLOC_PROTOS
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..3b74d82
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PROJECT=dbus
+TEST_TYPE=-f
+FILE=dbus-1.0.pc.in
+
+DIE=0
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+       echo
+       echo "You must have autoconf installed to compile $PROJECT."
+       echo "Download the appropriate package for your distribution,"
+       echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+       DIE=1
+}
+
+AUTOMAKE=automake-1.6
+ACLOCAL=aclocal-1.6
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+        AUTOMAKE=automake
+        ACLOCAL=aclocal
+}
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+       echo
+       echo "You must have automake installed to compile $PROJECT."
+       echo "Get ftp://ftp.cygnus.com/pub/home/tromey/automake-1.2d.tar.gz"
+       echo "(or a newer version if it is available)"
+       DIE=1
+}
+
+if test "$DIE" -eq 1; then
+       exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+       echo "You must run this script in the top-level $PROJECT directory"
+       exit 1
+}
+
+if test -z "$*"; then
+       echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+libtoolize --copy --force
+
+echo $ACLOCAL $ACLOCAL_FLAGS
+$ACLOCAL $ACLOCAL_FLAGS
+
+# optionally feature autoheader
+(autoheader --version)  < /dev/null > /dev/null 2>&1 && autoheader
+
+$AUTOMAKE -a $am_opt
+autoconf || echo "autoconf failed - version 2.5x is probably required"
+
+cd $ORIGDIR
+
+$srcdir/configure --enable-maintainer-mode "$@"
+
+echo 
+echo "Now type 'make' to compile $PROJECT."
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..18f8f96
--- /dev/null
@@ -0,0 +1,64 @@
+AC_INIT(dbus/dbus.h)
+
+AM_CONFIG_HEADER(config.h)
+
+AM_INIT_AUTOMAKE(dbus, 0.1)
+
+# Honor aclocal flags
+ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+
+GETTEXT_PACKAGE=dbus-1
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE")
+
+AM_MAINTAINER_MODE
+
+AC_PROG_CC
+AC_ISC_POSIX
+AC_HEADER_STDC
+AC_ARG_PROGRAM
+AM_PROG_LIBTOOL
+
+AC_ARG_ENABLE(qt,   [  --disable-qt      disable Qt-friendly client library],enable_qt=no,enable_qt=yes)
+AC_ARG_ENABLE(glib, [  --disable-glib    disable GLib-friendly client library],enable_glib=no,enable_glib=yes)
+
+changequote(,)dnl
+if test "x$GCC" = "xyes"; then
+  case " $CFLAGS " in
+  *[\ \        ]-Wall[\ \      ]*) ;;
+  *) CFLAGS="$CFLAGS -Wall" ;;
+  esac
+fi
+changequote([,])dnl
+
+AC_CHECK_SIZEOF(char)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(__int64)
+
+## byte order
+AC_C_BIGENDIAN
+
+AC_CHECK_FUNCS(vsnprintf vasprintf)
+
+DBUS_CLIENT_CFLAGS=
+DBUS_CLIENT_LIBS=
+AC_SUBST(DBUS_CLIENT_CFLAGS)
+AC_SUBST(DBUS_CLIENT_LIBS)
+
+DBUS_SERVER_CFLAGS=
+DBUS_SERVER_LIBS=
+AC_SUBST(DBUS_SERVER_CFLAGS)
+AC_SUBST(DBUS_SERVER_LIBS)
+
+AC_OUTPUT([
+Makefile
+dbus/Makefile
+server/Makefile
+test/Makefile
+doc/Makefile
+dbus-1.0.pc
+])
diff --git a/dbus-1.0.pc.in b/dbus-1.0.pc.in
new file mode 100644 (file)
index 0000000..2df0a7c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: dbus
+Description: Free desktop message bus
+Version: @VERSION@
+Libs: -L${libdir} -ldbus-1
+Cflags: -I${includedir}/dbus-1.0
+
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
new file mode 100644 (file)
index 0000000..09dd84f
--- /dev/null
@@ -0,0 +1,22 @@
+
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS)
+
+dbusincludedir=$(includedir)/dbus-1.0/dbus
+
+lib_LTLIBRARIES=libdbus-1.la
+
+dbusinclude_HEADERS=                           \
+       dbus.h
+
+libdbus_1_la_SOURCES=                          \
+       dbus-message.c
+
+noinst_LTLIBRARIES=libdbus-convenience.la
+
+libdbus_convenience_la_SOURCES=                        \
+       dbus-hash.c
+
+libdbus_1_la_LIBADD=  $(DBUS_CLIENT_LIBS) libdbus-convenience.la
+## don't export symbols that start with "_" (we use this 
+## convention for internal symbols)
+libdbus_1_la_LDFLAGS= -export-symbols-regex "^[[^_]].*"
diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dbus/dbus.h b/dbus/dbus.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..d84c70b
--- /dev/null
@@ -0,0 +1,7 @@
+EXTRA_DIST=                                    \
+       dcop-howto.txt                          \
+       fdmb-design.txt                         \
+       fdmb-messages.txt                       \
+       fdmb-properties.txt                     \
+       message-delivery.txt                    \
+       message-matching.txt
diff --git a/doc/dcop-howto.txt b/doc/dcop-howto.txt
new file mode 100644 (file)
index 0000000..dfd3bcf
--- /dev/null
@@ -0,0 +1,559 @@
+               DCOP: Desktop COmmunications Protocol
+
+                   Preston Brown <pbrown@kde.org>
+                          October 14, 1999
+
+        Revised and extended by Matthias Ettrich <ettrich@kde.org>
+                          Mar 29, 2000
+
+        Extended with DCOP Signals by Waldo Bastian <bastian@kde.org>
+                           Feb 19, 2001
+
+
+Motivation and Background:
+--------------------------
+
+The motivation behind building a protocol like DCOP is simple.  For
+the past year, we have been attempting to enable interprocess
+communication between KDE applications. KDE already has an extremely
+simple IPC mechanism called KWMcom, which is (was!) used for communicating
+between the panel and the window manager for instance.  It is about as
+simple as it gets, passing messages via X Atoms.  For this reason it
+is limited in the size and complexity of the data that can be passed
+(X atoms must be small to remain efficient) and it also makes it so
+that X is required.  CORBA was thought to be a more effective IPC/RPC
+solution.  However, after a year of attempting to make heavy use of
+CORBA in KDE, we have realized that it is a bit slow and memory
+intensive for simple use.  It also has no authentication available.
+
+What we really needed was an extremely simple protocol with basic
+authorization, along the lines of MIT-MAGIC-COOKIE, as used by X.  It
+would not be able to do NEARLY what CORBA was able to do, but for the
+simple tasks required it would be sufficient. Some examples of such
+tasks might be an application sending a message to the panel saying,
+"I have started, stop displaying the 'application starting' wait
+state," or having a new application that starts query to see if any
+other applications of the same name are running.  If they are, simply
+call a function on the remote application to create a new window,
+rather than starting a new process.
+
+Implementation:
+---------------
+
+DCOP is a simple IPC/RPC mechanism built to operate over sockets.
+Either unix domain sockets or tcp/ip sockets are supported. DCOP is
+built on top of the Inter Client Exchange (ICE) protocol, which comes
+standard as a part of X11R6 and later. It also depends on Qt, but
+beyond that it does not require any other libraries. Because of this,
+it is extremely lightweight, enabling it to be linked into all KDE
+applications with low overhead.
+
+Model:
+------
+
+The model is simple.  Each application using DCOP is a client.  They
+communicate to each other through a DCOP server, which functions like
+a traffic director, dispatching messages/calls to the proper
+destinations.  All clients are peers of each other.
+
+Two types of actions are possible with DCOP: "send and forget"
+messages, which do not block, and "calls," which block waiting for
+some data to be returned.
+
+Any data that will be sent is serialized (marshalled, for you CORBA
+types) using the built-in QDataStream operators available in all of
+the Qt classes.  This is fast and easy.  In fact it's so little work
+that you can easily write the marshalling code by hand. In addition,
+there's a simple IDL-like compiler available (dcopidl and dcopidl2cpp)
+that generates stubs and skeletons for you. Using the dcopidl compiler
+has the additional benefit of type safety.
+
+This HOWTO describes the manual method first and covers the dcopidl
+compiler later.
+
+Establishing the Connection:
+----------------------------
+
+KApplication has gained a method called "KApplication::dcopClient()"
+which returns a pointer to a DCOPClient instance.  The first time this
+method is called, the client class will be created.  DCOPClients have
+unique identifiers attached to them which are based on what
+KApplication::name() returns.  In fact, if there is only a single
+instance of the program running, the appId will be equal to
+KApplication::name().
+
+To actually enable DCOP communication to begin, you must use
+DCOPClient::attach().  This will attempt to attach to the DCOP server.
+If no server is found or there is any other type of error, attach()
+will return false. KApplication will catch a dcop signal and display an
+appropriate error message box in that case.
+
+After connecting with the server via DCOPClient::attach(), you need to
+register this appId with the server so it knows about you.  Otherwise,
+you are communicating anonymously.  Use the
+DCOPClient::registerAs(const QCString &name) to do so.  In the simple
+case:
+
+/*
+ * returns the appId that is actually registered, which _may_ be
+ * different from what you passed
+ */
+appId = client->registerAs(kApp->name());
+
+If you never retrieve the DCOPClient pointer from KApplication, the
+object will not be created and thus there will be no memory overhead.
+
+You may also detach from the server by calling DCOPClient::detach().
+If you wish to attach again you will need to re-register as well.  If
+you only wish to change the ID under which you are registered, simply
+call DCOPClient::registerAs() with the new name.
+
+KUniqueApplication automatically registers itself to DCOP. If you
+are using KUniqueApplication you should not attach or register
+yourself, this is already done. The appId is by definition
+equal to kapp->name(). You can retrieve the registered DCOP client
+by calling kapp->dcopClient().
+
+Sending Data to a Remote Application:
+-------------------------------------
+
+To actually communicate, you have one of two choices.  You may either
+call the "send" or the "call" method.  Both methods require three
+identification parameters: an application identifier, a remote object,
+a remote function. Sending is asynchronous (i.e. it returns immediately)
+and may or may not result in your own application being sent a message at
+some point in the future. Then "send" requires one and "call" requires
+two data parameters.
+
+The remote object must be specified as an object hierarchy.  That is,
+if the toplevel object is called "fooObject" and has the child
+"barObject", you would reference this object as "fooObject/barObject".
+Functions must be described by a full function signature.  If the
+remote function is called "doIt", and it takes an int, it would be
+described as "doIt(int)".  Please note that the return type is not
+specified here, as it is not part of the function signature (or at
+least the C++ understanding of a function signature).  You will get
+the return type of a function back as an extra parameter to
+DCOPClient::call().  See the section on call() for more details.
+
+In order to actually get the data to the remote client, it must be
+"serialized" via a QDataStream operating on a QByteArray. This is how
+the data parameter is "built". A few examples will make clear how this
+works.
+
+Say you want to call "doIt" as described above, and not block (or wait
+for a response).  You will not receive the return value of the remotely
+called function, but you will not hang while the RPC is processed either.
+The return value of send() indicates whether DCOP communication succeeded
+or not.
+
+QByteArray data;
+QDataStream arg(data, IO_WriteOnly);
+arg << 5;
+if (!client->send("someAppId", "fooObject/barObject", "doIt(int)",
+                 data))
+  qDebug("there was some error using DCOP.");
+
+OK, now let's say we wanted to get the data back from the remotely
+called function.  You have to execute a call() instead of a send().
+The returned value will then be available in the data parameter "reply".
+The actual return value of call() is still whether or not DCOP
+communication was successful.
+
+QByteArray data, replyData;
+QCString replyType;
+QDataStream arg(data, IO_WriteOnly);
+arg << 5;
+if (!client->call("someAppId", "fooObject/barObject", "doIt(int)",
+                  data, replyType, replyData))
+  qDebug("there was some error using DCOP.");
+else {
+  QDataStream reply(replyData, IO_ReadOnly);
+  if (replyType == "QString") {
+    QString result;
+    reply >> result;
+    print("the result is: %s",result.latin1());
+  } else
+    qDebug("doIt returned an unexpected type of reply!");
+}
+
+N.B.: You cannot call() a method belonging to an application which has
+registered with an unique numeric id appended to its textual name (see
+dcopclient.h for more info). In this case, DCOP would not know which
+application it should connect with to call the method. This is not an issue
+with send(), as you can broadcast to all applications that have registered
+with appname-<numeric_id> by using a wildcard (e.g. 'konsole-*'), which
+will send your signal to all applications called 'konsole'.
+
+Receiving Data via DCOP:
+------------------------
+
+Currently the only real way to receive data from DCOP is to multiply
+inherit from the normal class that you are inheriting (usually some
+sort of QWidget subclass or QObject) as well as the DCOPObject class.
+DCOPObject provides one very important method: DCOPObject::process().
+This is a pure virtual method that you must implement in order to
+process DCOP messages that you receive.  It takes a function
+signature, QByteArray of parameters, and a reference to a QByteArray
+for the reply data that you must fill in.
+
+Think of DCOPObject::process() as a sort of dispatch agent.  In the
+future, there will probably be a precompiler for your sources to write
+this method for you.  However, until that point you need to examine
+the incoming function signature and take action accordingly.  Here is
+an example implementation.
+
+bool BarObject::process(const QCString &fun, const QByteArray &data,
+                       QCString &replyType, QByteArray &replyData)
+{
+  if (fun == "doIt(int)") {
+    QDataStream arg(data, IO_ReadOnly);
+    int i; // parameter
+    arg >> i;
+    QString result = self->doIt (i);
+    QDataStream reply(replyData, IO_WriteOnly);
+    reply << result;
+    replyType = "QString";
+    return true;
+  } else {
+    qDebug("unknown function call to BarObject::process()");
+    return false;
+  }
+}
+
+Receiving Calls and processing them:
+------------------------------------
+
+If your applications is able to process incoming function calls
+right away the above code is all you need. When your application
+needs to do more complex tasks you might want to do the processing
+out of 'process' function call and send the result back later when
+it becomes available.
+
+For this you can ask your DCOPClient for a transactionId. You can
+then return from the 'process' function and when the result is
+available finish the transaction. In the mean time your application
+can receive incoming DCOP function calls from other clients.
+
+Such code could like this:
+
+bool BarObject::process(const QCString &fun, const QByteArray &data,
+                       QCString &, QByteArray &)
+{
+  if (fun == "doIt(int)") {
+    QDataStream arg(data, IO_ReadOnly);
+    int i; // parameter
+    arg >> i;
+    QString result = self->doIt(i);
+
+    DCOPClientTransaction *myTransaction;
+    myTransaction = kapp->dcopClient()->beginTransaction();
+
+    // start processing...
+    // Calls slotProcessingDone when finished.
+    startProcessing( myTransaction, i);
+
+    return true;
+  } else {
+    qDebug("unknown function call to BarObject::process()");
+    return false;
+  }
+}
+
+slotProcessingDone(DCOPClientTransaction *myTransaction, const QString &result)
+{
+    QCString replyType = "QString";
+    QByteArray replyData;
+    QDataStream reply(replyData, IO_WriteOnly);
+    reply << result;
+    kapp->dcopClient()->endTransaction( myTransaction, replyType, replyData );
+}
+
+DCOP Signals
+------------
+
+Sometimes a component wants to send notifications via DCOP to other
+components but does not know which components will be interested in these
+notifications. One could use a broadcast in such a case but this is a very
+crude method. For a more sophisticated method DCOP signals have been invented.
+
+DCOP signals are very similair to Qt signals, there are some differences 
+though. A DCOP signal can be connected to a DCOP function. Whenever the DCOP
+signal gets emitted, the DCOP functions to which the signal is connected are
+being called. DCOP signals are, just like Qt signals, one way. They do not
+provide a return value. 
+
+A DCOP signal originates from a DCOP Object/DCOP Client combination (sender). 
+It can be connected to a function of another DCOP Object/DCOP Client 
+combination (receiver).
+
+There are two major differences between connections of Qt signals and 
+connections of DCOP signals. In DCOP, unlike Qt, a signal connections can
+have an anonymous sender and, unlike Qt, a DCOP signal connection can be
+non-volatile.
+
+With DCOP one can connect a signal without specifying the sending DCOP Object 
+or DCOP Client. In that case signals from any DCOP Object and/or DCOP Client
+will be delivered. This allows the specification of certain events without
+tying oneself to a certain object that implementes the events.
+
+Another DCOP feature are so called non-volatile connections. With Qt signal
+connections, the connection gets deleted when either sender or receiver of
+the signal gets deleted. A volatile DCOP signal connection will behave the
+same. However, a non-volatile DCOP signal connection will not get deleted 
+when the sending object gets deleted. Once a new object gets created with 
+the same name as the original sending object, the connection will be restored.
+There is no difference between the two when the receiving object gets deleted,
+in that case the signal connection will always be deleted.
+
+A receiver can create a non-volatile connection while the sender doesn't (yet)
+exist. An anonymous DCOP connection should always be non-volatile.
+
+The following example shows how KLauncher emits a signal whenever it notices
+that an application that was started via KLauncher terminates.
+
+   QByteArray params;
+   QDataStream stream(params, IO_WriteOnly);
+   stream << pid;
+   kapp->dcopClient()->emitDCOPSignal("clientDied(pid_t)", params);
+
+The task manager of the KDE panel connects to this signal. It uses an 
+anonymous connection (it doesn't require that the signal is being emitted
+by KLauncher) that is non-volatile:
+
+   connectDCOPSignal(0, 0, "clientDied(pid_t)", "clientDied(pid_t)", false);
+
+It connects the clientDied(pid_t) signal to its own clientDied(pid_t) DCOP
+function. In this case the signal and the function to call have the same name.
+This isn't needed as long as the arguments of both signal and receiving function
+match. The receiving function may ignore one or more of the trailing arguments
+of the signal. E.g. it is allowed to connect the clientDied(pid_t) signal to
+a clientDied(void) DCOP function.
+
+Using the dcopidl compiler
+---------------------
+
+dcopidl makes setting up a DCOP server easy. Instead of having to implement
+the process() method and unmarshalling (retrieving from QByteArray) parameters
+manually, you can let dcopidl create the necessary code on your behalf.
+
+This also allows you to describe the interface for your class in a
+single, separate header file.
+
+Writing an IDL file is very similar to writing a normal C++ header. An
+exception is the keyword 'ASYNC'. It indicates that a call to this
+function shall be processed asynchronously. For the C++ compiler, it
+expands to 'void'.
+
+Example:
+
+#ifndef MY_INTERFACE_H
+#define MY_INTERFACE_H
+
+#include <dcopobject.h>
+
+class MyInterface : virtual public DCOPObject
+{
+  K_DCOP
+
+  k_dcop:
+
+    virtual ASYNC myAsynchronousMethod(QString someParameter) = 0;
+    virtual QRect mySynchronousMethod() = 0;
+};
+
+#endif
+
+As you can see, you're essentially declaring an abstract base class, which
+virtually inherits from DCOPObject.
+
+If you're using the standard KDE build scripts, then you can simply
+add this file (which you would call MyInterface.h) to your sources
+directory. Then you edit your Makefile.am, adding 'MyInterface.skel'
+to your SOURCES list and MyInterface.h to include_HEADERS.
+
+The build scripts will use dcopidl to parse MyInterface.h, converting
+it to an XML description in MyInterface.kidl. Next, a file called
+MyInterface_skel.cpp will automatically be created, compiled and
+linked with your binary.
+
+The next thing you have to do is to choose which of your classes will
+implement the interface described in MyInterface.h. Alter the inheritance
+of this class such that it virtually inherits from MyInterface. Then
+add declarations to your class interface similar to those on MyInterface.h,
+but virtual, not pure virtual.
+
+Example:
+
+class MyClass: public QObject, virtual public MyInterface
+{
+  Q_OBJECT
+  
+  public:
+    MyClass(); 
+    ~MyClass();
+
+    ASYNC myAsynchronousMethod(QString someParameter);
+    QRect mySynchronousMethod();
+};
+
+Note: (Qt issue) Remember that if you are inheriting from QObject, you must
+place it first in the list of inherited classes.
+
+In the implementation of your class' ctor, you must explicitly initialize
+those classes from which you are inheriting from. This is, of course, good
+practise, but it is essential here as you need to tell DCOPObject the name of
+the interface which your are implementing.
+
+Example:
+
+MyClass::MyClass()
+  : QObject(),
+    DCOPObject("MyInterface")
+{
+  // whatever...
+}
+
+Now you can simply implement the methods you have declared in your interface,
+exactly the same as you would normally.
+
+Example:
+
+void MyClass::myAsynchronousMethod(QString someParameter)
+{
+  qDebug("myAsyncMethod called with param `" + someParameter + "'");
+}
+
+
+It is not necessary (though very clean) to define an interface as an
+abstract class of its own, like we did in the example above. We could
+just as well have defined a k_dcop section directly within MyClass:
+
+class MyClass: public QObject, virtual public DCOPObject
+{
+  Q_OBJECT
+  K_DCOP
+
+  public:
+    MyClass(); 
+    ~MyClass();
+
+  k_dcop:
+    ASYNC myAsynchronousMethod(QString someParameter);
+    QRect mySynchronousMethod();
+};
+
+In addition to skeletons, dcopidl2cpp also generate stubs. Those make
+it easy to call a DCOP interface without doing the marshalling
+manually. To use a stub, add MyInterface.stub to the SOURCES list of
+your Makefile.am. The stub class will then be called MyInterface_stub.
+
+Conclusion:
+-----------
+
+Hopefully this document will get you well on your way into the world
+of inter-process communication with KDE!  Please direct all comments
+and/or suggestions to Preston Brown <pbrown@kde.org> and Matthias
+Ettrich <ettrich@kde.org>.
+
+
+Inter-user communication
+------------------------
+
+Sometimes it might be interesting to use DCOP between processes
+belonging to different users, e.g. a frontend process running
+with the user's id, and a backend process running as root.
+
+To do this, two steps have to be taken:
+
+a) both processes need to talk to the same DCOP server
+b) the authentication must be ensured
+
+For the first step, you simply pass the server address (as
+found in .DCOPserver) to the second process. For the authentication,
+you can use the ICEAUTHORITY environment variable to tell the
+second process where to find the authentication information.
+(Note that this implies that the second process is able to
+read the authentication file, so it will probably only work
+if the second process runs as root. If it should run as another
+user, a similar approach to what kdesu does with xauth must
+be taken. In fact, it would be a very good idea to add DCOP
+support to kdesu!)
+
+For example
+
+ICEAUTHORITY=~user/.ICEauthority kdesu root -c kcmroot -dcopserver `cat ~user/.DCOPserver`
+
+will, after kdesu got the root password, execute kcmroot as root, talking
+to the user's dcop server.
+
+
+NOTE: DCOP communication is not encrypted, so please do not
+pass important information around this way.
+
+
+Performance Tests:
+------------------
+A few back-of-the-napkin tests folks:
+
+Code:
+
+#include <kapplication.h>
+
+int main(int argc, char **argv)
+{
+  KApplication *app;
+
+  app = new KApplication(argc, argv, "testit");
+  return app->exec();
+}
+
+Compiled with:
+
+g++ -O2 -o testit testit.cpp -I$QTDIR/include -L$QTDIR/lib -lkdecore
+
+on Linux yields the following memory use statistics:
+
+VmSize:     8076 kB
+VmLck:         0 kB
+VmRSS:      4532 kB
+VmData:      208 kB
+VmStk:        20 kB
+VmExe:         4 kB
+VmLib:      6588 kB
+
+If I create the KApplication's DCOPClient, and call attach() and
+registerAs(), it changes to this:
+
+VmSize:     8080 kB
+VmLck:         0 kB
+VmRSS:      4624 kB
+VmData:      208 kB
+VmStk:        20 kB
+VmExe:         4 kB
+VmLib:      6588 kB
+
+Basically it appears that using DCOP causes 100k more memory to be
+resident, but no more data or stack.  So this will be shared between all
+processes, right?  100k to enable DCOP in all apps doesn't seem bad at
+all. :)
+
+OK now for some timings.  Just creating a KApplication and then exiting
+(i.e. removing the call to KApplication::exec) takes this much time:
+
+0.28user 0.02system 0:00.32elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (1084major+62minor)pagefaults 0swaps
+
+I.e. about 1/3 of a second on my PII-233.  Now, if we create our DCOP
+object and attach to the server, it takes this long:
+
+0.27user 0.03system 0:00.34elapsed 87%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (1107major+65minor)pagefaults 0swaps
+
+I.e. about 1/3 of a second.  Basically DCOPClient creation and attaching
+gets lost in the statistical variation ("noise").  I was getting times
+between .32 and .48 over several runs for both of the example programs, so
+obviously system load is more relevant than the extra two calls to
+DCOPClient::attach and DCOPClient::registerAs, as well as the actual
+DCOPClient constructor time.
+
diff --git a/server/Makefile.am b/server/Makefile.am
new file mode 100644 (file)
index 0000000..3304996
--- /dev/null
@@ -0,0 +1,15 @@
+
+INCLUDES=-I$(top_srcdir) $(DBUS_SERVER_CFLAGS) \
+       -DDAEMON_NAME=\"dbus-daemon-1\"
+
+EFENCE=
+
+bin_PROGRAMS=dbus-daemon-1
+
+dbus_daemon_1_SOURCES=                         \
+       main.c
+
+dbus_daemon_1_LDADD=                           \
+       $(EFENCE)                               \
+       $(DBUS_SERVER_LIBS)                     \
+       $(top_builddir)/dbus/libdbus-convenience.la
diff --git a/server/main.c b/server/main.c
new file mode 100644 (file)
index 0000000..1025a0e
--- /dev/null
@@ -0,0 +1,8 @@
+
+int
+main (int argc, char **argv)
+{
+
+
+  return 0;
+}
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644 (file)
index 0000000..e69de29