mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-10 14:00:15 +01:00
initial import of "dbus" skeleton
This commit is contained in:
parent
47229f7331
commit
93cff3d69f
20 changed files with 897 additions and 0 deletions
1
AUTHORS
Normal file
1
AUTHORS
Normal file
|
|
@ -0,0 +1 @@
|
|||
Havoc Pennington <hp@redhat.com>
|
||||
121
COPYING
Normal file
121
COPYING
Normal file
|
|
@ -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.
|
||||
4
ChangeLog
Normal file
4
ChangeLog
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
2002-11-21 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* Initial module creation
|
||||
|
||||
0
INSTALL
Normal file
0
INSTALL
Normal file
3
Makefile.am
Normal file
3
Makefile.am
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
SUBDIRS=dbus server test doc
|
||||
|
||||
1
NEWS
Normal file
1
NEWS
Normal file
|
|
@ -0,0 +1 @@
|
|||
No news.
|
||||
1
README
Normal file
1
README
Normal file
|
|
@ -0,0 +1 @@
|
|||
D-BUS is a simple IPC library based on messages.
|
||||
10
acconfig.h
Normal file
10
acconfig.h
Normal file
|
|
@ -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
|
||||
70
autogen.sh
Executable file
70
autogen.sh
Executable file
|
|
@ -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."
|
||||
64
configure.in
Normal file
64
configure.in
Normal file
|
|
@ -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
|
||||
])
|
||||
11
dbus-1.0.pc.in
Normal file
11
dbus-1.0.pc.in
Normal file
|
|
@ -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
|
||||
|
||||
22
dbus/Makefile.am
Normal file
22
dbus/Makefile.am
Normal file
|
|
@ -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 "^[[^_]].*"
|
||||
0
dbus/dbus-hash.c
Normal file
0
dbus/dbus-hash.c
Normal file
0
dbus/dbus-message.c
Normal file
0
dbus/dbus-message.c
Normal file
0
dbus/dbus.h
Normal file
0
dbus/dbus.h
Normal file
7
doc/Makefile.am
Normal file
7
doc/Makefile.am
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
EXTRA_DIST= \
|
||||
dcop-howto.txt \
|
||||
fdmb-design.txt \
|
||||
fdmb-messages.txt \
|
||||
fdmb-properties.txt \
|
||||
message-delivery.txt \
|
||||
message-matching.txt
|
||||
559
doc/dcop-howto.txt
Normal file
559
doc/dcop-howto.txt
Normal file
|
|
@ -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.
|
||||
|
||||
15
server/Makefile.am
Normal file
15
server/Makefile.am
Normal file
|
|
@ -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
|
||||
8
server/main.c
Normal file
8
server/main.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
0
test/Makefile.am
Normal file
0
test/Makefile.am
Normal file
Loading…
Add table
Reference in a new issue