13.6. Developer Concerns and Tools in DCOP

At this point in the journey of learning DCOP, most of the necessary notions and principles have been presented. You should be able to add DCOP functionality to your existing KDE code. The appropriation of the information presented in the preceding sections hopefully offers a good foundation. A wealth of concrete DCOP usage examples are provided in the standard KDE code.

The remaining sections attempt to provide a fast reference to deeper technical details related to DCOP.

13.6.1. Stay Informed

The team of developers focusing on the KDE's communication protocol technology has made a number of additions to the standard DCOP API designed to make the protocol more informative and even easier to use.

Because DCOP makes use of a server that has to run permanently, willing DCOP clients can be enabled to access an important amount of information about their peers running at a given moment on the desktop. The functionalities offered by the peers are also made publicly available. Following is a list of DCOP API tools that will extract and report this kind of information. The presentation offered here for each of the tools is brief. For a complete description of their programming interface, the API documentation available at http://developer.kde.org is the authoritative resource.

  • isRegistered()—Returns a boolean value stating whether the current client is already registered with the DCOP server. This method is particularly useful when using DCOP in KPart applications. More details are provided near the end of this section.

  • isApplicationRegistered()—Accepts a QCString parameter containing the identifier of a remote DCOP client. Returns a true boolean value if an application with the given identifier is registered with the DCOP server.

  • registeredApplications()—Returns a list of identifiers for all applications registered with the DCOP server.

  • remoteObjects()—Given the identifier of a remote DCOP client as a parameter, returns a list of all DCOP-enabled objects in that client.

  • remoteInterfaces()—Returns the list of DCOP interfaces that a client implements. The clients that use automatic DCOP interface generation (the dcopidl tools) have at least a DCOPObject interface declared. The data provided by this method has no functional role, but only an informative one.

  • remoteFunctions()—Requires an application identifier and an object signature as parameters and returns the list of methods accessible through DCOP for the designated hierarchy.

  • findObject()—This method is a complex tool that was particularly useful before the heuristic mechanisms were added to the DCOPClient::call() method. It takes as parameters a trial client identifier, a trial object signature, and a few other optional parameters. The real identifier and the signature of the DCOP hierarchy (application/object1/object2/…) that answered the request properly are returned as references. The method returns a false boolean value if no matching client is found. This is a potentially blocking method (in other words, its execution time could be long enough to hinder the user interface activity). It is possible to counter the effects of blocking by setting a true boolean value to the useEventLoop parameter that the method accepts.

  • senderId()—Returns the DCOP identifier of the last peer with which the current client had communication. This is potentially particularly powerful and useful information.

  • socket()—Returns a number that identifies the ICEConnection socket over which communication is established with the DCOP server.

13.6.2. Referencing DCOP Objects

Another powerful functionality added recently to the DCOP API is represented by the message redirection technology (also called referencing). A normal DCOP client can create and use DCOPRef objects. The role of this type of objects is to provide a reference to an object made public over DCOP by a remote client. The identifier of the remote client as well as the signature of the receptor object can be indicated at the creation or at any other moment in the life of the DCOPRef object. It might not be immediately obvious what role the DCOP object references in the general desktop communication landscape are playing. An example will help for a better understanding. KDesktop is an application that offers the KDE user control over the background of the computer screen, usually referred to as the desktop. KDesktop manages the following:

  • The desktop icons and icon operations (for example, Alignment)

  • Drag-and-drop operations on the desktop

  • The "Trash"

  • The "AutoStart" functionality

  • The desktop's contextual menus

  • Wallpapers

  • Screensavers

Apart from this set of obvious responsibilities, KDesktop is also charged with the hidden capability of providing the user with the necessary means for remote control of these desktop resources. As a consequence, KDesktop became one of the most important beneficiaries of the DCOP technology. In accordance with the object-oriented programming philosophy, the stretch of functionalities KDesktop controls required modularization. Thus, the control over wallpapers and the handling of screensavers is passed on to modules. Yet, it is logical to have DCOP control over all KDesktop functionalities published to the DCOP "community" of applications from KDesktop. Because the wallpaper handling module (named KBackground) and the screen locking engine have their own DCOP interfaces, the general DCOP interface of KDesktop is designed as shown in Listing 13.13.


