<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dcop on Roberto Selbach</title><link>https://rselbach.com/tags/dcop/</link><description>Recent content in Dcop on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sun, 02 Mar 2003 11:44:53 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/dcop/index.xml" rel="self" type="application/rss+xml"/><item><title>Let DCOP Tell You the Signature</title><link>https://rselbach.com/let-dcop-tell-you-the-signature/</link><pubDate>Sun, 02 Mar 2003 11:44:53 +0000</pubDate><guid>https://rselbach.com/let-dcop-tell-you-the-signature/</guid><description>&lt;p&gt;A DCOP call failed today even though the method name was correct. The method name, unfortunately, was only part of the name that mattered. I had sent an &lt;code&gt;int&lt;/code&gt;; the exported function expected an unsigned value.&lt;/p&gt;
&lt;p&gt;Before changing code, I ask the running object what it exposes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop myapp MainIface
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output includes complete function signatures. In this case it shows &lt;code&gt;void setPage(unsigned int)&lt;/code&gt;. I then call it from the command line with a small test argument:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop myapp MainIface setPage &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;DCOP identifies methods by their signatures and marshals known Qt types through &lt;code&gt;QDataStream&lt;/code&gt;. The sending and receiving sides must therefore agree on argument types, order, and return type. A visually similar C++ declaration is not necessarily the same wire contract.&lt;/p&gt;
&lt;p&gt;For custom values, both programs need compatible streaming operators and type registration. I avoid custom structures in small public interfaces when a &lt;code&gt;QString&lt;/code&gt;, &lt;code&gt;QCString&lt;/code&gt;, or simple list expresses the operation clearly. Fewer private types also make the command-line client useful.&lt;/p&gt;
&lt;p&gt;When writing the C++ caller, I keep the request and reply types visible next to each other:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QByteArray data;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QDataStream &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;(data, IO_WriteOnly);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; page &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;args &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; page;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QCString replyType;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QByteArray replyData;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;client&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;call(app, &lt;span style="color:#e6db74"&gt;&amp;#34;MainIface&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;setPage(unsigned int)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data, replyType, replyData)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kdWarning() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;DCOP setPage call failed&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a function with a return value, I verify &lt;code&gt;replyType&lt;/code&gt; before extracting from &lt;code&gt;replyData&lt;/code&gt;. Deserializing a reply under the wrong assumption merely converts a useful interface error into strange application state.&lt;/p&gt;
&lt;p&gt;The application and object names should not be copied from a single run if multiple instances are possible. I list registered clients and decide whether the program is meant to address one instance, every instance, or the instance owning a particular document. A suffix added to keep names unique is normal, not a DCOP server losing its arithmetic.&lt;/p&gt;
&lt;p&gt;I also preserve failures in scripts. The command-line client returns useful status, and a shell script should check it rather than carrying on after the target application has exited. Interprocess calls cross a lifetime boundary; yesterday&amp;rsquo;s object name is not a reservation for today.&lt;/p&gt;
&lt;p&gt;I keep the exported interface narrow and test it independently of the window. If the command works but a toolbar action does not, DCOP has been acquitted and I can inspect the connection instead.&lt;/p&gt;
&lt;p&gt;I let &lt;code&gt;dcop&lt;/code&gt; provide the authoritative spelling instead of copying it from memory. Memory is fast, local, and apparently not type-safe.&lt;/p&gt;</description></item><item><title>A Small DCOP Command Is a Good Test</title><link>https://rselbach.com/a-small-dcop-command-is-a-good-test/</link><pubDate>Tue, 14 May 2002 18:36:52 +0000</pubDate><guid>https://rselbach.com/a-small-dcop-command-is-a-good-test/</guid><description>&lt;p&gt;I needed to tell a running application to refresh a document, and my first instinct was to add a socket and invent a tiny protocol. Then I remembered that a KDE session already has DCOP, including discovery, calls, and argument marshalling. It seemed wasteful to build a worse version before lunch.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dcop&lt;/code&gt; command is the quickest way to see what is available:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop konqueror
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop konqueror KonquerorIface
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first command lists registered applications. Supplying an application lists its objects and interfaces; adding an object shows callable functions. This is useful beyond scripting. It tells me whether the object registered under the name I expected and whether the signature exported by the program matches my mental version of it.&lt;/p&gt;
&lt;p&gt;For a simple application object, I derive from &lt;code&gt;DCOPObject&lt;/code&gt; and name the interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RefreshIface&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;virtual&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; DCOPObject
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; K_DCOP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; k_dcop:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;virtual&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; refresh(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; QString &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;path) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The implementation registers through the application&amp;rsquo;s &lt;code&gt;DCOPClient&lt;/code&gt;. Calls are sent through the session&amp;rsquo;s DCOP server, which locates the target client and carries the serialized arguments. The caller does not need the target&amp;rsquo;s process identifier, and the receiver can expose a small interface rather than its internal objects.&lt;/p&gt;
&lt;p&gt;I keep DCOP methods coarse. Sending &lt;code&gt;refresh(QString)&lt;/code&gt; is reasonable; reproducing every setter on a widget is not. Once the interface mirrors the user interface, outside programs depend on details I will want to change.&lt;/p&gt;
&lt;p&gt;There is also a choice between a call that waits for a reply and one that merely sends a message. I use a synchronous call only when the result is genuinely needed. Blocking while another desktop process opens a file or asks a question can make both programs feel frozen.&lt;/p&gt;
&lt;p&gt;Application names need care as well. A second instance may register with a numbered name rather than replacing the first one. If the operation concerns a particular document, guessing the first process in the list is unsafe. I either arrange single-instance behavior deliberately or discover the intended application and object from information I already have. DCOP removes the need for process identifiers; it does not remove the need to choose the right process.&lt;/p&gt;
&lt;p&gt;Failures should remain visible. A call can fail because the application exited, the object disappeared, or the signature changed. I report that to the caller instead of treating a missing reply as an empty successful result.&lt;/p&gt;
&lt;p&gt;My rule now is to prove the exchange with the command-line client first. If &lt;code&gt;dcop&lt;/code&gt; cannot see or call the object, another page of C++ is unlikely to improve matters. This is one of those rare debugging techniques that removes code, which makes it suspiciously pleasant.&lt;/p&gt;</description></item></channel></rss>