Example 13.13. Example of DCOPRef Usage

   1 
   2 File KDesktopIface.h (from the real KDE-2.0 code base)
   3 ------------------------------------------------------
   4  1: #ifndef __KDesktopIface_h__
   5  2: #define __KDesktopIface_h__
   6  3:
   7  4: #include <qstringlist.h>
   8  5: #include <dcopobject.h>
   9  6: #include <dcopref.h>
  10  7:
  11  8: class KDesktopIface : virtual public DCOPObject
  12  9: {
  13 10:   K_DCOP
  14 11: public:
  15 12:
  16 13: k_dcop:
  17 14:   virtual void rearrangeIcons() = 0;
  18 15:   virtual void rearrangeIcons( bool bAsk ) = 0;
  19 16:   virtual void lineupIcons() = 0;
  20 17:   virtual void selectIconsInRect( int x, int y, int dx, int dy ) = 0;
  21 18:   virtual void selectAll() = 0;
  22 19:   virtual void unselectAll() = 0;
  23 20:   virtual QStringList selectedURLs() = 0;
  24 21:   virtual void configure() = 0;
  25 22:   virtual void popupExecuteCommand() = 0;
  26 23:   virtual DCOPRef background() = 0;
  27 24:   virtual DCOPRef screenSaver() = 0;
  28 25: };
  29 26:
  30 26: #endif
  31 
  32 File desktop.h (from the real KDE-2.0 code base)
  33 ------------------------------------------------
  34 .
  35 96:  virtual DCOPRef background()
  36      { return DCOPRef( "kdesktop", "KBackgroundIface" ); }
  37 97:  virtual DCOPRef screenSaver()
  38      { return DCOPRef( "kdesktop", "KScreensaverIface" ); }
  39 .
  40 .
  41 .
  42 

The relevant lines are, of course, 23 and 24 in KDesktopIface.h and the clipped lines from desktop.h. At the level of the client's DCOPObject representation, this results in the addition of objects named "KBackgroundIface" and "KScreensaverIface" to the rest of the (normally built) DCOP interface of KDesktop. These objects allow, as expected, remote control over functionalities of the background engine and the screen locking engine. The automatically generated DCOP interfaces of these modules are defined independently. For a thorough understanding of the topic of DCOP object referencing, you may prefer to peruse the source code of the KDesktop application.

13.6.3. Signals and Slots Through the DCOP Server

KDE developers are very familiar with the concepts of signals and slots intensively used by the Qt library, the basement on which KDE is built. Very powerful and particularly useful concepts, the signals and slots play an important role in the elegance and the ease of use of the Qt toolkit. The DCOP API contains the implementation of a similar mechanism. In addition to the "strong" bindings offered by the DCOPClient::send() and DCOPClient::call() methods, DCOPSignals provide what can be depicted as "weak" or "flexible" bindings. The mildly experienced Qt programmer will be able to appropriate the principle of DCOPsignals easily. The equivalents of Qt's QObject::connect(), QObject::disconnect(), and QObject::emit() methods are conveniently named DCOPClient::connectDCOPSignal(), DCOPClient::disconnectDCOPSignal(), and DCOPClient::emitDCOPSignal(). They use roughly similar functioning principles too. There are two noticeable differences between the implementation of Qt's signals and slots and the implementation of KDE's over-DCOP signals and slots:

  • Data has to be encapsulated into a proper QByteArray/QDataStream envelope when passed over a DCOP signal-slot connection from a DCOPClient::emitDCOPSignal() method call.

  • In order to have proper control over-DCOP signal/slot connections, a supplementary method from the DCOPClient API has to be invoked before actually using them. This method is DCOPClient::setNotifications() and has to be called after establishing all wanted connections, but before issuing the first DCOP signal emit.

  • There are a few predefined, convenient signals, built in to the DCOPClient class:

    • The signal DCOPClient::applicationRegistered() is emitted automatically at the moment a client uses the attach() method.

    • Its counterpart, DCOPClient::applicationRemoved(), is emitted when a detach() call is performed (this usually happens when the client quits functioning).

13.6.4. DCOP with an Embedded KPart

DCOP and KParts are the technologies KDE is using to comply with the modern requirements of software modularization. Both technologies are convenient for building reusable objects and, when used together, they open large opportunities for creatively minded developers. This section attempts to draw attention to the somewhat delicate aspect of programming modules using both the embedding and the communication technologies at once.

There is nothing that prevents an embeddable KPart from gaining DCOP functionality. The developer needs to write in his KPart the usual code meant to create the DCOP client object, to attach it to the server, and then to register it so that the duplex communication can be enabled. Yet, it is important to note that the embedding application, which will host the DCOP client KPart, may also be a DCOP client before the embedding occurs. In consequence, caution is required. Listing 13.14 is a small example of proper DCOP client registration code as provided in the KWrite editor KPart.


Example 13.14. DCOP within a KPart

   1 
   2 File kwview.cpp (from the real KDE-2.0 code base)
   3 ------------------------------------------------
   4 .
   5 .
   6 1527:   DCOPClient *client = kapp->dcopClient();
   7 1528:   if (!client->isRegistered())  // just in case we're embedded
   8 1529:   {
   9 1530:     client->attach();
  10 1531:     client->registerAs("kwrite");
  11 1532:   }
  12 .
  13 .
  14 

The need for such code comes from the fact that attempting to register an embedded KPart instance while the embedding application is already registered with the DCOP server will modify (with unpredictable consequences) the identity of the embedding application on the DCOP client names pool.

The solution to this problem is based on a simple but brilliant idea:

  • The DCOP client object is created using the normal instantiation method.

  • Prior to all attaching and registering attempts, a check with the DCOP server is performed in order to learn whether a legitimate registration is already available.

  • If the embedding application is already registered, then the embedded KPart instance learns that proper registration exists, hence it doesn't need to register itself anymore.

  • If the embedding application doesn't exhibit DCOP functionality, then the KPart instance needs to register properly.

A question becomes evident: How does the embedded KPart instance acquire proper visibility in the DCOP "community" when the embedding application is already registered? Indeed, the embedded KPart instance needs a working registration with the server so that it can receive DCOP calls from the peer clients. The little secret resides in proper usage of DCOPRef objects previously presented. At embedding time, the embedding application creates DCOPRef objects for the DCOP objects that an embedded KPart instance makes public. For example, as a result of this behavior, a Konqueror DCOP client with an embedded KWrite view part, observed from the exterior, will appear to provide a reunion of Konqueror-specific and KWrite-specific DCOP object interfaces.

13.6.5. Performance and Overhead

DCOP presently plays a central role in the KDE desktop. Also, the history of the KDE project recorded rather painful CORBA experiences, therefore the concerns about performance, resource usage, and overhead related to the intensive usage of the protocol are legitimate. Fortunately, KDE team members performed a few instrumental tests. Also, many hundreds of developers and alpha/beta testers assured rather intensive normal usage testing during many months. This section enlists a collection of significant results, courtesy of KDE developers Preston Brown, Matthias Ettrich, David Faure, Waldo Bastian, and Kurt Granroth.

Concerning performance, numbers regarding the useful message exchanges between peers are of interest. Consider, for example, two clients only, passing messages between them by the mediation of the DCOP server.

Usual desktop computers (popular processors running at frequencies of around 300 MHz) are credited with allowing 1500 to 2000 usual DCOP messages per second. Usual DCOP messages consist of rather small amounts of data (1 to 5 Kbytes). The two clients aren't able to saturate the capabilities of the server. Adding two more clients determines the augmentation of the maximal counts with about 40%.

In order to put these numbers in context, we have to observe that the MICO implementation of CORBA provides results of about 900 hits on a same type of computer. Also note that usual IPC/RPC implementations are credited with a maximum of 3000 hits per second. As a conclusion, DCOP is fast enough for the practical needs of modern desktop environment software.

The disadvantages associated with DCOP appear evident, though, when trying to transfer large amounts of data between clients. The explication resides in the fact that the operation of data copying always has to be performed twice (first from the sender client to the DCOP server, then from the server to the receptor). This issue is known to the KDE developers. The proposed solution consists of implementing shared memory backend usage for such large data transfers. The design of the current DCOP implementation would easily allow for such an enhancement. It is worth mentioning that Stefan Westerfeld, member of the KDE Multimedia team, designed and implemented a communication protocol adapted to the needs of multimedia applications. His protocol (named MCOP, as you will learn about in Chapter 14, "Multimedia") is similar in functionality to DCOP but allows for asynchronous, fast transfers of the large amounts of data specific to this particular field (video and audio streams, for example). This technology is also actively used in the current version of KDE (2.0) under the form of the network-transparent, composition-capable, KDE audio technology and server (named aRts and artsd respectively).

DCOP, as all other computer technologies, will need to use memory and processing power in order to do something useful. For the case in discussion, the memory usage is required by the operation of equipping a normal KDE KApplication object with a functional DCOP client data and live code structures. According to preliminary measurements performed by KDE developers, this memory overhead amounts to about 100 Kbytes per application. When measuring startup time delays that might be introduced by using DCOP in a usual KDE application, these delays are too small for the observer to detect them from the statistical variation.

It is thus obvious that performance and overhead aren't hindering issues with DCOP. Yet, the developers are carefully observing these and are striving to keep DCOP's impact on normal use of the KDE software as small as possible.