1
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook V3.1-Based Variant V1.0//EN" [
2
<!ENTITY kdevelop "<application>kdevelop</application>">
3
<!ENTITY % addindex "IGNORE">
4
<![ %addindex; [ <!ENTITY docindex SYSTEM "docindex.docbook"> ]]>
9
<title>The KDE 2 Developer's Guide</title>
10
<subtitle>The KDE 2 information guide to development, I/O slaves and KOM/OpenParts</subtitle>
13
<firstname>Ralf</firstname>
14
<surname>Nolden</surname>
17
<firstname>Kurt</firstname>
18
<surname>Granroth</surname>
21
<firstname>Simon</firstname>
22
<surname>Hausmann</surname>
25
<firstname>David</firstname>
26
<surname>Sweet</surname>
29
<firstname>Preston</firstname>
30
<surname>Brown</surname>
33
<firstname>Torben</firstname>
34
<surname>Weis</surname>
37
<firstname>Bern</firstname>
38
<surname>Wuebben</surname>
41
<date>21/03/2000</date>
42
<releaseinfo>1.02.00</releaseinfo>
44
<para>This Handbook is a collection of various documentation about KDE 2 development. Each chapter remains the copyright of the original
45
author mentioned at the beginnig of the chapters and in section <link linkend="Copyright">Copyright</link>.</para>
48
<keyword>KDE</keyword>
49
<keyword>KDevelop</keyword>
50
<keyword>I/O slaves</keyword>
51
<keyword>KOM</keyword>
52
<keyword>OpenParts</keyword>
56
<chapter id="preface">
57
<title>Preface</title>
59
<para>This handbook has been assembled to provide KDE developers the information they will need when porting their applications to KDE 2,
60
currently under development. KDE 2 is based on the Qt 2.x and KDE 1.1.x libraries, whereby the KDE libraries are ported to work with
61
the current Qt library. Further, the KDE libraries will introduce a component technology based on the MICO CORBA implementation which
62
is developed and tested with the KOffice suite.</para>
64
<para>As KDE application developers not involved in implementing for the KDE core team will probably want to port their applications, they
65
will not only have to watch out for the changes in Qt, but also for KDE's improvements and additions. As KDE 1.x applications will not
66
only be binary incompatible but also sourcecode incompatible, we want to provide enough information that can be used by developers that
67
are using the currently stable KDE 1.x implementation for applications that are suitable for production use, so transitioning will be
68
made less complicated and further implementations in current projects can be reviewed for possible problems that will arise when
71
<para>Also the usual KDE developer does not have too much information about CORBA, not to speak of KOM. Therefore, this handbook tries to
72
give an insight where to get information and how the current implementation works in general. This will enable you to find out where
73
your applications can probably take advantage of distributed component technology where needed. In conjunction with the latest
74
development, this version of the KDE 2 Developer's Guide also contains a short HOWTO for the new DCOP (Desktop COmmunications
75
Protocol), which was created due to performance problems of local desktop applications using CORBA. Therefore, a few things mentioned
76
and explained in the documents relying on CORBA technology can be out of date and reading yourself into the dcop library reference and
77
reviewing current KDE CVS sourcecode will give you probably more up-to-date information on IPC (Inter-Process-Communication) between
78
local desktop applications using DCOP.</para>
80
<para>I want to thank all authors that were willing to contribute their current documentation to this handbook and hope this collection will
81
be of good use to those who want to stay on the bleeding edge of KDE development.</para>
83
<para>Ralf Nolden</para>
86
<chapter id="mini-howto">
87
<title>The KDE Developer's mini-HOWTO</title>
89
<para>David Sweet &<;dsweet@chaos.umd.edu&>;</para>
91
<para>March, 11, 2000</para>
93
<para><emphasis>To help develop KDE or a KDE application you need to know
94
how to (i) find KDE information and code, (ii) use CVS, and (iii)
95
compile. This document aims to help to you do these things without
96
losing too much hair. This HOWTO is geared toward new developers, occasional
97
developers, and anyone considering contributing the the most excellent
98
free software project that is KDE. It addresses questions that I and
99
others have been asking on the <emphasis remap="bf">kde-devel</emphasis> mailing list recently
100
along with some more general information.
101
You can find a current version of this document at the
102
<ulink url="http://www-chaos.umd.edu/~dsweet/KDE/DeveloperHOWTO">KDE Developer's HOWTO homepage</ulink>.
103
To contribute, comment, or correct, please email me at
104
<ulink url="mailto:dsweet@chaos.umd.edu">dsweet@chaos.umd.edu</ulink></emphasis></para>
106
<sect1 id="information-and-source-code">
107
<title>Information and Source Code</title>
109
<sect2 id="general-information">
110
<title>General Information</title>
112
<para>The K Desktop Environment is an open source Unix desktop created by volunteers from around the world. There are many ways to
113
contribute to the project. You can write new code, improve old code, write documentation, translate to other languages, create
114
artwork, sounds, & music, report bugs, and suggest new features. If you would like to develop code, read on. If you would like to
115
contribute in another way, please visit the KDE web site (<ulink url="http://www.kde.org">\|\|</ulink> name="http://www.kde.org">) for more information.</para>
117
<para>KDE uses the Qt toolkit which is developed by Troll Tech (<ulink url="http://www.troll.no">http://www.troll.no</ulink>). The main
118
components of the desktop are a file manager (kfm), window manager (kwm), and panel (kpanel). There are many more utilities and
119
applications which are included in the base distribution and available elsewhere. The primary programming language used for development
120
is C++, although bindings are available for Python (pyKDE). The KDE code consists of libraries containing classes for, for example:
121
(libkdecore) an application base (KApplication), accessing configuration files (KConfig), launching external processs (KProcess);
122
(libkdeui) widgets (KEdit, KFontDialog, KToolBar, etc.); and other utility classes like KFileDialog (a file dialog) and KSpell (a
123
spellchecker).</para>
125
<para>Various desktop, configuration, and system administration utilities are also included in the distribution. These are
126
some of the things KDE developers work on. A more recent creation is KOffice, a productivity suite which includes a word processor,
127
spreadsheet, and presentation tool The currently released version of KDE is 1.1.2.</para>
129
<para>KDE 2.0, which is, perhaps, the main focus of development right now, will include rewrites or major updates of kfm, khtmlw (an HTML
130
widget), kpanel, kmail, and maybe kwm, unicode support, Inter-Process-Communication protocols and much more.</para>
136
<para><itemizedlist><listitem>
137
<para>The main KDE web site is at: <ulink url="http://www.kde.org">http://www.kde.org</ulink>.</para>
140
<para>The developer's library is at: <ulink url="http://developer.kde.org">http://developer.kde.org</ulink>.</para>
143
<para> Bug reports can be found at (and sent to): <ulink url="http://bugs.kde.org">http://bugs.kde.org</ulink>.</para>
146
<para> Troll Tech (makers of the Qt toolkit) main site: <ulink url="http://www.troll.no">http://www.troll.no</ulink>.</para>
149
<para> KDE Source Code and binaries: <ulink url="ftp://ftp.kde.org">ftp://ftp.kde.org</ulink> (or mirrors)</para>
152
<para> Qt Source Code and binaries: <ulink url="ftp://ftp.troll.no">ftp://ftp.troll.no</ulink></para>
154
</itemizedlist></para>
157
<sect2 id="mailing-lists">
158
<title>Mailing lists</title>
160
<para>The list <emphasis remap="bf">kde-devel</emphasis> is for KDE developers in general. The <emphasis remap="bf">kde-koffice</emphasis> mailing list is for developers interested in koffice,
161
and <emphasis remap="bf">kfm-devel</emphasis> is for kfm (the file manager) developers.</para>
163
<para>Send a message to either <emphasis remap="bf">kde-devel-request</emphasis> or <emphasis remap="bf">koffice-request</emphasis> with the message "subscribe myid@myserver" (where myid@myserver
164
stands for your email address). Go to the KDE mail page a click on "Mailing Lists" for more information about other KDE mailing lists
165
and the mailing list archive.</para>
167
<para>Toll Tech provides a list for users of the Qt 2.1 snapshots (discussed below). You may subscribe to this by sending an email to
168
snapshot-users-request@troll.no with the <emphasis>message</emphasis> "subscribe".</para>
170
<para>As a KDE developer you may want or need a kde email address, like joedeveloper@kde.org. To obtain one, send an email with a polite
171
request to Martin Konold at konold@kde.org.</para>
173
<para>To gain access to the KDE CVS respository (discussed below), you firsly need to have a good reason for wanting access. For example,
174
you may be maintaining a CVS module. If you think you have a good reason, send a polite email request to Stephan Kulow
175
&<;coolo@kde.org&>;.</para>
177
<para>You'll also need to send him an encrypted password to get the account set up. To create your encrpyted password, type:
178
<screen> perl -e print\ crypt\('passwd','sa'\)\.\"\\n\"
181
where <literal remap="tt">passwd</literal> is your choice of password and <literal remap="tt">sa</literal> is two random
182
characters from the set (a-zA-Z0-9./). The output is your encrypted
188
<title>KDE CVS</title>
190
<sect2 id="introduction">
191
<title>Introduction</title>
193
<para>The KDE CVS (Concurrent Versions System) is the source code repository for the KDE project. You can access it via (i) WWW:
194
http://www., (ii) cvs utility, (iii) cvsup utility, or (iv) snapshots. You will need CVS access only for (ii); (i), (iii), and (iv) are
195
read-only methods and available to the public.</para>
197
<para>The web page for method (i) explains its usage. I haven't an explanation for method (iii), cvsup, yet. Please see
198
http://www.kde.org/cvsup.html &{; -- Perhaps someone who uses it will contribute a short explanation of usage and information
199
on obtaining it. -- &};</para>
201
<para>The snapshots, (iv), are .tar.bz2 files which contain a section of KDE code (called "modules"; ex, kdelibs, kdeutils) as it looked on
202
some specified day (specified in the filename: ex, kdelibs990517.tar.bz2). The snapshots are posted daily
203
in ftp://ftp.kde.org/pub/kde/unstable/CVS/snapshots. &{; (ii) is described below. &};</para>
205
<para>The repository (or, just "CVS") stores all of the changes made to the source code by all of the contributors so that changes may be
206
undone. Each time a user makes a change (s)he includes a comment so that the devlopment of code can be more easily followed. These
207
comments are sent to the kde-cvs mailing list. The CVS splits into &_;branches&_; which may contain different versions of the KDE project.
208
For example, the two branches being developed now are KDE&_;1&_;1&_;BRANCH and HEAD. They both are derived from the same code (i.e., if you
209
"undid" enough of the changes made to either branch you'd reveal identical source code) but used for different purposes. Here are some
210
branches and descriptions for your reference:</para>
214
<para> KDE&_;1&_;1&_;2&_;RELEASE - code that was considered stable, released,
215
and distributed as KDE 1.1.2
219
<para> HEAD - code which will become KDE 2.0. It is based on Qt 2.1, has a new kwm, kpanel, etc. LOTS of changes.</para>
225
<sect2 id="using-cvs">
226
<title>Using <literal remap="tt">cvs</literal></title>
228
<para>The cvs utility is probably on your system. If not, you should visit <ulink url="http://www.cyclic.com/cyclic-pages/howget.html">http://www.cyclic.com/cyclic-pages/howget.html</ulink> To learn to use it I would recommend reading the man page! But, I've included
229
explanations of some common functions below.</para>
231
<para>Let's assume for this section that your username is <literal remap="tt">joedeveloper</literal>. As written below you should enter all of these commands from
232
some base directory. (KDE/CVS is not a bad choice!)</para>
234
<para>Set the environment variable <literal remap="tt">CVSROOT</literal> to</para>
236
<para><literal remap="tt">:pserver:joedeveloper@cvs.kde.org:/home/kde.</literal></para>
238
<para><emphasis remap="bf">Listing CVS modules</emphasis> You can't do this directly unfortunately. You can, however, view the contents of the file /home/kde/modules
240
<screen>cvs -z6 co -c
244
<para>The <literal remap="tt">-z6</literal> option tells the server to compress the code at "level 6" before sending it to you. This may speed things up for you.
245
(In this case, since the module listing is small, it may not matter.)</para>
247
<para><emphasis remap="bf">Checking out a module</emphasis>, e.g. kdelibs from HEAD
248
<screen>cvs -z6 checkout -r HEAD kdelibs
249
cvs -z6 checkout kdelibs
253
<para>The -r options tells cvs which branch you want to checkout from. The
254
default is the HEAD branch.</para>
256
<para><emphasis remap="bf">Checking out a module</emphasis>, ex. kdelibs, from KDE&_;1&_;1&_;2&_;RELEASE
257
<screen>cvs -z6 checkout -r KDE_1_1_2_RELEASE kdelibs
261
<para><emphasis>Note</emphasis>: you could use co as an abbreviation for checkout.</para>
263
<para><emphasis remap="bf">Checking out an application from within a module</emphasis> (ex kjots, which
264
is in the kdeutils module) from the HEAD branch
265
<screen>(1) cvs -z6 co -l kdeutils
266
(2) cvs -z6 co -l admin
267
(3) cvs -z6 co -l kdeutils/kjots
268
(4) cd kdeutils; ln -s ../admin
272
<para>The <literal remap="tt">-l</literal> in line (1) tells cvs not to recurse the subdirectories of kdeutils. This means will get the configure script and its
273
companions (discussed below), but none of the application source code.</para>
275
<para>Line (2) gets the admin directory which contains support files for autoconf and friends. (This directory is retrieved automatically
276
when checking out an entire module.)</para>
278
<para>Line (3) gets the kjots source.</para>
280
<para>Line (4) makes a link to the admin directory. (This is better than copying or moving the directory here. If you leave admin where cvs
281
put if then you can easily update the admin directory with cvs. You could also make links to admin from any other modules you check
282
out this way and thus have only one, up-to-date copy of admin.)</para>
284
<para><emphasis remap="bf">Updating source code you've previously checked out</emphasis> (ex. kdeutils/kjots)
285
<screen> cvs -z6 update -P -d kdeutils/kjots
289
<para>The source code for kjots on your hard drive will be updated to match the code in the CVS. You don't need to specify the branch here.
290
The correct branch is stored in <literal remap="tt">kdeutils/kjots/CVS/Tag</literal>.</para>
292
<para><emphasis remap="bf">Commiting changes</emphasis> (putting them into CVS) (ex. kdeutils/kjots)
293
<screen>cvs -z6 commit kdeutils/jots
297
<para>You'll be prompted to edit a comment. Enter a short one which desribes the changes you're making with this commmit. (You can use
298
your editor of choice by setting the EDITOR or CVSEDITOR environment variable.)</para>
300
<para><emphasis remap="bf">Adding a file</emphasis> (ex. kdeutils/kmyapp/greatnewcode.cpp)
301
<screen>(create the file first!)
303
cvs add greatnewcode.cpp
308
<para><emphasis remap="bf">Deleting a file</emphasis> (ex. kdeutils/kmyapp/badoldcode.cpp)
309
<screen>cd kdeutils/kmyapp
311
cvs remove badoldcode.cpp
316
<para><emphasis remap="bf">Adding a directory</emphasis> (a module, like a new app) (ex. kdeutils/kmyapp, with the source file kmysource.cpp)
319
(create the kmyapp/kmysource.cpp file)
321
cvs add kmyapp/kmysource.cpp
322
cvs commit (actually puts the directory and file in the CVS)
326
<para><emphasis>Note</emphasis>: You need to have files in a directory to commit it.
327
<emphasis remap="bf">Removing a directory</emphasis> (a module, like a new app) (ex. kdeutils/kmyapp)
328
<screen>cd kdeutils/kmyapp
329
(delete all files, as described above in "Deleting a file")
331
cvs -P update (will remove the local kmyapp automatically)
337
<sect1 id="compiling-and-safe-development-practices-wit">
338
<title>Compiling and Safe Development Practices (with configure)</title>
340
<para>Before you start downloading and compiling the latest sources you should be aware that there's a good chance they won't work! They are
341
in a state of constant development so they could very well have bugs.</para>
343
<para>Knowing this, you should find a way to compile and run new KDE stuff without interfering with your existing stable KDE setup. Here's
344
one way, using the HEAD branch as an example. We, again, assume your login is joedeveloper. We also assume that your home directory
345
is in /home/joedeveloper. (This would be the case for Red Hat systems.)</para>
347
<sect2 id="organizing">
348
<title>Organizing</title>
350
<para>Make a directory called KDE in the home directory of your *user* account. You should not be doing any of this as root! Make another
351
called KDE/CVS-HEAD. cd into that directory and get the KDE sources from the HEAD branch that you want. The (minumum) modules needed
352
to use an application are: kdesupport, kdelibs. You should compile and install them in that order (see below for compiling). Others
353
you might want are: kdebase, kdeutils, kdegraphics, etc. Now, make a directory called KDE/kde-HEAD. This is where you'll store the
354
compiled code from the HEAD branch -- as well as Qt 2.1!</para>
357
<sect2 id="compiling-qt-2.1">
358
<title>Compiling Qt 2.1</title>
360
<para>Let's get Qt 2.1. Take the KDE copy of the current Qt library from the KDE CVS with</para>
362
<para><screen>cvs -z6 co qt-copy
364
setenv QTDIR $PWD (if you use csh/tcsh)
366
export QTDIR=`pwd` (if you use bash)
367
make -f Makefile.cvs (creates symlinks -without that, qt will not compile !)
368
./configure (-gif optionally)
374
<sect2 id="compiling-kde-head">
375
<title>Compiling KDE (HEAD)</title>
377
<para>Now, for the KDE code. <literal remap="tt">cd</literal> to KDE/CVS-HEAD/kdesupport. Type</para>
379
<para><screen>make -f Makefile.cvs
380
./configure --prefix=/home/joedeveloper/KDE/kde-HEAD
381
--with-qt-dir=/home/joedeveloper/KDE/kde-HEAD/qt-copy
382
--with-qt-libs=/home/joedeveloper/KDE/kde-HEAD/qt-copy/lib
385
If all goes well, then
389
If not, try to fix things, then type
393
Repeat this process for the other modules. You should alter the
394
./configure line to read
395
./configure --prefix=/home/joedeveloper/KDE/kde-HEAD
396
--with-qt-dir=/home/joedeveloper/KDE/kde-HEAD/qt-copy
397
--with-qt-libs=/home/joedeveloper/KDE/kde-HEAD/qt-copy/lib
402
<sect2 id="compiling-tips">
403
<title>Compiling tips</title>
407
<para> I usually put that long configure command into a file called <literal remap="tt">conf</literal> and leave it in my CVS-HEAD directory. Then I can do a
408
<literal remap="tt">../conf</literal> from any module and get a good configure.</para>
411
<para> It seems that you need to compile and install qimageio (part of Qt) separately. Just
412
<literal remap="tt">cd</literal> to <literal remap="tt">/$QTDIR/extensions/imageio/src</literal> and type <literal remap="tt">make install</literal></para>
419
<sect1 id="documentation">
420
<title>Documentation</title>
422
<para>It's important to document your application so that end-users can make the most of it. You should be clear and concise. Describe any
423
non-standard installation, usage and UI features. There's no need to talk about how to use the <emphasis>File</emphasis> menu, for example, unless
424
you've put some special entry on it. Include contact and bug-reporting information as well as a hyperlink to the application's home
425
page. Writing documentation for KDE 2 should be done in docbook-sgml. Look at <ulink url="http://developer.kde.org">http://developer.kde.org</ulink> for more details how to get the needed packages for installing the docbook tools. KDE extends these
426
tools by the module kdesdk/ksgmltools. This module also contains information where to get the docbook tools, additional documentation
427
as well as how to use docbook and KDE.</para>
429
<para>You should also document your widgets and other classes. You can include comments in your header ( <literal remap="tt">.h</literal>) files which describe
430
each <literal remap="tt">public</literal> or <literal remap="tt">protected</literal> method. It you do this as you write the methods it will make the documentation proceSss seem
431
easier. (It may also help you be certain about what function(s) that method is to perform.) The script <literal remap="tt">kdoc</literal> will turn your header
432
files into beautiful class documentation. You can see examples of <literal remap="tt">kdoc</literal> output if you look at <ulink url="http://www.ph.unimelb.edu.au/~ssk/kde/srcdoc/kdecore/index-long.html">http://www.ph.unimelb.edu.au/~ssk/kde/srcdoc/kdecore/index-long.html</ulink>. This is the annotated list of the core KDE classes.</para>
434
<para>You can find <literal remap="tt">ksgmltools</literal> in the KDE SDK which is available in the kdesdk module of CVS, <literal remap="tt">kdoc</literal> in the kdoc module. (Methods for
435
getting things from CVS are described above.)</para>
437
<sect2 id="kdoc-the-kde-class-documentation-tool-for-c">
438
<title>KDOC: The KDE Class Documentation Tool for C++</title>
440
<para>It's called <literal remap="tt">kdoc</literal> and is in the kdedoc subdirectory of the CVS
441
module kdesdk.</para>
443
<para>If you mark up your header files like this:
445
* Short description of this class
447
* This is a longer description of my class. It does the following
448
* @li Some bulleted thing
449
* @li Some other bulleted thing
450
* You should use it when ... It's not appropriate for ...
452
* @author My Name <myemail@wherever.edu>
460
* Describe method. It takes &<;i&>;argument&<;/i&>; to mean ...
462
* @return A pointer to another class
465
KOtherClass *method (int argument);
470
<para>The text in the comments beginning with <literal remap="tt">/**</literal> (two asterisks,
471
mind you!) will be taken by <literal remap="tt">kdoc</literal> as class documentation and
472
formatted appropriately. You can use some HTML tags (like the
473
&<;i&>; above). The <literal remap="tt">@author</literal> and other tags are meaningful
474
to <literal remap="tt">kdoc</literal> and used for formatting.</para>
476
<para>To run <literal remap="tt">kdoc</literal>, use the following command
477
<screen> kdoc -dhtml -L$KDEDIR/share/kdoc -a Title header1.h header2.h ...
481
<para>This instructs <literal remap="tt">kdoc</literal> to generate HTML output (the default) in the
482
<literal remap="tt">html</literal> directory (by the <literal remap="tt">-d</literal> option) from the specified header
483
files. It uses <literal remap="tt">Title</literal> as the title for the documentation. ( <literal remap="tt">-a</literal>
484
says to do work on all header files, even if they don't "ask for it". I
485
haven't told you how to "ask for it." The <literal remap="tt">-L</literal> tells kdoc where
486
its libraries are.) Type <literal remap="tt">kdoc -h</literal> for more information.</para>
490
<sect1 id="packaging-and-submitting-code-to-kde">
491
<title>Packaging and Submitting Code to KDE</title>
493
<sect2 id="packaging">
494
<title>Packaging</title>
496
<para>'Packing' means putting your (in this case source) code into some
500
<para> easy for others to configure and install, and</para>
503
<para> easy to transfer,</para>
506
<para> can be indexed so that it is easy to find.</para>
511
<para>These three concepts are expanded upon in the next three subsections.</para>
513
<sect3 id="gnu-configure">
514
<title>GNU Configure</title>
516
<para>The standard KDE application (or other code) source code package includes the GNU <literal remap="tt">configure</literal> script which determines some
517
information about the user's system and provides it to your source code as <literal remap="tt">&#;define</literal> statements in a header file called
518
<literal remap="tt">config.h</literal>.</para>
520
<para>To get started with this, get the kdesdk from CVS using a method described above. Then prepare kexample, an example package, for your
523
<para><screen> cd kdesdk
526
cd ..; cp -r kexample ~/KDE/kmyapp-0.0.1
530
<para>(That last directory is just an example. Replace kmyapp with your application's (or widget's) name, and replace 0.0.1 with its version
533
<para>Now, we'll put your source code into the example package. Let's say your source code was in the directory & ;/KDE/KMyApp:</para>
535
<para><screen> cd ~/KDE/kmyapp-0.0.1
537
cp ~/KDE/KMyApp/*.cpp kmyapp
538
cp ~/KDE/KMyApp/*.h kmyapp
539
(There may be other files to copy, but leave your old Makefile behind!)
542
Now, edit kmyapp-0.0.1/Makefile.am and change the line
543
<screen> SUBDIRS = kexample
547
<screen> SUBDIRS = kmyapp
551
<para><emphasis>Note</emphasis>: kmyapp here refers to the subdirectory by that name. You could include more subdirectories to be compiled. For example:
552
<screen> SUBDIRS = kmyapp kmysupportclass
556
<para>Also edit the last line of configure.in to read</para>
558
<para><screen>AC_OUTPUT(Makefile \
564
<para>The <literal remap="tt">po</literal> directory contains translations of strings that you used in your code (this is about i18n(), which is not covered in this
565
HOWTO). We'll get to that it a minute.</para>
567
<para>Now we want to set up the Makefile for the kmyapp subdirectory. Edit <literal remap="tt">kmyapp/Makefile.am</literal> according to the instructions given
568
in the comments. They should be clear enough.</para>
570
<para>Now <literal remap="tt">cd &˜;/KDE/kmyapp</literal> and type
577
<para> Makefile</para>
580
<para> kmyapp/Makfile</para>
583
<para> config.h</para>
588
<para>You can now include config.h in your source code with <literal remap="tt">&#;include "../config.h"</literal> and have your code compile differently on
589
different systems based on the <literal remap="tt">&#;define</literal>s. Eh? Well, different systems have slightly differnent ideas about implementing
590
standards and such, and your code my need take this into account to be portable, i.e. to work on various Unices. Take a look inside
591
<literal remap="tt">config.h</literal> for descriptions of the <literal remap="tt">&#;define</literal>s.</para>
593
<para><emphasis remap="bf">Shared Libraries!</emphasis> If you are packaging a widget or other class you should be compiling a shared library. Luckily, this is
594
easy to do within the kexample packge. You only need to change the Makefile.am that resides in your code's sudirectory. Unluckily,
595
now example for a shared-library Makefile.am is included. So, I've included one in the next section. <emphasis>Note</emphasis>: If you distribute a
596
widget, you should also distribute a small program which tests the widget. Put that program in the same package in another
597
subdirectory and have it compile along with the widget.</para>
599
<para>Next, make a compressed archive. You can do it this way
600
<screen> cd ~/KDE/kmyapp
603
tar -cvf kmyapp-0.1.1.tgz kmyapp-0.1.1
606
or however you like. Just be sure that the archive expands to <emphasis>one</emphasis> directory containing all of the files. This is neater and
607
easier for the user to deal with.</para>
610
<sect3 id="example-makfile.am-for-a-shared-library">
611
<title>Example Makfile.am for a Shared Library</title>
613
<para><screen># Example Makefile.am for a shared library. It makes a library
614
# called "example" as libexample.so.2.1.2
615
# This Makefile.am was taken from the kdelibs distribution and modified
616
# to serve as an example.
621
INCLUDES= $(all_includes)
623
lib_LTLIBRARIES = libexample.la
625
# Note: If you specify a:b:c as the version in the next line,
626
# the library that is made has version (a-c).c.b. In this
627
# example, the version is 2.1.2.
628
libexample_la_LDFLAGS = -version-info 3:2:1 $(all_libraries)
630
include_HEADERS = header1.h header2.h\
633
# Which headers shouldn't be installed when a make install is done?
634
noinst_HEADERS = version.h
636
libexample_la_SOURCES = code1.cpp code2.cpp
639
# AUTO is great. This takes care of all of your moc'ing
641
# (You still need to include, for example, header1.moc in code1.cpp.)
642
libexample_la_METASOURCES = AUTO
647
<sect3 id="lsm-file">
648
<title>LSM file</title>
650
<para>Next, you need and LSM file. You can keep a copy in kmyapp-0.1.1
651
for distribution.</para>
653
<para>Here's a sample <literal remap="tt">.lsm</literal>:</para>
660
Description: GUI and more for RLab
661
Keywords: kde rlab math plot plotting
662
Author: David Sweet &<;dsweet@chaos.umd.edu&>;
663
Maintained-by: David Sweet &<;'dsweet@chaos.umd.edu&>;
664
Home-page: http://www.glue.umd.edu/~dsweet/KDE/KLab
665
Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/scientific
666
Alternate-site: http://www.glue.umd.edu/~dsweet/KDE/KLab/
667
Original-site: ftp://upload.kde.org/pub/kde/Incoming
675
<para>You can copy and paste this text into a file called "kmyapp.lsm" and make the appropriate changes.</para>
679
<sect2 id="submitting">
680
<title>Submitting</title>
682
<para>If you are hacking at CVS, you should follow the commit procedure outlined above. If you want to submit changes to code
683
that you are not maintaining, you should first check with the maintainer of the application. You can usually find his/her email
684
address in the directory containing the source. Also check the program's "About" box if it has one. If no maintainer is specifically
685
listed, you should contact the author.</para>
687
<para>If you are developing outside of CVS, you can submit your code (widgets, applications, etc.) via FTP to
688
<ulink url="ftp://upload.kde.org/pub/kde/Incoming">ftp://upload.kde.org/pub/kde/Incoming</ulink></para>
690
<para>When you do this be sure to include an <literal remap="tt">.lsm</literal> (Linux Software Map) file. This way your code can be automatically placed in the
691
appropriate spot on ftp.kde.org and its mirrors and an announcement can be automatically sent to the kde-announce mailing list.</para>
693
<para><emphasis>Note</emphasis>: The <literal remap="tt">.lsm</literal> file should be uploaded separately from the source code (as a plain ASCII file). The source code should be
694
packaged as a .tar.gz (or .tgz) or .tar.bz2. This archive should expand to a single directory with all of your stuff in it.</para>
698
<sect1 id="acknowledgements">
699
<title>Acknowledgements</title>
701
<para>I'd like to thank the following people for their suggestions (in no particular order): Roberto Alsina, Waldo Bastian, Harri Porten,
702
Samuel Wuethrich, Richard Moore, Daniel Naber, Ralf Nolden, Martin Konold, and Pietro Iglio, Stephan Kulow, Junji Takagi.</para>
705
<sect1 id="about-this-document">
706
<title>About this document</title>
709
<title>Finding</title>
711
<para>The current version of this document is available at <ulink url="http://www.chaos.umd.edu/~dsweet/KDE/MiniHOWTO">http://www.chaos.umd.edu/~dsweet/KDE/MiniHOWTO</ulink>.</para>
713
<para>A Japanese language version is available at <ulink url="http://www.asahi-net.or.jp/~hc3j-tkg/kde-jp/DevelMiniHOWTO-jp.txt">http://www.asahi-net.or.jp/~hc3j-tkg/kde-jp/DevelMiniHOWTO-jp.txt</ulink> thanks to Junji Takagi.</para>
715
<para>This document is included in the KDE Developer's Web Site (<ulink url="http://developer.kde.org">http://developer.kde.org</ulink>)
716
and is part of the KDevelop (<ulink url="http://www.kdevelop.org">http://www.kdevelop.org</ulink>) programming manuals.</para>
720
<title>Changes</title>
722
<sect3 id="changes-from-version-july-1-1999-to-version-">
723
<title>Changes from version &<;July 1, 1999&>; to version &<;March, 11, 2000&>;:</title>
727
<para> Added "About this document" section</para>
730
<para> Added more acknowledgements</para>
733
<para> Multiple formatting changes (thanks Ralf!)</para>
736
<para> Fixed instructions for getting CVS access</para>
739
<para> updated contents for current KDE 2 development state (March, 11, 2000)</para>
748
<chapter id="using-kde-io-slaves">
749
<title>Using KDE I/O Slaves</title>
751
<para>Kurt Granroth <ulink url="mailto:granroth@kde.org">\|<\|granroth@kde.org\|>\|</ulink></para>
753
<para>v0.1, 15, June 1999</para>
755
<para><emphasis>This HOWTO describes how the KDE I/O slaves (ioslaves) work. It is
756
intended for both ioslave implementers as well as users. In this
757
document, I will attempt to describe both how ioslaves work as well
758
as how to use them.</emphasis></para>
760
<sect1 id="introduction-0">
761
<title>Introduction</title>
763
<sect2 id="what-are-io-slaves">
764
<title>What Are I/O Slaves?</title>
766
<para>The K Desktop Environment (KDE) I/O slaves (ioslaves) are a series of
767
small programs that have intimate knowledge on working with a very
768
specific protocol. For instance, the HTTP ioslave (<literal remap="tt"><indexterm remap="cdx"><primary><literal>kio&_;http</literal></primary></indexterm>kio&_;http</literal>)
769
knows all about sending and receiving data to and from a web server <indexterm remap="idx"><primary>web server</primary></indexterm>. It
770
knows all about SSL <indexterm remap="idx"><primary>SSL</primary></indexterm>, encoding, and what all of the different header fields
771
mean. It knows this so that KDE developers won't have to -- if they want
772
a web page, they merely have to use <literal remap="tt"><indexterm remap="cdx"><primary><literal>kio&_;http</literal></primary></indexterm>kio&_;http</literal> for it and it will
773
take care of everything for them.</para>
775
<para>The ioslaves are based on the KIO library (<literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal>). This library
776
implements a method of asynchronous communication between
777
applications as well as provides a "protocol registry" of sorts.
778
This has many advantages. Two of the major ones are:</para>
782
<para>The client does not need to know anything about the ioslave that
783
it is calling. It merely specifies the protocol and <literal remap="tt">cdx/libkio/</literal> will
784
automatically determine the proper ioslave to use.
788
<para>All communication is done asynchronously. All <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> calls will
789
return immediately. Whenever events occur, <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> will send
790
signals altering the client to that fact. This means that the
791
client does not have to engage in any "busy waiting."</para>
796
<para>Here is a fully working snippet of code to download a web page:<indexterm remap="ncdx"><primary><literal>KIOJob</literal></primary></indexterm><indexterm remap="ncdx"><primary><literal>sigData()</literal></primary></indexterm></para>
798
<para><programlisting> KIOJob *job = new KIOJob;
799
connect(job, SIGNAL(sigData(int, const char*, int)),
800
this, SIGNAL(slotData(int, const char*, int)));
801
job->get("http://www.kde.org/news_dyn.html");
805
<para>That's it! When the ioslave is done getting the KDE news page, it
806
will call your application's slotData() function with the page.</para>
809
<sect2 id="copyright">
810
<title>Copyright</title>
812
<para>Copyright (c) 1999 Kurt Granroth, All rights reserved. This is free
813
documentware; you can redistribute it and/or modify it under the
814
terms of version 2 or later of the
815
<ulink url="http://www.gnu.org/copyleft/gpl.html">GNU General Public License</ulink></para>
819
<sect1 id="setting-up-ioslaves">
820
<title>Setting Up IOSlaves
823
<para>Using the KDE ioslaves is very easy once the framework is in place.
824
This section will describe getting the "back-end" stuff setup.</para>
826
<sect2 id="the-kio-library">
827
<title>The KIO Library
830
<para>The first part that needs to be installed is the KDE IO library
831
(<literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal>). This library is part of the KDE 2.x <literal remap="tt"><indexterm remap="cdx"><primary><literal>kdelibs</literal></primary></indexterm>kdelibs</literal>
833
will be installed by default on all KDE 2.x systems when 2.x is
834
finally released. In the meantime, you will need to get it through
835
either CVSUP or the snapshots. See www.kde.org (or a later appendix
836
when I get around to it later) for details on that.</para>
838
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> depends on the KDE UI library (<literal remap="tt"><indexterm remap="cdx"><primary><literal>libkdeui</literal></primary></indexterm>libkdeui</literal>), the KDE
839
Core library (<literal remap="tt"><indexterm remap="cdx"><primary><literal>libkdecore</literal></primary></indexterm>libkdecore</literal>), and Qt (<literal remap="tt"><indexterm remap="cdx"><primary><literal>libqt</literal></primary></indexterm>libqt</literal>). These are
840
the "standard" KDE libraries so there shouldn't be any problems, there.</para>
843
<sect2 id="the-ioslaves">
847
<para>There are ioslaves for <literal remap="tt"><indexterm remap="cdx"><primary><literal>http</literal></primary></indexterm>http</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>file</literal></primary></indexterm>file</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>gzip</literal></primary></indexterm>gzip</literal>,
848
<literal remap="tt"><indexterm remap="cdx"><primary><literal>tar</literal></primary></indexterm>tar</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>file</literal></primary></indexterm>file</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>smb</literal></primary></indexterm>smb</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>pop3</literal></primary></indexterm>pop3</literal>, and
849
<literal remap="tt"><indexterm remap="cdx"><primary><literal>imap4</literal></primary></indexterm>imap4</literal> as of the time of this writing. They are all found in the
850
<literal remap="tt"><indexterm remap="cdx"><primary><literal>kdebase</literal></primary></indexterm>kdebase</literal> package under <literal remap="tt"><indexterm remap="cdx"><primary><literal>kioslaves</literal></primary></indexterm>kioslaves</literal>. Again, these are
851
available only from the KDE development CVS so you'll need to use CVSUP or
852
the snapshots to retrieve them.</para>
856
<sect1 id="using-ioslaves-in-your-application">
857
<title>Using ioslaves in your Application
860
<para>Now that you have the backend stuff all setup, you can start setting
861
up your application to use them. This requires adding the <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal>
862
library to your linking and including the proper header files.</para>
864
<sect2 id="modifying-your-makefile">
865
<title>Modifying your Makefile
868
<para>If you are using the standard KDE automake/autoconf system for your
869
application, then you are in luck! Adding another library is
874
<para>Edit Makefile.am <indexterm remap="idx"><primary>Makefile.am</primary></indexterm></para>
877
<para>Change the line &<;yourapp&>;<indexterm remap="cdx"><primary><literal>&_;LDADD</literal></primary></indexterm>&_;LDADD to look something like:
879
<programlisting> myapp_LDADD = $(LIB_KIO)
886
<para>That's it! If you are not using the KDE setup, then just make sure
887
that you are including the following in your link stage:</para>
889
<para><programlisting> -lkio -lkdeui -lkdecore -lqt
894
<sect2 id="adding-the-proper-headers">
895
<title>Adding the Proper Headers
898
<para>This is also simple:</para>
900
<para><programlisting> #include <kio_job.h>
904
<para>Will take care of everything.</para>
908
<sect1 id="using-ioslaves-via-kiojob">
909
<title>Using IOSlaves via KIOJob
912
<para>Now that your application is all prepped for using ioslaves, you can
913
actually start using them!</para>
915
<para>The only class you need to deal with at a client level is the KIOJob
916
class. You will use it to "call" the ioslaves and it will send you
917
signals when it received events from them.</para>
919
<para>The basic procedure is something like this:</para>
923
<para>Create a KIOJob <indexterm remap="idx"><primary>KIOJob</primary></indexterm> instance</para>
926
<para>Connect all of the signals (events) that you are interested in to
927
some local slots (callbacks).</para>
930
<para>Send the actual request</para>
933
<para>Process the resulting response in your slots.</para>
938
<sect2 id="typical-example">
939
<title>Typical Example
942
<para>An example looks like so:<indexterm remap="ncdx"><primary><literal>sigData()</literal></primary></indexterm><indexterm remap="ncdx"><primary><literal>sigError()</literal></primary></indexterm><indexterm remap="ncdx"><primary><literal>sigDataEnd()</literal></primary></indexterm><indexterm remap="ncdx"><primary><literal>sigFinished()</literal></primary></indexterm></para>
944
<para><programlisting> KIOJob *job = new KIOJob;
945
connect(job, SIGNAL(sigData(int, const char*, int)),
946
this, SLOT(slotData(int, const char*, int)));
947
connect(job, SIGNAL(sigError(int, int, const char*)),
948
this, SLOT(slotError(int, int, const char*)));
949
connect(job, SIGNAL(sigDataEnd(int)),
950
this, SLOT(slotDataEnd(int)));
951
connect(job, SIGNAL(sigFinished(int)),
952
this, SLOT(slotFinished(int)));
953
job->get("http://www.pobox.com/~kurt_granroth/index.html");
957
<para>This will get the web page at the above URL. When the ioslave is done
958
receiving the page, it will send it to you with your <literal remap="tt"><indexterm remap="cdx"><primary><literal>slotData()</literal></primary></indexterm>slotData()</literal>
959
function. If there was an error, then you receive it in
960
<literal remap="tt">slotError()</literal>. If the page was large, then it will be sent in
961
chunks. You know that you are done receiving data when
962
<literal remap="tt">slotDataEnd()</literal> is called. The <literal remap="tt">slotFinished()</literal> function is
963
called when the ioslave is completely done.</para>
967
<sect1 id="kiojob-calls">
971
<para>There are numerous operations that you can do with KIOJob. Some of them
972
are: <literal remap="tt"><indexterm remap="cdx"><primary><literal>put</literal></primary></indexterm>put</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>get</literal></primary></indexterm>get</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>mkdir</literal></primary></indexterm>mkdir</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>copy</literal></primary></indexterm>copy</literal>,
973
<literal remap="tt"><indexterm remap="cdx"><primary><literal>move</literal></primary></indexterm>move</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>del</literal></primary></indexterm>del</literal>, <literal remap="tt"><indexterm remap="cdx"><primary><literal>unmount</literal></primary></indexterm>unmount</literal>, and <literal remap="tt"><indexterm remap="cdx"><primary><literal>mount</literal></primary></indexterm>mount</literal>. I will
974
refer only to <literal remap="tt"><indexterm remap="cdx"><primary><literal>put()</literal></primary></indexterm>put()</literal> and <literal remap="tt"><indexterm remap="cdx"><primary><literal>get()</literal></primary></indexterm>get()</literal> in this HOWTO. The others
975
follow similar patterns.</para>
977
<sect2 id="getconst-char-url">
978
<title>get(const char* url)
981
<para>This is probably the most common operation. It tells the ioslave to
982
"get" the resource described in the URL. This may be a web page, a
983
POP3 message, or a local file -- it all depends on your URL.</para>
985
<para>This operation is not very interactive. You tell the ioslave what
986
you want and it gets it for you. Period.</para>
988
<para>Specifically, it will send back your data with the <literal remap="tt"><indexterm remap="cdx"><primary><literal>sigData(int id,
989
char char* data, int length)</literal></primary></indexterm>sigData(int id,
990
char char* data, int length)</literal> signal.</para>
992
<para>Parameters:</para>
994
<para>const char *url - The URL of the resource that you wish to get</para>
997
<sect2 id="putconst-char-url-int-mode-bool-overwrite-bo">
998
<title>put(const char* url, int mode, bool overwrite, bool resume, int size)
1001
<para>This operation will start the process of "putting" or sending data to
1002
the location specified in the URL. This is used, for instance, to
1003
send files to a remote FTP server or do do a PUT or POST request with
1004
HTTP. It is not quite a straight-forward as a <literal remap="tt"><indexterm remap="cdx"><primary><literal>get()</literal></primary></indexterm>get()</literal> operation.</para>
1006
<para>The basic procedure looks like:</para>
1008
<para><itemizedlist>
1010
<para>Connect <literal remap="tt"><indexterm remap="cdx"><primary><literal>sigReady(int)</literal></primary></indexterm>sigReady(int)</literal> to a local slot (e.g., <literal remap="tt">slotReady(int)</literal>)</para>
1013
<para>Send a <literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::put(..)</literal></primary></indexterm>KIOJob::put(..)</literal> request</para>
1016
<para>When <literal remap="tt">slotReady(..)</literal> is called, you know that the ioslave is ready
1017
to relay your data to its final destination.</para>
1020
<para>Send all of your data using the <literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::data(const char*, int)</literal></primary></indexterm>KIOJob::data(const char*, int)</literal>
1021
operation. When you are done, notify the ioslave of this by
1022
sending a <literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::dataEnd()</literal></primary></indexterm>KIOJob::dataEnd()</literal></para>
1027
<para>Some sample code looks like so:</para>
1029
<para><programlisting> KIOJob *job;
1030
char *data = "My message";
1034
connect(job, SIGNAL(sigReady(int)), this, SLOT(slotReady(int)));
1035
connect(job, SIGNAL(sigData(int, const char*, int)),
1036
this, SLOT(slotData(int, const char*, int)));
1037
connect(job, SIGNAL(sigDataEnd(int)),
1038
this, SLOT(slotDataEnd(int)));
1039
job->put("http://server.com/cgi-bin/post.cgi", -1, true, false, strlen(data));
1042
void Client::sigReady(int id)
1044
job->data(data, strlen(data));
1050
<para>Parameters:</para>
1052
<para>const char* url - The end location for your data
1053
int mode - Special permissions for your data. This should be set
1054
to -1 if there are no special permissions
1055
bool overwrite - Instructs the ioslave to overwrite anything that
1056
may already be there.
1057
bool resume - Instructs the ioslave to resume a previously aborted
1059
int size - This is the size of the data that you will be sending</para>
1061
<para>Beyond that, everything else is identical to the 'get' method.</para>
1064
<sect2 id="datavoid-data-int-size">
1065
<title>data(void *data, int size)
1068
<para>This is used to send data to an ioslave. It is used in conjunction with
1069
the <literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::put(..)</literal></primary></indexterm>KIOJob::put(..)</literal> operation. It is almost always called from
1070
your object's <literal remap="tt">slotReady()</literal> slot as you must wait for the
1071
<literal remap="tt"><indexterm remap="cdx"><primary><literal>sigReady(int)</literal></primary></indexterm>sigReady(int)</literal> signal before sending any data. If your data is
1072
greater than 2048 bytes, then you must break it up into many chunks and
1073
send each chunk individually.</para>
1075
<para>Parameters:</para>
1077
<para>void *data - Your data that needs to go to the ioslave. This should be no
1078
more than 2048 bytes.
1079
int size - The size of this data</para>
1082
<sect2 id="dataend">
1086
<para>This is used along with <literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::data(..)</literal></primary></indexterm>KIOJob::data(..)</literal> and
1087
<literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::put(..)</literal></primary></indexterm>KIOJob::put(..)</literal>. It signals the ioslave that you are done
1088
sending it data. If you do not send this signal, then the ioslave will
1089
essentially hang. You do not need to use this if you are using
1090
<literal remap="tt"><indexterm remap="cdx"><primary><literal>KIOJob::get(..)</literal></primary></indexterm>KIOJob::get(..)</literal>.</para>
1092
<para>Parameters:</para>
1098
<sect1 id="kiojob-signals">
1099
<title>KIOJob Signals
1102
<para>All communication from the ioslaves come through KIOJob in the form of
1103
signals. There are quite a few of them (see <literal remap="tt"><indexterm remap="cdx"><primary><literal>kio&_;job.h</literal></primary></indexterm>kio&_;job.h</literal> for a complete
1104
listing), but I'll only discuss the "essential" ones.</para>
1106
<sect2 id="sigerrorint-id-int-errid-const-char-text">
1107
<title>sigError(int id, int errid, const char* text)
1110
<para>This signal is emitted whenever an error occurs. You should always connect a
1111
slot to this signal unless you really don't care if there is an error or not.</para>
1113
<para>Parameters:</para>
1115
<para>int id - The job id
1116
int errid - The error code. This corresponds to the list of errors
1117
defined in kio&_;interface.h
1118
const char* text - A textual description of the error</para>
1121
<sect2 id="sigreadyint-id">
1122
<title>sigReady(int id)
1125
<para><indexterm remap="ncdx"><primary><literal>sigReady()</literal></primary></indexterm>
1126
This signal occurs when the ioslave is ready to accept data. If you are
1127
using only <literal remap="tt"><indexterm remap="cdx"><primary><literal>get(..)</literal></primary></indexterm>get(..)</literal> methods, then you should not have to connect to this
1128
signal. If you are using a <literal remap="tt"><indexterm remap="cdx"><primary><literal>put(..)</literal></primary></indexterm>put(..)</literal> method, then you must connect to this
1129
signal and begin sending data from there.</para>
1131
<para>Parameters:</para>
1133
<para>int id - The job id</para>
1136
<sect2 id="sigdataint-id-const-char-data-int-size">
1137
<title>sigData(int id, const char *data, int size)
1140
<para><indexterm remap="ncdx"><primary><literal>sigData()</literal></primary></indexterm>
1141
This signal happens whenever the ioslave is sending you data. This is
1142
typically the data that it just downloaded. It will never be more than 2048
1143
bytes, so plan on having it called several times. You are responsible for
1144
collecting all of the data. You will know that the ioslave is done sending
1145
you data when you get the <literal remap="tt"><indexterm remap="cdx"><primary><literal>sigDataEnd(int)</literal></primary></indexterm>sigDataEnd(int)</literal> signal.</para>
1147
<para>Parameters:</para>
1149
<para>int id - The job id
1150
const char *data - The data that the ioslave just downloaded
1151
int size - The size of this data chunk</para>
1154
<sect2 id="sigdataendint-id">
1155
<title>sigDataEnd(int id)
1158
<para><indexterm remap="ncdx"><primary><literal>sigDataEnd()</literal></primary></indexterm>
1159
This signal is sent to signify that the ioslave is done sending you data.
1160
You should use this signal as an assurance that you can use the data as
1161
<literal remap="tt"><indexterm remap="cdx"><primary><literal>sigData(..)</literal></primary></indexterm>sigData(..)</literal> will never again be called.</para>
1163
<para>Parameters:</para>
1165
<para>int id - The job id</para>
1168
<sect2 id="sigfinishedint-id">
1169
<title>sigFinished(int id)
1172
<para><indexterm remap="ncdx"><primary><literal>sigFinished()</literal></primary></indexterm>
1173
This signal indicates the the ioslave is completely done.</para>
1175
<para>Parameters:</para>
1177
<para>int id - The job id</para>
1182
<chapter id="komop">
1183
<title>KDE KOM/Open Parts</title>
1185
<para>Torben Weis <literal remap="tt">weis@kde.org</literal>, Bernd Wuebben <literal remap="tt">wuebben@kde.org</literal></para>
1187
<para>v 1.0 August 1998</para>
1189
<para><emphasis>A free Object Model for Unix</emphasis></para>
1191
<sect1 id="introduction-1">
1192
<title>Introduction</title>
1194
<para>Although it is nice to have applications like StarOffice and
1195
ApplixWare available for Unix/Linux, it is a sad fact that they do not
1196
interact with other applications. In fact user is expected to use the
1197
supplied e-mail-client only, the StarOffice spreadsheet cannot be
1198
embedded into an Applix document, and users cannot use the WWW
1199
browser of their choice.</para>
1201
<para>Even a rather simple component-based approach like COM (Component
1202
Object Model) can do lots of magic. Take a glimpse into Bill Gates'
1203
world to convince yourself. The spread sheet of one software house can
1204
be used in a word processor of another and many applications support
1205
scripting interfaces. A veritable industry of OCX/ActiveX component
1206
writers has cropped up. Using easy to learn languages such as Visual
1207
Basic, users with a minimal programming background can glue separate
1208
components together with ease in order to create new applications
1209
exhibiting previously unavailable functionality. As Aristotle put it:
1210
The whole is more than the sum of its parts.</para>
1212
<para>Even the most faithful of all Unix supporters had to recognize that
1213
the Unix community had technologically fallen far behind the windows as
1214
well as Macintosh worlds with regard to GUI and desktop technologies.
1215
Fortunately, distributed objects make sense beyond a the realm of
1216
desktop and GUI applications. The development of distributed databases
1217
may serve as an example and component technology in general fits
1218
nicely into the strategy of major software companies which in turn
1219
helped to push CORBA development on the UNIX platform. Consequently,
1220
there is a standardized, network transparent, platform- and
1221
language-independent solution to the IPC-problem available, that is
1222
based on an object-oriented approach and that offers exception
1223
handling as well as support for management of complex data structures.</para>
1225
<para>While initially only available commercially, free implementations of
1226
the CORBA 2.0 standard object request broker (ORB) became available as
1227
well. A particularly well done free implementation of the CORBA
1228
standard, that will soon cover the full CORBA-2.1 standard, was
1229
developed at the university of Frankfurt, Germany. This GNU GPL'd ORB
1230
named MICO, can compete with commercial implementations with respect to
1231
completeness and stability.</para>
1234
<sect1 id="corba-based-kde-object-model">
1235
<title>CORBA-based KDE Object Model</title>
1237
<para>However, CORBA alone is not enough, as the standard only describes how
1238
distributed objects communicate; the COSS (CORBA Standard Services)
1239
define interfaces for a whole range of so called services, such as
1240
trading services, security services, transactions sercies and license
1241
management services and others. As is apparent, desktop development or
1242
even GUI application development did not play an important role when
1243
designing CORBA. The nearly indispensable event service does not
1244
support event filtering, furthermore it lacks a mechanism for so
1245
called 'callbacks'. Thus, in order for X11 and CORBA to work well
1246
together, CORBA�s well done industry standard object model had to be
1247
enhanced in order to be suitable as the underlying distributed object
1248
broker on which to build the all important compound document
1249
framework. Of course all this had to be undertaking within the limits
1250
of the accepted CORBA industry standards.</para>
1252
<para>The KDE Object Model (KOM) addresses these issues and makes life
1253
easier for a programmer by automatically giving each object a base set
1254
of functionalities. This includes first and foremost event
1255
handling. Each KOM object is capable of receiving events. An event
1256
consists of an arbitrary data structure (<literal remap="tt">CORBA::Any</literal>) as well
1257
as a string, describing the type of the event, for example
1258
Desktop/Font/ChangeFont or Desktop/Color. By reading this string, an
1259
object can decide whether it is interested in that event, and will
1260
know how the unknown data structure is to be interpreted semantically.</para>
1263
<sect1 id="flexibility-with-events-and-filters">
1264
<title>Flexibility with events and filters</title>
1266
<para>An important aspect when processing events is filtering. It allows the
1267
developer to enhance the functionality of a program without having to
1268
change the sources. There are three types of filters: those which
1269
merely recognize events, those which are allowed to change or discard
1270
events, and finally those which finally process them. This model can
1271
be illustrated with a simple WWW browser example: If a program wants
1272
the browser to open a new URL, it has to send it an event. To enhance
1273
the browser with a history function and the user only has to plug in a
1274
filter of the first category into the browser. This filter can record
1275
all URLs, thereby managing a history function. A tool for blocking
1276
certain pages (in order to protect minors for example) belongs to
1277
category two: If the URL is rated unsuitable for minors, the filter
1278
discards the event or replaces the URL in it with a different one. If
1279
the Browser does not support mailto, we need a third category filter:
1280
upon arrival of a URLOpen event with mailto:joe@doe in it, the event
1281
is discarded from the browser's point of view, but the filter offers
1282
an alternative implementation.</para>
1284
<para>The filter principle is of great importance, as in CORBA only
1285
interfaces are inherited, not implementations. It would not be
1286
possible to derive from the browser object and to just overload the
1287
function that opens a new URL. The event model does not just solve
1288
this problem, it enables developers to install several enhancements at
1289
the same time. A second filter, filtering FTP URLs for example, can be
1290
easily installed in addition. It is important that an user can plug-in
1291
an arbitrary number of such filters at run-time. A filter is installed
1295
KOM::EventTypeSeq types;
1299
types [0] = CORBA::string_dup ("OpenURL");
1301
browser->installEventFilter ( this, "eventFilter", types);
1307
<para>Now, all you have to do is wait for events:</para>
1310
boolean MailFilter::eventFilter (in Object obj, in EventType type, in any value)
1313
if ( type == "OpenURL" )
1318
if (( value >>=p ) && strcmp (type, "mailto:", 7) == 0)
1323
CORBA::string_free (p);
1337
<para>When a user enters a URL in the example above, the browser sends an
1338
event to itself. This concept can also serve for a macro recorder,
1339
because events can be filtered, saved and re-send later. As event
1340
handling works the same way for all KOM objects, there is now - at
1341
last - the possibility of creating a supra-component macro recording.</para>
1343
<para>To avoid performance loss, filters can be installed in a way that they
1344
only receive events whose type matches a certain
1345
expression. Desktop/Font/* would filter all events that have to do
1346
with the font settings of the whole desktop.</para>
1349
<sect1 id="callbacks-with-signal-and-slots">
1350
<title>Callbacks with signal and slots</title>
1352
<para>In an event-driven environment, programmers have to deal with so
1353
called callbacks. A callback is a mechanism by which a button for
1354
example activates a procedure that is supposed to be called once the
1355
button is pressed. C offers pointers to functions for that, under C++
1356
we can use elegant signals and slots. A wonderful implementation of
1357
this idea is offered by the QT toolkit. KOM offers this technique for
1358
distributed objects as well, it uses CORBA�s DII (Dynamic Invocation
1359
Interface) for that purpose. An object can be target and sender of
1360
signals at the same time. To receive a signal, an object must have a
1361
slot with a matching list of parameters. Such a slot is not different
1362
from a usual CORBA method without return value. The lines</para>
1365
MySender_var s = new MySender;
1367
MyReceiver_var r = new MyReceiver;
1369
r.connect ( "selected", s, "myslot" );
1375
<para>connect two objects with each other. As soon as <literal remap="tt">s</literal> emits the
1376
selected signal, the function myslot of object <literal remap="tt">r</literal> is
1377
called. If one of the objects is destroyed, the connection between the
1378
two is released automatically. It is possible to connect one signal to
1379
different slots and one slot to different signals. Theoretically, it
1380
would also be possible to work with events here. Signals and slots
1381
however work a lot faster and are easier to handle for the programmer,
1382
because he/she does not have to deal with event
1383
processing. Furthermore they are type-safe. On the other hand, you
1384
have to work without the advantages of filtering.</para>
1386
<para>As already mentioned, interface inheritance does not solve all
1387
problems. The browser example shows that installing multiple
1388
enhancements at run-time works only because filters are loaded which
1389
can plug into the browser. The principle behind this mechanism is
1390
called dynamic aggregation. You take a core object (the browser) and
1391
enhance it by other objects (plug-ins). The interface of the browser
1392
is expanded with the sum of the plug-ins' interfaces. KOM support
1393
run-time installation and uninstallation of those plug-ins. Neither is
1394
required to run within the same process or even the same computer.</para>
1396
<para>An object that communicates with the browser does not notice which
1397
interface was implemented by the core object and which by the
1398
plug-ins. If a client wants to know whether a component supports a
1399
special interface, a simple</para>
1402
CORBA::Object_var obj = browser->getInterface ('IDL:/foo/bar:1.0');
1408
<para>is enough to get a reference to that interface. It is even possible to
1409
load the plug-in with the required interface at run-time. This saves a
1410
lot of memory, because the plug-ins allocate resources only then when
1411
they are really needed.</para>
1414
<sect1 id="openparts-kom-meets-gui">
1415
<title>OpenParts: KOM meets GUI</title>
1417
<para>Until now, the word GUI has not been mentioned a single time. Indeed,
1418
KOM is solely based on CORBA. There are in effect quite a number of
1419
applications which do not have or do not need a GUI. It would not make
1420
sense to burden those applications with GUI code; we better leave that
1421
to the supporters of the Redmond doctrine. OpenParts form a layer on
1422
top of CORBA, KOM, and X11. Embedding GUI components in own programs
1423
has become widely known since introduction of MS Internet Explorer
1424
4.0. In the windows world, a lot of controls have been created, a
1425
whole industry has formed around the creation of controls and nearly
1426
everything, from a simple push-button to a complete WWW browser, can
1427
be realized as a control.</para>
1429
<para>The idea behind controls is actualized in KDE's OpenParts. This is
1430
done using window objects that export a well-defined interface. The
1431
CORBA Implementation Repository registers the implementation of those
1434
<para>When an application needs a specific control, it relays a request to
1435
the repository. In the OpenParts framework, separate server processes
1436
handle these requests. Thus, a high level of toolkit, compiler,
1437
language and multi threading-support independence is achieved. The
1438
repository returns a reference to a factory. CORBA does not support
1439
the creation of new objects with a special construct. Because of that,
1440
factories have been introduced, which serve the purpose of creating a
1441
new object and returning a reference to it.</para>
1443
<para>The actual embedding is done via X11 swallowing. The element that is
1444
to be embedded (a X11 window) is assigned a new parent using the X11
1445
Xlib call <literal remap="tt">XReparentWindow</literal>. In order to keep developers away
1446
from messing around with pure X11, there exist so called control
1447
frames. This class depends on the used toolkit and (viewed from
1448
outside) looks like a normal window implemented using a specific GUI
1449
toolkit. The control frame is made the new father of the control. Is
1450
it moved or resized, the control is moved or resized as well.</para>
1453
<sect1 id="dynamic-elements-realized-easily">
1454
<title>Dynamic Elements realized easily</title>
1456
<para>Some elements of a window are subject to restrictions. There can only
1457
be one menu bar as well as one status bar. Great confusion would ensue
1458
if controls were allowed to take control of these restricted
1459
elements. One way to avoid this confusion is offered by an enhancement
1460
of controls: Parts. A part can be in three different modes: inactive,
1461
marked, or active. In a top-level window only one can be active. This
1462
part gains control over the restricted elements. The top-level window
1463
is called PartShell; it owns menu bar, tool bars, status bar etc. Each
1464
part can register its menus and toolbars with the Shell. The Shell,
1465
however, only displays the restricted elements of the active Part.</para>
1467
<para>Using Parts, one can build the basic structure of an integrated office
1468
suite. Text processing, spread sheet, drawing application and all the
1469
rest is put into such structures. As Parts can contain Parts, a
1470
spread-sheet Part can be embedded into a text-Part with no
1471
problems. Instead of ControlFrames, the developer can use the mightier
1472
PartFrames as well. A single click on a part creates a window frame,
1473
the user can move and resize the frame now; another click makes it
1474
active. The window frame is changed automatically to show the user,
1475
that the part has been made active. The Shell changes menu bar and
1476
tool bar to the needs of the Part that has become active.</para>
1478
<para>What is missing is a common file menu: it is the Shell's privilege to
1479
provide a menu and a toolbar of its own for that purpose. Via these
1480
widgets, the user can access the document as a whole, for example to
1481
save or print it.</para>
1484
<sect1 id="the-document-view-architecture">
1485
<title>The Document View Architecture</title>
1487
<para>OpenParts support the Document View Model, known from Smalltalk and
1488
popularized in Microsoft's MFC. A view displays the document on the
1489
screen and is derived from the Parts class. The document contains data
1490
as well as the associated algorithms. The advantage of this solution is
1491
that users can have several views of the document. It is, for example,
1492
possible to display two paragraphs of a longer article in two windows
1493
or to display an image in a separate window when manipulating it. When
1494
zooming in on this picture, the rest of the document does not have to
1495
be enlarged as well.</para>
1497
<para>For reasons of performance, document and view run within the same
1498
process. In order to achieve a clean design, the developer has to
1499
strictly follow the principle of separating data and belonging
1500
manipulating algorithms on one side and viewing algorithms on the
1501
other side. Every user action first affects the view. This view must
1502
then signal the Document to change the data basis accordingly. After
1503
that, the Document must inform all views to update their windows
1504
in order to correctly reflect the new data state.</para>
1506
<para>An important aspect is using a Document without a View. This allows to
1507
make use of an office suite's functionality in a batch job, for
1508
example. The Document should export methods for manipulating data. A
1509
CORBA-aware scripting language could make use of those methods. At
1510
this time, CORBA-binding for Perl, Tcl, and CORBA-Script exist, a
1511
Python binding is being worked on.</para>
1513
<para>Object models, and operating systems are alike in that they are of
1514
mere academic value as long as there are no applications making use of
1515
their qualities. KOffice is, at the moment, the largest and most
1516
widely known application using OpenParts technology. As the KDE
1517
project makes wider use of CORBA, and KOM and OpenParts respectively,
1518
there is reason to hope that Unix will soon have a free implementation
1519
of a object model that transfers the advantages of contemporary
1520
compound document framework technology to the user.</para>
1523
<sect1 id="using-openparts-koffice">
1524
<title>Using OpenParts: KOffice</title>
1526
<para>Based on OpenParts technology, the KOffice project aims at offering a
1527
free and easily extendible office suite for KDE.</para>
1529
<para>The 'mother' of all KOffice components (called Parts) is the spread
1530
sheet KSpread. Although officially still declared 'alpha', it is
1531
already working very well.. Its mathematical functions can be easily
1532
enhanced by means of an embedded Python language interpreter.</para>
1534
<para>KPresenter is a presentation application written by Reginald
1535
Stadlbauer, which convincingly demonstrated its usability at the Linux
1536
Congress in Cologne where a talk about KDE was given using
1537
KPresenter. In the future, Linus Torvalds will no longer have use
1538
Windows applications when giving presentations.</para>
1540
<para>KChart is an application to create diagrams. It supports different
1541
modes (bars, lines, etc.) and can be embedded into other KOffice
1542
application without problems. When data is changed in, for example,
1543
KSpread, the chart automatically changes itself accordingly.</para>
1545
<para>There is a component for displaying graphics, and work is being done
1546
adapting a formula editor and a vector-oriented painting application
1547
(KIllustrator). For the future, adaptation of KLyx is planned to embed
1548
Parts in LaTeX documents. Other KDE applications like KOrganizer,
1549
KAddressbook and KMail will be enhanced with CORBA interfaces to
1550
provide seamless integration in the KOffice suite.</para>
1552
<para>If possible, components save their data in XML format. To save an
1553
aggregate document in a file, the MIME multi-part format is used. XML
1554
and MIME multi-part share the advantage that import and exports filters
1555
can easily be written in scripting languages like Python and
1556
Perl. Ever since a WinWord filter attracted attention on
1557
c.o.l.a. (comp.os.linux.announce), developers began writing import
1558
filters for the most important MS applications.</para>
1560
<para>KOffice runs quite stably for a alpha release. To compile it, a fast
1561
CPU and a reasonable amount of RAM ( 64 MByte) should be available;
1562
for using KOffice, 32 MByte and a Pentium 133 MHz will
1563
suffice. KOffice is reported to work on DEC Alpha and Sun Sparcs as
1564
well. The sources for KOffice, KOM and OpenParts are available on
1565
<ulink url="http://www.kde.org">http://www.kde.org</ulink></para>
1568
<sect1 id="code-re-use-with-corba">
1569
<title>Code Re-use with CORBA</title>
1571
<para>A developer, sitting in front of his editor and trying to build new
1572
software components out of old ones, might sadly remember the good old
1573
Lego pieces from his/her childhood. Those always fit together nicely,
1574
and from a great number of primitive elements, great buildings could be
1575
constructed. From the software developer's point of view, software
1576
pieces do not fit at all, and each new building requires a lot of work
1577
to make it usable. Many developers therefore choose to rewrite the
1578
sources rather than to re-use code.</para>
1580
<para>Under Unix, the usual method concerning code re-use is putting code
1581
into libraries and linking the application against them. However,
1582
sometimes it happens that those libraries use different GUI toolkits,
1583
or that some support multi-threading and some do not. Additionally,
1584
all libraries should have been compiled with the same compiler,
1585
otherwise you will be subject to problems at the linking stage.</para>
1587
<para>One solution is to split an application into several processes. One
1588
process might, for example, offer database functionality with
1589
multi-threading, another one might offer the X11-GUI
1590
single-threaded. Now, the problem of Interprocess Communication (IPC)
1591
remains to be solved. CORBA (Common Object Request Broker
1592
Architecture) offers a modern and object-oriented solution, but the
1593
developer is tied to the CORBA object model, what is somewhat limited
1594
in contrast to the C++, Python or Smalltalk object model. First of all
1595
one can derive only from interfaces, not from implementations. If
1596
there is a text editor as a CORBA object, it usually is impossible to
1597
derive from this editor and overload just a few of its functions. The
1598
derivation of implementations works only if the sources of the editor
1599
are available, or if it is available as a library. But that was what
1600
we wanted to avoid.</para>
1602
<para>As the main article describes, the KDE Object Model (KOM) offers a
1603
solution for this problem; it is based on events and event
1604
filters. Instead of calling a function directly, it is possible to
1605
send an event. By filtering events, function overloading can be
1608
<para>There are other obstacles when re-using code: According to Murphy's
1609
laws, the desperately needed module is always written in a different
1610
programming language than expected. Mixing different languages in one
1611
application is always a problem for programmers. Even semi-automatic
1612
wrapper generators like SWIG expect a certain amount of refining from
1613
the programmer. Further, a look at the KDE bindings in Python, Perl
1614
and Tcl shows that this wrapper code can easily grow huge. As
1615
OpenParts is CORBA-based, objects can be implemented in any of the
1616
languages for which CORBA bindings are available for. For interpreter
1617
languages, in most cases no special wrapper code is necessary, for
1618
compiler languages like C/C++, wrapper code generation is done
1619
automatically.</para>
1622
<sect1 id="credits">
1623
<title>Credits</title>
1625
<para>Most of this document was written by Torben Weis
1626
<ulink url="email:weis@kde.org">weis@kde.org</ulink>.
1627
Additions, corrections as well as the editorial work was done by
1628
Bernd Johannes Wuebben <ulink url="email:wuebben@kde.org">wuebben@kde.org</ulink>.</para>
1632
<chapter id="komhowto">
1633
<title>Using KOM / OpenParts HOWTO</title>
1635
<para>Simon Hausmann <ulink url="mailto:hausmann@kde.org"><hausmann@kde.org></ulink></para>
1637
<para>v1.0 18, June 1999</para>
1639
<para><emphasis>This documentation is meant to help programmers who are already familiar
1640
with the standard Qt/KDE application framework and who are interested in using
1641
the KDE component technology, the KDE Object Model (KOM) and OpenParts, for
1642
their application. It covers both "why" you should use KOM/OP
1643
and "how" to do so.</emphasis></para>
1645
<sect1 id="introduction-2">
1646
<title>Introduction</title>
1648
<para>This documentation is meant to help programmers who are already familiar with
1649
the standard Qt/KDE application framework and who are interested in using the
1650
KDE component technology, the KDE Object Model (KOM) and OpenParts, for their
1651
application. The goals of using components in case of standard KDE
1652
applications might be:</para>
1654
<para><itemizedlist>
1656
<para>make several modules of the application re-usable components, being
1657
available for other applications, not matter in what language they are
1658
written or on what platform/machine they're running.</para>
1661
<para>make use of OpenPart's embedding facility and its way to manage shared
1662
GUI elements to provide seamless graphical integration of components in
1663
applications.</para>
1666
<para>use CORBA and KOM as an easy way of inter-process communication</para>
1671
<para>I recommend reading the
1672
<ulink url="http://developer.kde.org/openparts/html/openparts.html">article by Torben Weis about KOM/Openparts</ulink>
1673
<ulink url="mailto:weis@kde.org">Torben Weis</ulink> is the
1674
author/creator/master/god of KOM/OpenParts.</para>
1677
<sect1 id="the-kde-object-model-kom">
1678
<title>The KDE Object Model (KOM)</title>
1680
<sect2 id="first-ways-of-communication-the-kombase-inte">
1681
<title>First ways of communication - the KOM::Base interface <indexterm remap="idx"><primary>KOM::Base interface</primary></indexterm></title>
1683
<para>The Base interface and its implementation in <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkom</literal></primary></indexterm>libkom</literal> provide the basic
1684
functionality for a standardized communication between CORBA objects using
1685
KOM. This includes</para>
1687
<para><itemizedlist>
1689
<para>signals and slots, similar to the mechanism used in the Qt toolkit</para>
1692
<para>event handling, including filtering</para>
1695
<para>relatives management</para>
1698
<para>reference counting</para>
1704
<sect2 id="signals-and-slots-signals-and-slots">
1705
<title>Signals and Slots <indexterm remap="idx"><primary>Signals and Slots</primary></indexterm></title>
1707
<para>KOM supports signals and slots just like in the Qt toolkit, with a few
1708
differences in usage and implementation. The first and biggest difference is
1709
that signals and slots are no more typesafe again, meaning there's no moc
1710
compiler generating meta data for KOM signals/slots to enable type checking at
1711
run-time, when connecting.</para>
1713
<para>Another difference is the way you declare signal and slot functions. Signals
1714
have to be declared with the <literal remap="tt"><indexterm remap="cdx"><primary><literal>SIGNAL&_;IMPL</literal></primary></indexterm>SIGNAL&_;IMPL</literal> macro from <literal remap="tt"><indexterm remap="cdx"><primary><literal>komBase.h</literal></primary></indexterm>komBase.h</literal>,
1715
without specifying any signal arguments. Slot methods have to be defined in
1716
your CORBA interface description.</para>
1718
<para>For KOM signals the equivalent to the "emit" keyword from Qt is the
1719
<literal remap="tt"><indexterm remap="cdx"><primary><literal>SIGNAL&_;CALL</literal></primary></indexterm>SIGNAL&_;CALLx</literal> macro, were "x" is one of 0, 1, 2, depending on the
1720
number of arguments.
1721
<indexterm><primary>KOM::Base</primary></indexterm>
1724
<para>In your CORBA interface description:
1725
<programlisting> #include &<;kom.idl&>;
1727
interface FooSender : KOM::Base
1729
signal void mySignal( in long foobaz );
1732
interface FooReceiver : KOM::Base
1734
slot void mySlot( in long gosh );
1738
<para>In the implementation of FooSender:
1739
<programlisting> FooSender_Impl::FooSender_Impl( ... )
1742
SIGNAL_IMPL( "mySignal" );
1746
FooSender_Impl::mySignal( CORBA::Long foobaz )
1748
SIGNAL_CALL1( "mySignal", foobaz );
1752
<para>In the implementation of FooReceiver:
1753
<programlisting> FooReceiver_Impl::mySlot( CORBA::Long gosh )
1759
<para>First some words about the sender: It is not required to define the signal
1760
in the interface description and to provide an implementation which simply
1761
emits the signal. However in many cases this is recommended, because this makes
1762
it easier for other developers to use your interface because they aren't required
1763
to seek in the implementation sources just to find out about the signals this
1764
object emits. Another way is to simply document the existence of the signal
1765
in the interface description, without defining a method. From the technical
1766
point only the <literal remap="tt"><indexterm remap="cdx"><primary><literal>SIGNAL&_;CALL</literal></primary></indexterm>SIGNAL&_;CALLx</literal> macro counts when emitting the signal.</para>
1768
<para>What's left is connecting and disconnecting. In the above described example it
1770
<programlisting> ...
1771
SenderObject->connect( "mySignal", ReceiverObject, "mySlot" );
1773
SenderObject->disconnect( "mySignal", ReceiverObject", "mySlot");</programlisting>
1776
<para>Well, this is quite self-explaining I think. Just make sure to always disconnect
1777
from your object upon destruction.</para>
1781
<title>Events</title>
1783
<para>An event consists of two elements, the event name, being a string, and an
1784
event argument, being a CORBA::Any value and therefore freely choosable by the
1787
<para>Events, sent to a specified object, can be imagined as being put through a
1788
pipe until they reach the destination object. This "pipe" is filled with
1789
installed event filters. There are three kinds of filters.
1792
<para>reading filters ( <literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;READ</literal></primary></indexterm>FM&_;READ</literal> )</para>
1795
<para>writing filters ( <literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;WRITE</literal></primary></indexterm>FM&_;WRITE</literal> )</para>
1798
<para>implementing filters ( <literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;IMPLEMENT</literal></primary></indexterm>FM&_;IMPLEMENT</literal> )</para>
1803
<para>In the current implementation in KOM these filter modes only specify the order
1804
how the event is processed. When an event is emitted it gets first filtered by
1805
all event filters with the filter mode <literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;WRITE</literal></primary></indexterm>FM&_;WRITE</literal>, then followed by
1806
<literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;IMPLEMENT</literal></primary></indexterm>FM&_;IMPLEMENT</literal> and finally by <literal remap="tt"><indexterm remap="cdx"><primary><literal>FM&_;READ</literal></primary></indexterm>FM&_;READ</literal>. Event filters have two
1807
possibilities what they can do with the actual event: They can just
1808
<emphasis remap="bf">read</emphasis> it or they can <emphasis remap="bf">discard</emphasis> it, which means the event is
1809
discarded and will never receive its destination object.</para>
1811
<para>The actual event name has a special meaning in regard to event filters. When
1812
installing an event filter to an object you have to specify, beside a
1813
reference to the filter object and the name of the filter mapping function, a
1814
sequence of so called event type patterns. An event type pattern can be the
1815
name of a single event as well as a special pattern (see <literal remap="tt"><indexterm remap="cdx"><primary><literal>kom.idl</literal></primary></indexterm>kom.idl</literal> for more
1816
information about event type patterns) .</para>
1818
<para>When an event is meant to be processed by a filter, the specified filter
1819
function gets called, with the event name and the event value as arguments.
1820
This filter function has to return (through a boolean value) whether the event
1821
should be discarded or not.</para>
1823
<para>When all filtering is done and none of the installed filters discarded the
1824
event, it is finally received by the destination object, by calling the
1825
object's <literal remap="tt"><indexterm remap="cdx"><primary><literal>event()</literal></primary></indexterm>event()</literal> method, defined in the KOM::Base <indexterm remap="idx"><primary>KOM::Base</primary></indexterm> interface. The default
1826
implementation does actually nothing, so you may want to re-implement this
1827
virtual function.</para>
1829
<para>The very low-level usage of events is to call the receive/receiveASync methods
1830
of an object for sending an event and to re-implement <indexterm remap="cdx"><primary><literal>KOMBase::event</literal></primary></indexterm>KOMBase::event for
1831
mapping an event. But KOM provides some nice macros which simplify the
1832
processing of events.</para>
1834
<sect3 id="sending-events">
1835
<title>Sending Events</title>
1837
<para>For sending komBase.h defines some useful <literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT</literal></primary></indexterm>EMIT&_;EVENT</literal> macros, all
1838
using the same syntax:
1839
<literal remap="verb">EMIT_EVENT_x( destination_object, event_name, event_argument)</literal></para>
1841
<para>"destination&_;object" is a reference to the object which is meant to
1842
receive/process the event. The event will be filtered through all event
1843
filters which are installed in this destination object. "event&_;name" is
1844
self-explaining ;-) . The event argument depends on the specific macro, which
1845
are in particular:</para>
1847
<para><itemizedlist>
1849
<para><literal remap="tt">EMIT&_;EVENT</literal>, the general macro for sending. The event argument is
1850
required to have a <literal remap="tt"><<=</literal> operator for CORBA::Any defined. You
1851
will want to use this macro whenever the event argument is a structure
1852
for example. (and don't forget to compile your idl file with the "--any"
1853
option, so that the idl compiler generates the necessary operator
1857
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;BOOLEAN</literal></primary></indexterm>EMIT&_;EVENT&_;BOOLEAN</literal>, useful for boolean event arguments. The
1858
only difference to the <literal remap="tt">EMIT&_;EVENT</literal> macro is that it uses
1859
CORBA::Any::from&_;boolean for you to convert the boolean value. So it
1860
doesn't really matter whether you use:
1862
<literal remap="verb"> EMIT_EVENT( receiver, name, CORBA::Any::from_boolean( value ) );</literal>
1864
<literal remap="verb"> EMIT_EVENT_BOOLEAN( receiver, name, value );</literal>
1868
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;OCTET</literal></primary></indexterm>EMIT&_;EVENT&_;OCTET</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for
1869
<indexterm remap="cdx"><primary><literal>CORBA::Octet</literal></primary></indexterm>CORBA::Octet values.</para>
1872
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;CHAR</literal></primary></indexterm>EMIT&_;EVENT&_;CHAR</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for char
1873
(<indexterm remap="cdx"><primary><literal>CORBA::Char</literal></primary></indexterm>CORBA::Char) values.</para>
1876
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;WCHAR</literal></primary></indexterm>EMIT&_;EVENT&_;WCHAR</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for
1877
<indexterm remap="cdx"><primary><literal>CORBA::WChar</literal></primary></indexterm>CORBA::WChar values.</para>
1880
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;STRING</literal></primary></indexterm>EMIT&_;EVENT&_;STRING</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for
1881
char * (<indexterm remap="cdx"><primary><literal>CORBA::Char*</literal></primary></indexterm>CORBA::Char*) values.</para>
1884
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;WSTRING</literal></primary></indexterm>EMIT&_;EVENT&_;WSTRING</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for
1885
<indexterm remap="cdx"><primary><literal>CORBA::WChar*</literal></primary></indexterm>CORBA::WChar* values.</para>
1888
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>EMIT&_;EVENT&_;OBJECT</literal></primary></indexterm>EMIT&_;EVENT&_;OBJECT</literal>, similar to EMIT&_;EVENT&_;BOOLEAN, useable for
1889
CORBA objects (<indexterm remap="cdx"><primary><literal>CORBA::Object</literal></primary></indexterm>CORBA::Object).</para>
1895
<sect3 id="receiving-events">
1896
<title>Receiving Events</title>
1898
<para>The process of receiving events is a little bit more difficult, compared
1899
to sending, since we have to process all kinds of events an object can receive
1900
in one handler method, KOM::Base <indexterm remap="idx"><primary>KOM::Base</primary></indexterm>::event (IDL <indexterm remap="idx"><primary>IDL</primary></indexterm>) / KOMBase::event (C++) . Just
1901
like with sending events you can again do everything on low CORBA level, but
1902
why should we go the hard way? KOM again provides very nice and easy-to-use
1903
macros for this (defined in komBase.h) :-) . Usually all this looks like the
1904
following example:<indexterm><primary>KOM::Base</primary></indexterm>
1905
<programlisting>#include &<;kom.idl&>;
1909
// we say: the event argument is a string
1910
const string eventFirstFoo = "MyFooEventNameOrWhateverYouNameIt";
1917
const string eventSecondFoo = "Blaafooo";
1918
typedef MyStruct EventSecondFoo;
1920
interface SomethingElse
1925
const string eventThirdFoo = "KOMIsCool";
1926
typedef SomethingElse EventThirdFoo;
1928
interface Foo : KOM::Base
1935
bool FooImpl::event( const char *event, const CORBA::Any &&;value )
1937
EVENT_MAPPER( event, value );
1939
MAPPING_STRING( MyModule::eventFirstFoo, mappingFirstFoo );
1941
MAPPING( MyModule::eventSecondFoo, MyModule::EventSecondFoo, mappingSecondFoo );
1943
MAPPING( MyModule::eventThirdFoo, MyModule::EventThirdFoo_ptr, mappingThirdFoo );
1945
END_EVENT_MAPPER; //the macro executes "return false;" for us, to indicate that
1946
//we did not handle the event if we reach this point
1949
bool FooImpl::mappingFirstFoo( const char *myArgument )
1952
//don't forget to return with a boolean value, indicating whether you sucessfully
1953
//processed the event or not.
1956
bool FooImpl::mappingSecondFoo( MyModule::MyString anotherArg )
1961
bool FooImpl::mappingThirdFoo( MyModule::SomethingElse_ptr whaaboo )
1968
<para>As you can see an event handler usually begins with the <literal remap="tt">EVENT&_;MAPPER</literal>
1969
macro and ends with <literal remap="tt">END&_;EVENT&_;MAPPER</literal> . Similar to the
1970
<literal remap="tt">EMIT&_;EVENT&_;x</literal> macros, the <literal remap="tt">MAPPING</literal> macros consist of a general
1971
<literal remap="tt">MAPPING</literal> macro and the following friends:
1974
<para><literal remap="tt">MAPPING&_;BOOLEAN</literal></para>
1977
<para><literal remap="tt">MAPPING&_;OCTET</literal></para>
1980
<para><literal remap="tt">MAPPING&_;CHAR</literal></para>
1983
<para><literal remap="tt">MAPPING&_;WCHAR</literal></para>
1986
<para><literal remap="tt">MAPPING&_;STRING</literal></para>
1989
<para><literal remap="tt">MAPPING&_;WSTRING</literal></para>
1992
<para><literal remap="tt">MAPPING&_;OBJECT</literal></para>
1997
<para>In order to structurize the process of event handling a little bit, every
1998
event gets its own event handling function. These functions are called by the
1999
mapping macros (last argument) . The above used naming scheme is not a
2000
requirement, however it is used in most applications using KOM.</para>
2004
<sect2 id="adopting">
2005
<title>Adopting</title>
2007
<para>You should use adopting whenever you want to hold a reference to an object and
2008
want to be informed when the object dies in order to free all your references
2009
to this object. But this should only be used when you're not the parent
2010
object, meaning you didn't reference the object directly via the KOM reference
2011
counter. When using adopting you should re-implement the <literal remap="tt">leaveNotify</literal>
2012
(and perhaps <literal remap="tt">adoptNotify</literal>) methods of your object (and don't forget
2013
to call the original KOMBase method!) .</para>
2016
<sect2 id="kom-referencing">
2017
<title>KOM referencing</title>
2019
<para>KOM reference counting should be used to "express" that you possess the
2020
object. This gives you direct control over the lifecycle of the object by
2021
letting the reference counter act directly on the server object, in contrary
2022
to CORBA reference counting, where the reference counter only acts on the stub
2023
object, in case of remote objects (this is different for local objects, where
2024
stub = server object) . When the KOM reference counter drops down to zero the
2025
object gets destroyed. This destruction is done by calling <literal remap="tt">cleanUp()</literal>,
2026
which closes all connections to other objects and leaves all relatives. After
2027
this call is finished the object truly gets released. You might want to
2028
re-implement the <literal remap="tt">cleanUp()</literal> method. In this case make sure that you
2029
don't forget two things:</para>
2031
<para><itemizedlist>
2033
<para>only execute if the boolean variable <literal remap="tt">m&_;bIsClean</literal> is false,
2034
otherwise simply return</para>
2037
<para>make sure you call the previous implementation!</para>
2042
<para>As a short summary to this KOM reference stuff just keep in mind, that
2043
there are three ways to hold a reference to an object:
2046
<para>you're connected to the object via signals/slots or via event filters</para>
2049
<para>you're the parent object, meaning you hold a reference through the KOM
2050
reference counter</para>
2053
<para>otherwise you should use adopting to get informed whenever the object wants
2054
to die, in order to free all references to the object which are not of
2055
one of the above kinds. The idea behind all this is that all
2056
connections/references between objects are symmetric, meaning
2057
<emphasis remap="bf">both</emphasis> sides know about the connection and <emphasis remap="bf">both</emphasis> sides
2058
clean up all connections between each other whenever one of the two
2059
objects wants to die. In case of signal/slot connections this is done
2060
automatically by KOM. In case of KOM reference counters you have the
2061
direct control over the lifecylcle for the object. Adopting, as third
2062
way, can be used to keep other connections symmetric, connections which
2063
are neither signal/slot connections nor direct references via the KOM
2064
reference counter.</para>
2069
<para>Hint: Using the <literal remap="tt">KOMVar</literal> template makes handling KOM references much
2070
easier, they can be used similar to the CORBA &_;var types.</para>
2073
<sect2 id="the-component-the-komcomponent-komcomponent-">
2074
<title>THE component - the KOM::Component <indexterm remap="idx"><primary>KOM::Component</primary></indexterm> interface</title>
2076
<para>The Component interface, being derived from the Base interface, additionally
2077
provides a kind of small interface repository for only this component,
2078
combined with the possibility to provide new interfaces by dynamic aggregation
2079
and a standard way to add plugin components. This gives CORBA objects the
2080
possibility to enhance their functionality at run-time.</para>
2082
<para>There are five kinds of interfaces:
2085
<para>Builtin Interfaces (derived Interfaces)</para>
2088
<para>Builtin Aggregate Interfaces</para>
2091
<para>Dynamic Aggregate Interfaces</para>
2094
<para>Builtin Plugin Interfaces</para>
2097
<para>Dynamic Plugin Interfaces</para>
2102
<para>Builtin interfaces are all interfaces the object directly implements. This
2103
means they are part of the actual object implementation and can be specified
2104
via the <literal remap="tt"><indexterm remap="cdx"><primary><literal>ADD&_;INTERFACE</literal></primary></indexterm>ADD&_;INTERFACE</literal> macro (in <indexterm remap="cdx"><primary><literal>komComponent.h</literal></primary></indexterm>komComponent.h) . So for example if
2105
your interface description looks like this:
2106
<programlisting>module Foo
2108
interface MyInterface : AnotherInterface
2115
<para>You should add the following line into the constructor of an implementation of
2117
<indexterm><primary>IDL</primary></indexterm>
2118
<programlisting>ConstructorNameOfMyInterface::ConstructorNameOfMyInterface( ... )
2121
ADD_INTERFACE( "IDL:Foo/MyInterface:1.0" );
2126
<para>This way you tell your component that it supports the interface
2127
"Foo/Interface" and therefore makes it available through the three functions
2128
<literal remap="tt">getInterface()</literal>, <literal remap="tt">interfaces()</literal> and
2129
<literal remap="tt">supportsInterface()</literal> .</para>
2132
<sect2 id="extend-your-component-by-aggregation-komaggr">
2133
<title>Extend your component by aggregation - KOM::Aggregate <indexterm remap="idx"><primary>KOM::Aggregate</primary></indexterm></title>
2135
<para>Aggregates solve a problem with distributed objects, the problem of
2136
derivation. Since the implementation of an interface is completely
2137
encapsulated there has to be another way to extend the functionality of an
2138
already existing object. By using aggregate components you can add new
2139
interfaces to an object, at run-time. This means you extend the functionality
2140
but you do not change the behaviour of the object itself.</para>
2142
<sect3 id="builtin-aggregates">
2143
<title>Builtin Aggregates</title>
2145
<para>Builtin aggregate interfaces are the interfaces of aggregate implementations
2146
which run in the same process as our component. See in komComponent.h the four
2147
functions of the <literal remap="tt"><indexterm remap="cdx"><primary><literal>KOMComponent</literal></primary></indexterm>KOMComponent</literal> class for adding builtin aggregates, it's easy.</para>
2150
<sect3 id="dynamic-aggregates">
2151
<title>Dynamic Aggregates</title>
2153
<para>Dynamic aggregates are similar to builtin aggregates, with two differences:</para>
2155
<para><itemizedlist>
2157
<para>They can (are) be installed from "outside" of the component,
2158
using AggregateFactories (see kom.idl <indexterm remap="idx"><primary>kom.idl</primary></indexterm>) . This way they do neither have
2159
to run within the same process nor on the same computer.</para>
2162
<para>They can depend on other available interfaces. KOM does the job of resolving
2163
these dependencies for you.</para>
2170
<sect2 id="plugins-the-komplugin-komplugin-interface">
2171
<title>Plugins - the KOM::Plugin <indexterm remap="idx"><primary>KOM::Plugin</primary></indexterm> interface</title>
2173
<para>Plugins are the kind of counterpart to aggregates. They do not extend the
2174
functionality of an object by providing new interfaces, but instead usually
2175
change the behaviour of it, by
2176
<orderedlist><listitem>
2177
<para>doing things like installing event filters to the object, etc.</para>
2180
<para>providing special plugin interfaces</para>
2186
<sect2 id="collect-your-components-the-komcontainer-kom">
2187
<title>Collect your components - the KOM::Container <indexterm remap="idx"><primary>KOM::Container</primary></indexterm> interface</title>
2189
<para>Containers do something simple but extremly useful: They act as repository for
2190
Container members. A container member structure consists of two elements:</para>
2192
<para><itemizedlist>
2194
<para>the member name, a freely chooseable and unique string identifier</para>
2197
<para>the member object, a KOM::Base <indexterm remap="idx"><primary>KOM::Base</primary></indexterm> type You can add, remove, replace, list
2198
and lookup container members or just clear the whole container. In
2199
addition the container emits signals whenever a member has been added
2206
<sect2 id="factories">
2207
<title>Factories</title>
2209
<para>KOM contains two abstract factory interfaces:
2210
<orderedlist><listitem>
2211
<para>KOM::AggregateFactory <indexterm remap="idx"><primary>KOM::AggregateFactory</primary></indexterm></para>
2214
<para>KOM::PluginFactory <indexterm remap="idx"><primary>KOM::PluginFactory</primary></indexterm></para>
2219
<para>They both serve the job of creating objects and are needed for the creation of
2220
dynamic plugin and aggregate components. Whenever you want to install a such a
2221
dynamically created object to a component you have to provide an
2222
implementation of a factory interface.</para>
2225
<sect2 id="komapplication-komapplication">
2226
<title>KOMApplication <indexterm remap="idx"><primary>KOMApplication</primary></indexterm></title>
2228
<para>KOMApplication <indexterm remap="idx"><primary>KOMApplication</primary></indexterm> is the drop-in replacement for KApplication <indexterm remap="idx"><primary>KApplication</primary></indexterm>, required when
2229
using CORBA in your KDE Application. It, internally, combines CORBA event
2230
handling with Qt event handling and initializes the ORB <indexterm remap="idx"><primary>ORB</primary></indexterm> and the BOA <indexterm remap="idx"><primary>BOA</primary></indexterm> on
2231
startup. komApplication.h defines two smart macros to get a reference to the
2232
ORB/BOA: <literal remap="tt">komapp&_;orb</literal> and <literal remap="tt">komapp&_;boa</literal> . Usually you will want
2233
to use your own application class, derived from KOMApplication, and
2234
re-implement <literal remap="tt">start()</literal> and/or <literal remap="tt">restore()</literal> , which will be called
2235
>from <literal remap="tt"><indexterm remap="cdx"><primary><literal>KOMApplication::exec()</literal></primary></indexterm>KOMApplication::exec()</literal>, depending on the BOA's state about
2236
restoring objects. For further information about KOMApplication's API see
2237
<indexterm remap="cdx"><primary><literal>komApplication.h</literal></primary></indexterm>komApplication.h .</para>
2241
<sect1 id="openparts">
2242
<title>OpenParts</title>
2244
<sect2 id="introduction-3">
2245
<title>Introduction</title>
2247
<para>The goals of the OpenParts technology, based upon KOM, are:
2250
<para>provide an easy way to graphically embed other application's "widgets"</para>
2253
<para>provide an clever way to manage shared GUI elements and provide a CORBA/KOM
2254
interface/implementation of these</para>
2257
<para>implement the basic support for the document view model</para>
2262
<para>To simplify the act of understanding OpenParts I will give a short example
2265
<para>Imagine you have an a word processor and a formula editor, both being separate
2266
applications. If you now want to insert a formula into your word processor
2267
document by using your formula editor application this arises several
2268
problems: You can of course embed the formula editor's main widget window via
2269
swallowing by using XReparentWindow and friends, or easier by using QXEmbed.
2270
But then how do you want to edit your formula without having access to the
2271
formula editor's menubar / toolbar? In any way it would look ugly if these are
2272
part of the formula window. Wouldn't it be nice if the menus / toolbars of
2273
your word processor application would get replaced by the formula editor ones,
2274
except for some general menu /toolbar items? And when you go back to your text
2275
document the old menus / toolbars come back again.</para>
2277
<para>Well, this is a perfect job for OpenParts :-) .</para>
2279
<para>OpenParts solves the above described problem by introducing a new sytem of
2280
visual components and a new way of creating shared GUI elements, such as menus
2281
or toolbars, dynamically on demand.</para>
2283
<para>In the implementation of OpenParts every element consists usually of two
2284
classes, the interface implementation, where the class name ends with "If",
2285
and the Qt/KDE object. So for example the OpenParts StatusBar element is
2286
represented by two classes: <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPStatusBar</literal></primary></indexterm>OPStatusBar</literal>, being derived from
2287
<indexterm remap="cdx"><primary><literal>KStatusBar</literal></primary></indexterm>KStatusBar, handles the Qt/KDE specific extensions, and
2288
<literal remap="tt"><indexterm remap="cdx"><primary><literal>OPStatusBarIf</literal></primary></indexterm>OPStatusBarIf</literal> which is responsible for providing an implementation
2289
of the actual <indexterm remap="cdx"><primary><literal>OpenPartsUI::StatusBar</literal></primary></indexterm>OpenPartsUI::StatusBar interface by "translating" the interface
2290
functionality into Qt/KDE function calls.</para>
2292
<para>Since every Qt/KDE object in OpenParts is most often bound to such an
2293
interface, like described above, there is usually an interface() function
2294
which returns a reference to the OpenParts interface of the element. In case
2295
of the above example <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPStatusBar::interface()</literal></primary></indexterm>OPStatusBar::interface()</literal> returns a reference to
2296
an <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPStatusBarIf</literal></primary></indexterm>OPStatusBarIf</literal> object which is directly bound to this
2297
<literal remap="tt"><indexterm remap="cdx"><primary><literal>OPStatusBar</literal></primary></indexterm>OPStatusBar</literal> object.</para>
2300
<sect2 id="opapplication-opapplication">
2301
<title>OPApplication <indexterm remap="idx"><primary>OPApplication</primary></indexterm></title>
2303
<para>Similar to <indexterm remap="cdx"><primary><literal>KOMApplication</literal></primary></indexterm>KOMApplication, the class <indexterm remap="cdx"><primary><literal>OPApplication</literal></primary></indexterm>OPApplication (derived from
2304
KOMApplication) is required when using OpenParts.</para>
2307
<sect2 id="qwidgetqwidget-as-component-the-openpartspar">
2308
<title><indexterm remap="cdx"><primary><literal>QWidget</literal></primary></indexterm>QWidget as Component? - the OpenParts::Part interface</title>
2310
<para>In OpenParts every window which has its own GUI and which is meant to be
2311
displayed in a MainWindow is called a Part (just like the formula editor view
2312
or the word processor document view in the above described example) , and
2313
implements the <indexterm remap="cdx"><primary><literal>OpenParts::Part</literal></primary></indexterm>OpenParts::Part interface by deriving from the class
2314
<literal remap="tt">OPPartIf</literal>.</para>
2316
<para>If you want to make a widget class a full-featured Part component then you
2317
have to handle some things different than you might be used to, in regard to
2318
the standard Qt/KDE widget framework. In fact now a widget is no more a simple
2319
window in which you display some data, no, a Part is much more than this. In
2320
particular a Part has, beside it's window (widget, which may of course contain
2321
sub-windows or even other Parts (see <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPFrame</literal></primary></indexterm>OPFrame</literal> documentation) ) a
2322
full-featured GUI, consisting of a menubar with menus, toolbar(s) and a
2325
<para>The special thing with the GUI is the way it is created, handled/used and
2326
"destroyed" . All this has to be highly dynamic because now the user decides
2327
about which Part he wants to have active. OpenParts provides the basic
2331
<para>it tells you when you have to create your GUI and provides you the necessary
2332
references to the GUI related objects of OpenParts.</para>
2335
<para>it also tells you when the GUI is destructed.</para>
2338
<para>in addition you are notified when your Part gets the focus and gives you
2339
the choice whether to accept or reject the focus.</para>
2342
<para>you are also notified when your Part gets registered to a MainWindow, in
2343
order to register your component at several GUI servant objects, just
2344
like the menubar manager for example.</para>
2349
<para>The very first step you have to make is to tell the OpenParts Part Interface
2350
(<literal remap="tt"><indexterm remap="cdx"><primary><literal>OPPartIf</literal></primary></indexterm>OPPartIf</literal>) , the class you have to inherit from, what the actual
2351
widget is, because <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPartIf</literal></primary></indexterm>OPartIf</literal> does not inherit from QWidget. This gives
2352
you the flexibility to separate your Part component from your actualy widget,
2353
but you don't have to do this. You can simply multiply inherit from
2354
<literal remap="tt">OPPartIf</literal> and <literal remap="tt"><indexterm remap="cdx"><primary><literal>QWidget</literal></primary></indexterm>QWidget</literal> or the appropriate widget class. In any way you
2355
specify your Part widget by calling <literal remap="tt">setWidget( your&_;widget&_;here )</literal> .
2356
In most cases, when the Part component is the widget at the same time, you
2357
simply call <literal remap="tt">setWidget( this )</literal> :-) . Make sure this call is done in
2358
the constructor of your class!</para>
2360
<para>The next important point is that you will want to re-implement the virtual
2361
<literal remap="tt">init()</literal> function of <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPPartIf</literal></primary></indexterm>OPPartIf</literal> . This is highly recommended
2362
since this function is called after your Part got registered by a MainWindow.
2363
The idea behind this function is that at the time the constructor of a Part
2364
gets executed, the Part itself is definitely not registered to a MainWindow,
2365
yet. But in fact you need to know when your Part gets registered, in order to
2366
register your Part at the GUI servant objects, which are only available via
2367
the MainWindow's interface. A reference to the MainWindow is available through
2368
the <literal remap="tt"><indexterm remap="cdx"><primary><literal>m&_;vMainWindow</literal></primary></indexterm>m&_;vMainWindow</literal> variable, which will be automatically initialized
2369
when the MainWindow registration is done, so don't use this variable before
2370
your <literal remap="tt">init()</literal> function gets called (<literal remap="tt">m&_;vMainWindow</literal> will be nil
2373
<para>Now over to the details of the <literal remap="tt"><indexterm remap="cdx"><primary><literal>init()</literal></primary></indexterm>init()</literal> function. Here you should place
2374
all initialisation stuff which depends on being registered to a MainWindow.
2375
In addition you can do the above mentioned registration at the GUI managing
2376
objects. Usually this looks like the following example:
2377
<programlisting>void MyPart::init()
2379
//register at the menubar manager if you want to use/display a menubar
2380
OpenParts::MenuBarManager_var menuBarManager = m_vMainWindow->menuBarManager();
2381
if ( !CORBA::is_nil( menuBarManager ) ) //check whether the shell window allows us to have a menubar
2382
menuBarManager->registerClient( id(), this ); //see chapter about the
2383
//*barManager objects
2384
//for further explanations
2386
//...the same with the toolbar
2387
OpenParts::ToolBarManager_var toolBarManager = m_vMainWindow->toolBarManager();
2388
if ( !CORBA::is_nil( toolBarManager ) )
2389
toolBarManager->registerClient( id(), this );
2391
//better define a class wide variable, of course
2392
OpenPartsUI::StatusBar_var m_vMyStatusBar;
2394
OpenParts::StatusBarManager_var statusBarManager = m_vMainWindow->statusBarManager();
2395
if ( !CORBA::is_nil( statusBarManager ) )
2396
m_vMyStatusBar = statusBarManager->registerClient( id() );
2400
<para>Note that the registration calls for these three GUI element types are only
2401
necessary if you really want to use them. For example if your Part does not
2402
want to display any toolbar you should leave out the corresponding call. In
2403
addition you might come up with the situation that for example the
2404
<literal remap="tt"><indexterm remap="cdx"><primary><literal>toolBarManager()</literal></primary></indexterm>toolBarManager()</literal> call returns a nil reference, which indicates that
2405
the MainWindow does not allow its Parts to have a toolbar. Obviously the same
2406
applies for the menubar and the statusbar.</para>
2408
<para>OpenParts makes use of KOM events to tell a Part about the
2409
construction/destruction of it's GUI. These are in particular:
2412
<para><literal remap="tt">OpenPartsUI::eventCreateMenuBar</literal> ("OpenPartsUI/CreateMenuBar")</para>
2416
The attached argument is a <literal remap="tt">OpenPartsUI::MenuBar</literal></para>
2418
<para><itemizedlist>
2420
<para><literal remap="tt">OpenPartsUI::eventCreateToolBar</literal> ("OpenPartsUI/CreateToolBar")</para>
2424
The attached argument is a <literal remap="tt">OpenPartsUI::ToolBarFactory</literal></para>
2426
<para>Depending on whether a Part wants to display a menubar and/or toolbar, the
2427
managing objects emit these two events to it. In regard to your implementation
2428
this means that you have to re-implement the <literal remap="tt"><indexterm remap="cdx"><primary><literal>event()</literal></primary></indexterm>event()</literal> function
2429
(remember: A Part is a full-featured KOM Component) .</para>
2431
<para>The attached event arguments indicate whether the toolbar(s) or the menubar
2432
are to be created or cleared. Check these arguments against
2433
<literal remap="tt">CORBA::is&_;nil()</literal> and you know :-) .</para>
2435
<para>The OpenParts StatusBar is handled different compared to the
2436
MenuBar/ToolBar(s) . In fact it is easier: When registering at the OpenParts
2437
StatusBarManager you receive your <literal remap="tt"><indexterm remap="cdx"><primary><literal>OpenParts::StatusBar</literal></primary></indexterm>OpenParts::StatusBar</literal> as return
2438
value. You can then use the StatusBar everywhere in your Part, independend
2439
from whether it is visible (active) or not.</para>
2441
<para>In the <literal remap="tt"><indexterm remap="cdx"><primary><literal>init()</literal></primary></indexterm>init()</literal> function a lot of registration stuff is done, and
2442
corresponding to this in the <literal remap="tt"><indexterm remap="cdx"><primary><literal>cleanUp()</literal></primary></indexterm>cleanUp()</literal> function (see chapter about
2443
KOM::Base <indexterm remap="idx"><primary>KOM::Base</primary></indexterm>) you have to unregister from the GUI servant objects and free all
2444
appropriate references, following KOM's model of symmetric references and
2445
connections. Usually the code looks like this:
2446
<programlisting>void MyPart::cleanUp()
2451
//unregister our menubar
2452
OpenParts::MenuBarManager_var menuBarManager = m_vMainWindow->menuBarManager();
2453
if ( !CORBA::is_nil( menuBarManager ) )
2454
menuBarManager->unregisterClient( id() );
2456
//...the same with the toolbar
2457
OpenParts::ToolBarManager_var toolBarManager = m_vMainWindow->toolBarManager();
2458
if ( !CORBA::is_nil( toolBarManager ) )
2459
toolBarManager->unregisterClient( id() );
2461
OpenParts::StatusBarManager_var statusBarManager = m_vMainWindow->statusBarManager();
2462
if ( !CORBA::is_nil( statusBarManager ) )
2463
statusBarManager->unregisterClient( id() );
2465
//free other references here
2468
//this is IMPORTANT!!!
2469
//Always call the cleanUp() method of the base class when you're done!
2470
OPPartIf::cleanUp();
2475
<sect2 id="part-children">
2476
<title>Part Children</title>
2478
<para>A Part Child is a usual Part with three extra features:
2479
<orderedlist><listitem>
2480
<para>A Part Child has a Parent Part assigned.</para>
2483
<para>It does not have a GUI and it therefore does not receive any GUI creation
2487
<para>The Parent Child receives events whenever there are any child related focus
2488
changes. Since the Part Child functionality is integrated in the
2489
<literal remap="tt"><indexterm remap="cdx"><primary><literal>OpenParts::Part</literal></primary></indexterm>OpenParts::Part</literal> interface and it's implementation,
2490
<literal remap="tt"><indexterm remap="cdx"><primary><literal>OPPartIf</literal></primary></indexterm>OPPartIf</literal>, you don't have to deal with additional classes when
2491
using Child Parts. Simply leave out the mapping of the OpenParts GUI
2492
events in the Child Part and instead map the Child Part events described
2493
below and assign the Parent Part via <literal remap="tt"><indexterm remap="cdx"><primary><literal>setParent()</literal></primary></indexterm>setParent()</literal>. See the
2494
interface description of <literal remap="tt"><indexterm remap="cdx"><primary><literal>OpenParts::Part</literal></primary></indexterm>OpenParts::Part</literal> , in <indexterm remap="cdx"><primary><literal>openparts.idl</literal></primary></indexterm>openparts.idl,
2495
for further information about the events and the API in general.</para>
2501
<sect2 id="how-to-embed-a-part-the-opframeopframe-class">
2502
<title>How to embed a Part - the <indexterm remap="cdx"><primary><literal>OPFrame</literal></primary></indexterm>OPFrame class</title>
2504
<para>Now that you know how to create full-featured Part components it is still
2505
unexplained how Parts are really displayed/shown. Since Parts are no simple
2506
QWidgets but CORBA objects we need a helping hand here, which is the
2507
<literal remap="tt">OPFrame</literal> class. In fact <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPFrame</literal></primary></indexterm>OPFrame</literal> is a <indexterm remap="cdx"><primary><literal>QWidget</literal></primary></indexterm>QWidget, but in
2508
conjuction with Qt's <indexterm remap="cdx"><primary><literal>QXEmbed</literal></primary></indexterm>QXEmbed it embeds the Part's widget window. The usage of
2509
<literal remap="tt">OPFrame</literal> is really easy, usually the code looks like this:</para>
2511
<para><programlisting>... somewhere in an application's widget ...
2512
myFrame = new OPFrame( the_parent_widget );
2513
myFrame->attach( a_reference_to_the_part_we_want_to_embed );
2514
myFrame->show();</programlisting>
2517
<para>In addition to the above example you can <literal remap="tt"><indexterm remap="cdx"><primary><literal>detach()</literal></primary></indexterm>detach()</literal> your Part, which
2518
you should usually do on exit. Just have a look at <indexterm remap="cdx"><primary><literal>opFrame.h</literal></primary></indexterm>opFrame.h, it is
2521
<para>One last important thing you have to know about <literal remap="tt"><indexterm remap="cdx"><primary><literal>OPFrame</literal></primary></indexterm>OPFrame</literal> is that this
2522
class internally uses KOM referencing (using a <literal remap="tt">KOMVar</literal> variable) to
2523
hold the Part. This means that there are two possible situations when using
2524
<literal remap="tt">OPFrame</literal> :</para>
2526
<para><itemizedlist>
2528
<para>If the embedding Widget/Object uses KOM referencing as well to keep a
2529
reference to the Part then there are two objects influencing the Part's
2530
lifecycle. On the one hand there's the <literal remap="tt">OPFrame</literal> which
2531
increases/decreases the Part's KOM reference counter when it gets
2532
attached/detached, and on the other hand there's the embedding
2533
Widget/Object. So make sure that you know when you free your KOM
2534
reference to the Part in regard to detaching the Part!</para>
2537
<para>If the embedding Widget/Object does not use KOM referencing then you have
2538
to know that when detaching the Part it automatically gets destroyed,
2539
since usually the <literal remap="tt">OPFrame</literal> is the only object holding a KOM
2540
reference to the Part and the KOM reference counter therefore drops
2541
down to zero and issues the complete destruction of the object.</para>
2547
<sect2 id="the-center-of-openparts-the-openpartsmainwin">
2548
<title>The center of OpenParts - the OpenParts::MainWindow interface</title>
2550
<para>Another important component is the so called <indexterm remap="cdx"><primary><literal>OpenParts::MainWindow</literal></primary></indexterm>OpenParts::MainWindow, being
2551
derived from a <indexterm remap="cdx"><primary><literal>KTMainWindow</literal></primary></indexterm>KTMainWindow in the implementation (and therefore the top-level
2552
window of your application) and being the shell around visible sub-windows and
2553
shared GUI elements.</para>
2555
<para>The MainWindow's functionality is extended by some builtin aggregates, the
2556
managing objects for the menu-/tool-/statusbar. These objects are either
2557
available directly via the <literal remap="tt">*barManager()</literal> methods of the MainWindow's
2558
interface or indirectly by being aggregates and therefore available via the
2559
components interface repository (<literal remap="tt"><indexterm remap="cdx"><primary><literal>getInterface()</literal></primary></indexterm>getInterface()</literal>,
2560
<literal remap="tt"><indexterm remap="cdx"><primary><literal>supportsInterface()</literal></primary></indexterm>supportsInterface()</literal>, ...) .</para>
2562
<para>A Part can only be displayed in a MainWindow and the MainWindow has to know
2563
about this. So before you can display a Part you have to register it to the
2564
MainWindow. This is done by calling the Part Interface's
2565
<literal remap="tt"><indexterm remap="cdx"><primary><literal>setMainWindow()</literal></primary></indexterm>setMainWindow()</literal> method (see previous chapter for further information
2566
about the process of registration) and this will give the Part a unique ID
2567
(which is for example used when addressing the part's GUI via the *bar manager
2570
<para>The MainWindow, as shell, has full control over all shared GUI elements. This
2571
means that it is responsible for
2574
<para>creating the appropriate *bar managing objects</para>
2577
<para>providing a skeleton/standard GUI which is meant to be always present,
2578
no matter what Part is active</para>
2581
<para>telling the GUI managing objects to activate/deactivate a Part's GUI</para>
2586
<para>The creation of the *bar managers can be easily done by simply performing a
2587
dummy call to <literal remap="tt">*barManager()</literal> which usually returns a pointer to the
2588
appropriate manager and also creates a new one if it does not exist yet. It is
2589
recommended to perform these calls in the constructor of your MainWindow.</para>
2591
<para>The creation/handling of the skeleton GUI is explained later in the chapters
2592
about <indexterm remap="cdx"><primary><literal>OPMenu</literal></primary></indexterm>OPMenu(Bar)/<indexterm remap="cdx"><primary><literal>OPToolBar</literal></primary></indexterm>OPToolBar .</para>
2594
<para>Your MainWindow emits a Qt signal (<literal remap="tt"><indexterm remap="cdx"><primary><literal>activePartChanged</literal></primary></indexterm>activePartChanged</literal>) which informs
2595
you about a focus change of the active part, meaning whenever the user clicks
2596
on a non-active Part and it accepts the focus. Beside the pure informative
2597
sense of this signal it is recommended to connect to this signal and perform
2598
the following two steps in the slot implementation:</para>
2600
<para><orderedlist><listitem>
2601
<para>deactivate the previous active Part's GUI by calling the *bar managers
2602
<literal remap="tt"><indexterm remap="cdx"><primary><literal>clear()</literal></primary></indexterm>clear()</literal> function, which will do the job and, beside some
2603
internal stuff, emit the GUI events (see previous chapter) to the Part.</para>
2606
<para>activate the new active Part's GUI by calling the *bar managers
2607
<literal remap="tt"><indexterm remap="cdx"><primary><literal>create()</literal></primary></indexterm>create()</literal> function, which will, similar to the activation, emit
2608
events to the Part. This is not really required but it is highly
2609
recommended. The following code is usually used for this:
2611
<programlisting> void NameOfYourMainWindow::slotActivePartChanged( unsigned long old_id,
2612
unsigned long new_id )
2614
// clear the menu/tool/statusbar(s)
2615
menuBarManager()->clear();
2616
toolBarManager()->clear();
2617
statusBarManager()->clear();
2618
// create the new Part's GUI
2619
menuBarManager()->create( new_id );
2620
toolBarManager()->create( new_id );
2621
statusBarManager()->create( new_id );
2629
<para>Now that the MainWindow handles all the shared "stuff" there is one thing
2630
which was not mentioned in this documentation, yet: What about the
2631
MainWindow's caption? The OpenParts MainWindow interface allows parts to have
2632
their own window captions, but how does OpenParts handle this?</para>
2634
<para>Well, there are two ways:
2635
<orderedlist><listitem>
2636
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>OPMainWindow</literal></primary></indexterm>OPMainWindow</literal> provides you a so called <literal remap="tt"><indexterm remap="cdx"><primary><literal>AutoCaption</literal></primary></indexterm>AutoCaption</literal> mode
2637
which automatically changes the MainWindow's caption whenever the active
2638
part changes. This is enabled by default.</para>
2641
<para>But sometimes the shell wants to have full control over the window's
2642
caption, and this is accomplished by disabling the <literal remap="tt">AutoCaption</literal>
2643
mode, which leads to the situation that the window's caption is not
2644
changed by OpenParts in any way but instead gives you control over it.</para>
2650
<sect2 id="access-shared-gui-elements-through-corba-ope">
2651
<title>Access shared GUI elements through CORBA - OpenPartsUI and its interfaces</title>
2653
<para>Well, now that we know when we have to construct/destruct a Part's GUI,
2654
via the <indexterm remap="cdx"><primary><literal>OpenPartsUI</literal></primary></indexterm>OpenPartsUI events, we have to learn how to really create it, because
2655
we don't have the common <indexterm remap="cdx"><primary><literal>KMenuBar</literal></primary></indexterm>KMenuBar, <indexterm remap="cdx"><primary><literal>KToolBar</literal></primary></indexterm>KToolBar, etc. classes anymore available.
2656
The replacement for them are CORBA Objects, described in openparts&_;ui.idl which
2657
is, together with the corresponding implementations, a part of the partsui
2658
module. The interfaces are 98&%;; similar to the KDE/Qt classes, so they're
2659
quite easy to use. Instead of bloating up this documentation with example code
2660
I rather suggest reading the tutorials in kdelibs/corba/tutorials .</para>
2663
<sect2 id="pixmaps-pixmaps-and-strings-strings-in-openp">
2664
<title>Pixmaps <indexterm remap="idx"><primary>Pixmaps</primary></indexterm> and Strings <indexterm remap="idx"><primary>Strings</primary></indexterm> in OpenParts - <indexterm remap="cdx"><primary><literal>OPUIUtils</literal></primary></indexterm>OPUIUtils</title>
2666
<para>Toolbars and menus are usually beautified with pixmaps, using QPixmap classes.
2667
As we now use a CORBA interface to access our GUI elements, <indexterm remap="cdx"><primary><literal>QPixmap</literal></primary></indexterm>QPixmap has become
2668
<indexterm remap="cdx"><primary><literal>OpenPartsUI::Pixmap</literal></primary></indexterm>OpenPartsUI::Pixmap for OpenParts applications. OpenPartsUI::Pixmap is just
2669
a "stringified" QPixmap, and opUIUtils.(h,cc) contains some easy
2670
to use conversion routines.</para>
2672
<para>In addition OPUIUtils contains string conversion routines between CORBA::WChar*
2673
and <indexterm remap="cdx"><primary><literal>QString</literal></primary></indexterm>QString. This is necessary since Qt version >=2.0 supports <indexterm remap="cdx"><primary><literal>Unicode</literal></primary></indexterm>Unicode,
2674
via QString, all over the place, and obviously GUI elements like menus or
2675
toolbars have been converted to support this. OpenParts has been converted,
2676
too, by using "wstring" (<indexterm remap="cdx"><primary><literal>CORBA::WChar *</literal></primary></indexterm>CORBA::WChar *) in the interfaces and by
2677
using and providing conversion routines. These routines are static member
2678
functions of the OPUIUtils class, just like with the pixmap conversion. To
2679
simplify the usage, two macros have been defined: <literal remap="tt"><indexterm remap="cdx"><primary><literal>Q2C</literal></primary></indexterm>Q2C</literal> and
2680
<literal remap="tt"><indexterm remap="cdx"><primary><literal>C2Q</literal></primary></indexterm>C2Q</literal> . The first one converts a QString into a CORBA::WChar * string
2681
and the second one vice-versa.</para>
2683
<para>When converting from QString to CORBA::WChar * the conversion routine
2684
allocates memory. To avoid memory leaks <indexterm remap="idx"><primary>memory leaks</primary></indexterm> it is highly recommended to use
2685
CORBA::WString&_;var variables. Exactly the same applies for QPixmap ->
2686
OpenPartsUI::Pixmap conversions: Use <indexterm remap="cdx"><primary><literal>OpenPartsUI::Pixmap&_;var</literal></primary></indexterm>OpenPartsUI::Pixmap&_;var , and you don't
2687
have to worry about leaks :-) .</para>
2689
<para>Here's some example code, to show how to do it right:
2690
<programlisting> ...
2691
OpenPartsUI::Pixmap_var pm = OPUIUtils::convertPixmap( QPixmap_variable_here );
2692
someToolBar->insertButton( pm, ... );
2694
//use the same pm variable again
2695
pm = OPUIUtils::convertPixmap( another_qpixmap );
2696
...</programlisting>
2699
<para>Similar things have to be done with QString's:</para>
2701
<para><programlisting> ...
2702
CORBA::WString_var text = Q2C( QString_here );
2703
someMenuBar->insertItem7( text, ... );
2705
// or you can write:
2706
someMenuBar->insertItem7( ( text = Q2C( QString_here ) ) , ...);
2707
...</programlisting>
2710
<para>One note left: When you return a "wide string" (CORBA::WChar *) as
2711
a function result by using <literal remap="tt">Q2C</literal>, make sure not to use
2712
<literal remap="tt"><indexterm remap="cdx"><primary><literal>CORBA::wstring&_;dup()</literal></primary></indexterm>CORBA::wstring&_;dup()</literal>.</para>
2715
<programlisting> return CORBA::string_dup( Q2C( QString_here ) ); //!!!! WRONG!!!!!
2717
return Q2C( QString_here ); // RIGHT! because Q2C already allocates the string</programlisting>
2720
<para>That's it! Have fun using KOM/OpenParts :-)</para>
2725
<para>KOMShutdownManager</para>
2728
<para>AutoLoader template classes</para>
2731
<para>OPApplication Interface + Factories</para>
2739
<chapter id="kdedaemon">
2740
<title>The KDE Daemon</title>
2742
<para>Simon Hausmann <ulink url="mailto:hausmann@kde.org"><hausmann@kde.org></ulink></para>
2744
<para>v1.0 26, June 1999</para>
2746
<para><emphasis>This documentation describes the KDE Daemon, the services it provides and
2747
how to use it. So if you're dealing with CORBA server <indexterm remap="idx"><primary>CORBA server</primary></indexterm>s in the KDE or if you're
2748
interested in a smart way of accessing KService <indexterm remap="idx"><primary>KService</primary></indexterm> data in your application then
2749
you might want to read this and use <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded</emphasis></para>
2751
<sect1 id="introduction-4">
2752
<title>Introduction</title>
2754
<para>The KDE Daemon, herein simply named <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded, is a central daemon in the KDE Desktop
2755
Environment. It provides three services:</para>
2757
<para><itemizedlist>
2759
<para>The KDE Trader (<indexterm remap="cdx"><primary><literal>KTrader</literal></primary></indexterm>KTrader) , which provides an easy-to-use but still extremly
2760
powerful interface to the KDE Registry.</para>
2763
<para>The KDE Activator (<indexterm remap="cdx"><primary><literal>KActivator</literal></primary></indexterm>KActivator) , which makes accessing CORBA based services
2764
in KDE the easiest thing of the world ;-) .</para>
2767
<para>The KDE Naming Service (<indexterm remap="cdx"><primary><literal>KNaming</literal></primary></indexterm>KNaming) , which provides a simple but useful
2768
naming service for CORBA Objects.</para>
2774
<sect1 id="using-the-kde-daemon-in-your-application">
2775
<title>Using The KDE Daemon In Your Application</title>
2777
<para>Before we can use any of <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded's services, we have to know something about it's
2778
"position" in the KDE and the way it itself and the services can be accessed.</para>
2780
<para>As <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded uses CORBA to communicate with it's clients, your application (as client),
2784
<para>link to the <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded library, <indexterm remap="cdx"><primary><literal>libkded</literal></primary></indexterm>libkded.</para>
2787
<para>link to libmico</para>
2790
<para>initialize the MICO <indexterm remap="idx"><primary>MICO</primary></indexterm> ORB <indexterm remap="idx"><primary>ORB</primary></indexterm></para>
2795
<para>The first two points are fixed for all clients, the third one depends on the
2796
specific client. In general you have to choices:</para>
2798
<para><itemizedlist>
2800
<para>If your application already uses KOM <indexterm remap="idx"><primary>KOM</primary></indexterm>, then you're fine with using
2801
<indexterm remap="cdx"><primary><literal>KOMApplication</literal></primary></indexterm>KOMApplication (as you need it anyway) .</para>
2804
<para>If you don't want to use KOM <indexterm remap="idx"><primary>KOM</primary></indexterm>, then you can initialize the ORBA "manually":
2805
<literal remap="verb">CORBA::ORB_ptr orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );</literal>
2806
Please note that when using this construct or similar ones, your application is
2807
<emphasis remap="bf">not</emphasis> able to act as CORBA server <indexterm remap="idx"><primary>CORBA server</primary></indexterm> if you are using KDE/Qt classes at the
2808
same time. This is due to the fact that the ORB <indexterm remap="idx"><primary>ORB</primary></indexterm> needs it's own event loop, beside
2809
the main Qt event loop. Currently only <indexterm remap="cdx"><primary><literal>KOMApplication</literal></primary></indexterm>KOMApplication, as part of the KDE Object
2810
Model, implements the needed functionality to combine both event loops and thus
2811
making KDE apps able to serve CORBA Objects.</para>
2816
<para>Although <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded uses CORBA extensively, the API is kept simple and free from
2817
complicated CORBA stuff. In fact when talking about <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded and it's API not the
2818
<indexterm remap="cdx"><primary><literal>kded server</literal></primary></indexterm>kded server is meant but the KDE Daemon library. This library contains the
2819
interface to the server (for the clients) as well as the whole server functionality.
2820
The reason for this is based on the idea that an application using <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded should
2821
not be forced to rely on an existing <indexterm remap="cdx"><primary><literal>kded server</literal></primary></indexterm>kded server binary nor a running server at
2822
all. The following three situations may exist when a client app gets started:</para>
2824
<para><itemizedlist>
2826
<para>No <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded is running and there's no <indexterm remap="cdx"><primary><literal>kded server</literal></primary></indexterm>kded server binary in the path. In this
2827
situation <indexterm remap="cdx"><primary><literal>libkded</literal></primary></indexterm>libkded will automatically start a local instance of <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded in
2828
the application's process.</para>
2831
<para>No <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded is running but there's a <indexterm remap="cdx"><primary><literal>kded server</literal></primary></indexterm>kded server binary available. Here <indexterm remap="cdx"><primary><literal>libkded</literal></primary></indexterm>libkded
2832
will start the kded executable and connect to it.</para>
2835
<para><indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded is already running :-) . The fact that a <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded is running is indicated
2836
by a special property on the X Root Window. <indexterm remap="cdx"><primary><literal>kded</literal></primary></indexterm>kded publishes it's IOR <indexterm remap="idx"><primary>IOR</primary></indexterm>
2837
(Interoperable Object Reference) in this property. This also ensures that
2838
a kded <indexterm remap="idx"><primary>kded</primary></indexterm> instance is specific to a X display and therefore to your KDE session.</para>
2843
<para>To sum it up: libkded <indexterm remap="idx"><primary>libkded</primary></indexterm> will always make sure that the services of kded <indexterm remap="idx"><primary>kded</primary></indexterm> are available
2844
for your client application, no matter in what alien environment the app is
2845
running :-) . And, although you don't have to care about this, you can optionally
2846
control this behaviour of libkded <indexterm remap="idx"><primary>libkded</primary></indexterm> by adding one of the following three commandline arguments <indexterm remap="idx"><primary>commandline arguments</primary></indexterm>
2850
<para>"-kdedlocal" , which will make libkded <indexterm remap="idx"><primary>libkded</primary></indexterm> <emphasis remap="bf">always</emphasis> start a process-local
2851
instance of kded and it's services.</para>
2854
<para>"-kdedremote" , which will make libkded <indexterm remap="idx"><primary>libkded</primary></indexterm> try to look for a running kded <indexterm remap="idx"><primary>kded</primary></indexterm>
2855
instance before starting a local one.</para>
2858
<para>"-kdedior ior&_;here" , which will make libkded <indexterm remap="idx"><primary>libkded</primary></indexterm> connect to the kded server <indexterm remap="idx"><primary>kded server</primary></indexterm>
2859
specified by the given IOR <indexterm remap="idx"><primary>IOR</primary></indexterm>.</para>
2864
<para>Your actual interface to kded <indexterm remap="idx"><primary>kded</primary></indexterm> and it's services is the <literal remap="tt"><indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance</literal> class,
2865
defined in kded&_;instance.h . So if you want to use kded <indexterm remap="idx"><primary>kded</primary></indexterm> (I guess that's why you're
2866
reading this shit ;) ) then make sure to create <emphasis remap="bf">one</emphasis> single instance
2867
of it, preferably by adding the following line somewhere in the beginning of
2868
your <literal remap="tt">main()</literal> :
2869
<literal remap="verb">KdedInstance( argc, argv, _a_reference_to_the_orb_here_ );</literal>
2870
If you're using KOMApplication <indexterm remap="idx"><primary>KOMApplication</primary></indexterm> as application object (make sure to create the
2871
instance before this line) , then you're fine by specifying <literal remap="tt">komapp&_;orb</literal> as
2872
reference to the ORB <indexterm remap="idx"><primary>ORB</primary></indexterm>.</para>
2874
<para>As there is always only one single instance of this class, you can simply access
2875
it by the static <literal remap="tt"><indexterm remap="cdx"><primary><literal>self()</literal></primary></indexterm>self()</literal> method of the class from anywhere you want. No
2876
need to pass <indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance arguments all around in your program ;-) .</para>
2878
<para>For further information about <literal remap="tt"><indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance</literal> you might want to read
2879
<literal remap="tt"><indexterm remap="cdx"><primary><literal>kded&_;instance.h</literal></primary></indexterm>kded&_;instance.h</literal> , it's pretty good documented.</para>
2882
<sect1 id="ktrader-ktrader">
2883
<title>KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm></title>
2885
<para>As already mentioned in the introduction, KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> gives you access to the registry.
2886
"Now what the hell is the registry?" you might ask. As this is just a documentation
2887
about kded <indexterm remap="idx"><primary>kded</primary></indexterm>/libkded <indexterm remap="idx"><primary>libkded</primary></indexterm>, I can only respond: "Please consult the documentation of/in
2888
<literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> for more information" :-&}; . Just one thing about it here: KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> loads
2889
the whole and bloaty registry for you. Thanks to the magic of <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> the loaded
2890
registry will always be in sync with the "real" registry, the .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> files in
2891
the following standard directories (both types, the system wide and the user ones) :
2897
<para>mimelnk</para>
2900
<para>services</para>
2903
<para>servicetypes</para>
2908
<para>Now over to KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> and it's API. Similar to <literal remap="tt"><indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance</literal> there can
2909
be only one single instance. The difference is that you don't have to care
2910
about allocating it, just simply get a reference to the KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> by calling
2911
the <literal remap="tt">ktrader()</literal> method of <literal remap="tt"><indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance</literal> . And: don't
2912
even think about deleting the returned reference! Just simply use it and be
2913
happy with it :-) . (hey, kded <indexterm remap="idx"><primary>kded</primary></indexterm> is designed to be easy to use, no need for difficult
2916
<para>The KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> API is even so simple that it contains only two methods ;-) . But
2917
before I describe these methods you have to know something about the kind of
2918
data KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> returns. In simple words: You will always get a list of KService <indexterm remap="idx"><primary>KService</primary></indexterm>
2919
objects. More detailed: The returned list is a <literal remap="tt"><indexterm remap="cdx"><primary><literal>QValueList</literal></primary></indexterm>QValueList</literal> and the
2920
entries are <literal remap="tt"><indexterm remap="cdx"><primary><literal>KSharedPtr</literal></primary></indexterm>KSharedPtr</literal>'s (FIXME: will soon be renamed to QSharedPtr,
2921
as it will become part of Qt.... AFAIK) to <literal remap="tt">KService <indexterm remap="idx"><primary>KService</primary></indexterm></literal> objects. Please
2922
read the corresponding Qt documentation about these two classes. The big advantage
2923
of using these two template classes is that everything becomes easy for you
2924
and that the memory consumption is kept at a minimum . You don't have to care
2925
about pointers, freeing them and cleaning up the list, as long as you use
2926
<literal remap="tt"><indexterm remap="cdx"><primary><literal>KTrader::ServicePtr</literal></primary></indexterm>KTrader::ServicePtr</literal> variables to hold the KService <indexterm remap="idx"><primary>KService</primary></indexterm> objects and as
2927
long as you use <literal remap="tt"><indexterm remap="cdx"><primary><literal>KTrader::OfferList</literal></primary></indexterm>KTrader::OfferList</literal> to pass the list around in your
2928
program. So: Remember to always use these two types when dealing with KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm>!</para>
2930
<para>Now over to the two methods.</para>
2932
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>KTrader::listServices()</literal></primary></indexterm>KTrader::listServices()</literal> returns your a list of <emphasis remap="bf">all</emphasis> available
2933
services in the whole KDE. (no need for further explanations I think...)</para>
2935
<para><literal remap="tt"><indexterm remap="cdx"><primary><literal>KTrader::query()</literal></primary></indexterm>KTrader::query()</literal> is the key method of this beast. It performs a lookup
2936
in the registry database, given your information about what you want to have.
2937
The first argument is the name of the servicetype which all returned services
2938
must implement. If you're unsure about the word "servicetype" , then you can
2939
replace it with "mimetype" , for most, but not all, cases.</para>
2941
<para>The second argument is an additional constraint expression, which has to be
2942
fulfilled by a service.</para>
2944
<para>The third argument is a preference expression after which the returned services
2945
will be sorted. The value of the expression has to be numeric.</para>
2947
<para>The syntax of these two expressions is equal with the language of the standard
2948
CORBA Trader (this is due to the fact that the parsing code is from the COS <indexterm remap="idx"><primary>COS</primary></indexterm>
2949
Trader of MICO <indexterm remap="idx"><primary>MICO</primary></indexterm>) . The language is not very difficult and I don't want to bloat
2950
this documentation with further explanations about it. Please consult your
2951
CORBA literature for more information. Just one thing you have to know:
2952
Comparisons are always done with the properties of the KService <indexterm remap="idx"><primary>KService</primary></indexterm> object,
2953
which are the standard entries (Name, ServiceType, RepoIds, ...) plus
2954
the ones specified in the servicetype declaration and read by KService <indexterm remap="idx"><primary>KService</primary></indexterm>.</para>
2956
<para>Well, after so much theoretical explanations it's time for some practical example
2958
<indexterm remap="ncdx"><primary><literal>KTrader::OfferList</literal></primary></indexterm>
2959
<programlisting> ...
2960
//get a reference to the KTrader
2961
KTrader *trader = KdedInstance::self()->ktrader();
2964
//will return a list of all services which implement the servicetype
2965
//named "text/plain"
2966
KTrader::OfferList offers = trader->query( "text/plain" );
2970
//will return a list of all services which implement the servicetype
2971
//named "image/gif" and which have the AllowAsDefault property set true
2972
KTrader::OfferList offers = trader->query( "image/gif", "AllowAsDefault == TRUE" );
2975
//will return KSpread ;-)
2976
KTrader::OfferList offers = trader->query( "KOfficeDocument", "(Exec == 'kspread') and (Path != '/opt/gnome/bin')" );
2979
//will return a list of all services which implement the servicetype
2980
//named "BlahFoo" and which will be sorted (from lowest to highest) by
2981
//the value of the property "Price" , declared in the servicetype
2982
//declaration of BlahFoo.
2983
KTrader::OfferList offers = trader->query( "BlahFoo", QString::null, "min Price" );</programlisting>
2986
<para>Please note that KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm>, since it queries <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> for services, will
2987
always return services sorted by the user's preferences for the specific
2988
servicetype. These preferences can be specified in the file "profilerc" .</para>
2990
<sect2 id="ktraderserviceprovider">
2991
<title>KTraderServiceProvider</title>
2993
<para>This section requires to be familiar with <literal remap="tt"><indexterm remap="cdx"><primary><literal>libkio</literal></primary></indexterm>libkio</literal> and it is meant for everybody who
2994
wants to use KRun <indexterm remap="idx"><primary>KRun</primary></indexterm> in his application.</para>
2996
<para>KRun <indexterm remap="idx"><primary>KRun</primary></indexterm> requires a fully loaded registry in order to resolve mimetype <-> application
2997
bindings. A fully loaded registry means that you need a <literal remap="tt"><indexterm remap="cdx"><primary><literal>KServiceTypeFactory</literal></primary></indexterm>KServiceTypeFactory</literal> and
2998
a KServiceFactory, which both load the appropriate <literal remap="tt"><indexterm remap="cdx"><primary><literal>KServiceType</literal></primary></indexterm>KServiceType</literal><literal remap="tt"><indexterm remap="cdx"><primary><literal>KService</literal></primary></indexterm>KService</literal> objects.
2999
Now the KServiceType information doesn't need that much memory, but the KService <indexterm remap="idx"><primary>KService</primary></indexterm>
3000
object really eat loooots of it. And isn't it kind of stupid to load this information
3001
if this is already done by kded <indexterm remap="idx"><primary>kded</primary></indexterm>? Yes, it is ;-) .</para>
3003
<para>What we would need is to make KRun <indexterm remap="idx"><primary>KRun</primary></indexterm> query KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> for KService <indexterm remap="idx"><primary>KService</primary></indexterm> data, instead of
3004
directly using KServiceTypeProfile <indexterm remap="idx"><primary>KServiceTypeProfile</primary></indexterm>. Fortunately KRun <indexterm remap="idx"><primary>KRun</primary></indexterm> is flexible enough for this,
3005
we just need a re-implementation of the KServiceProvider <indexterm remap="idx"><primary>KServiceProvider</primary></indexterm>, defined in <literal remap="tt"><indexterm remap="cdx"><primary><literal>krun.h</literal></primary></indexterm>krun.h</literal>
3006
and used by KRun <indexterm remap="idx"><primary>KRun</primary></indexterm>. Guess what, but KTrader <indexterm remap="idx"><primary>KTrader</primary></indexterm> provides you this re-implementation :-) .
3007
Just have a look at the end of <literal remap="tt"><indexterm remap="cdx"><primary><literal>ktrader.h</literal></primary></indexterm>ktrader.h</literal>.</para>
3009
<para>To sum it up: The following line makes KRun <indexterm remap="idx"><primary>KRun</primary></indexterm> query kded <indexterm remap="idx"><primary>kded</primary></indexterm>, in your application:
3010
<programlisting> ...
3011
//place this somewhere BEFORE the first usage of KRun, preferable somewhere
3013
KTraderServiceProvider serviceProvider;
3014
...</programlisting>
3016
That's all, except that you <emphasis remap="bf">must</emphasis> have a <indexterm remap="cdx"><primary><literal>KdedInstance</literal></primary></indexterm>KdedInstance in order to be
3017
able to use it.</para>
3021
<sect1 id="kactivator-kactivator">
3022
<title>KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm></title>
3024
<para>One often mentioned problem, when talking about applications which provide
3025
their services via CORBA, is how to start and access these services. Solutions
3026
like making apps write the IOR <indexterm remap="idx"><primary>IOR</primary></indexterm> of an object somewhere into a file in the
3027
filesystem or similar approaches are just hacks ;-) . Better use KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm>,
3028
since it can automatically, on demand, start servers for you or use already
3029
running ones. This is accomplished with the help of the mediators for BOA/POA <indexterm remap="idx"><primary>BOA/POA</primary></indexterm>
3030
and the IMR <indexterm remap="idx"><primary>IMR</primary></indexterm> (Implementation Repository), both provided by MICO <indexterm remap="idx"><primary>MICO</primary></indexterm>. Fortunately
3031
you don't have to deal with IMR entries and the mediators.</para>
3033
<para>Before you can use KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> to start a server for you, you have to register
3034
the server's service. There are two possible ways, the last one is highly
3035
recommended though:</para>
3037
<para><itemizedlist>
3039
<para>Register and unregister it manually, by using the two corresponding
3040
methods of the KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm>.</para>
3043
<para>Go the smart way and provide the necessary information in a .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> file.
3044
Fortunately KService <indexterm remap="idx"><primary>KService</primary></indexterm> supports the necessary properties, like repository
3045
ids, activation mode and others.</para>
3050
<para>For the second point it's important that the .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> file is available for
3051
KRegistry <indexterm remap="idx"><primary>KRegistry</primary></indexterm>, by placing it in a directory which gets scanned by the registry.
3052
If your application has already a .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> file in the applnk tree for example,
3053
then you're fine with adding the necessary fields in there. Otherwise the
3054
directory named "services" (either system-wide or user-local) is the best place
3055
for it. If you provide the CORBA service information this way, then KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm>
3056
will automatically detect it and register it automatically at the IMR. This
3057
means that it is immediately available for KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> and thus to your client app.
3058
And since KRegistry <indexterm remap="idx"><primary>KRegistry</primary></indexterm> is such a cool thing :-) , you can do all this even at
3059
run-time, when kded <indexterm remap="idx"><primary>kded</primary></indexterm> is running. Just place the .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> file in one of the
3060
right directories for it and KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> will update the IMR on-the-fly. The
3061
same applies obviously for just deleted or modified .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> files, which will
3062
make KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> adjust the IMR. Now you might get the idea why this is the
3063
preferred way :-)) .</para>
3065
<para>Now that you know how to register CORBA services you will want to know how
3066
to "access" it. <literal remap="tt">activateService()</literal> is your friend here. Simply pass
3067
it the name of the service, the repository id of the server object and the
3068
object's tag and it will return you a functional object reference. That's all :-)</para>
3070
<para>Depending on the service's activation mode, KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> will either return a reference
3071
to an already running server or it will start a new instance.</para>
3073
<para>One note about the returned object reference: This is a virtual reference,
3074
which means that that server object is started when the first call is invoked
3075
on this reference, thus making your server get started "lazy", only on-demand.
3076
But that's just additional information, you don't have to deal and know about
3077
it at all. Just be happy with your functional object reference :-) .</para>
3079
<para>Want some examples? Here we go:</para>
3081
<para>This is how a .desktop <indexterm remap="idx"><primary>.desktop</primary></indexterm> file could look like, assuming that the commandline
3082
"--server" starts the app in CORBA server <indexterm remap="idx"><primary>CORBA server</primary></indexterm> mode:
3083
<programlisting>Name=MyApp
3085
CORBAExec=fooblah --server
3086
X-KDE-RepoIds=IDL:Foo/Blah:1.0#MyFoo
3087
X-KDE-ActivationMode=shared</programlisting>
3090
<para>If KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> "gets" this file, it will register the service and then you're
3091
able to do something like this:
3092
<programlisting> ...
3093
KActivator *activator = KdedInstance::self()->kactivator();
3095
CORBA::Object_var obj = activator->activateServer( "MyApp", "IDL:Foo/Blah:1.0", "MyFoo );
3096
...</programlisting>
3099
<para>The above example will either start a new fooblah instance or connect to a running
3102
<para>For further information please have a look at the examples in kdelibs/corba/tutorials/kded .
3103
The example application there registers the server manually via <literal remap="tt">registerService</literal> .</para>
3105
<para>Please note: The server <emphasis remap="bf">has</emphasis> to be started by kded <indexterm remap="idx"><primary>kded</primary></indexterm> in order to make KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm>
3106
return a reference to a running one. Executing "fooblah" from somewhere else
3107
will <emphasis remap="bf">not</emphasis> make KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> use it. This is a problem for persistent
3108
servers like KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm> for example. But there's a solution available, just read
3109
the next chapter about the KDE Naming Service :-) .</para>
3112
<sect1 id="knaming-knaming">
3113
<title>KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm></title>
3115
<para>The KDE Naming Service, KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm>, is also a very simple service, but it's pretty
3116
useful and in some cases a very nice solution to make a CORBA client connect to
3117
a persistent CORBA server <indexterm remap="idx"><primary>CORBA server</primary></indexterm>.</para>
3119
<para>With KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm> you can bind a freely chooseable name to a CORBA object. And since
3120
kded <indexterm remap="idx"><primary>kded</primary></indexterm> is system (session) wide available, your object becomes available for any
3121
client which is able to connect to kded <indexterm remap="idx"><primary>kded</primary></indexterm>.</para>
3123
<para>There's not much to explain here :-&}; , so I suggest having a look at the KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm>
3124
API, in <literal remap="tt"><indexterm remap="cdx"><primary><literal>knaming.h</literal></primary></indexterm>knaming.h</literal>.</para>
3126
<para>Example code can be, again, found in kdelibs/corba/tutorials/kded . Here's just
3127
a short real example situation:</para>
3129
<para>Just think of KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm>, that nice app providing your background desktop icons.
3130
It provides some functionality via CORBA, just have a look at kdesktop.idl to
3131
see what I'm talking about. Now the problem for KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm> is: How can it provide
3132
this service to other apps in the system? Writing an IOR <indexterm remap="idx"><primary>IOR</primary></indexterm> into some file is no
3133
clean solution IMHO, and using KActivator <indexterm remap="idx"><primary>KActivator</primary></indexterm> doesn't work because KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm> does not
3134
get started by kded <indexterm remap="idx"><primary>kded</primary></indexterm> but by the startkde script on KDE startup. So we find a better
3135
way and make KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm> register it's object at KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm>. This is done by the following
3137
<programlisting> ...
3138
KNaming *knaming = KdedInstance::self()->knaming();
3139
naming->bind( "KDesktop", kdesktop_object_here );
3140
...</programlisting>
3142
Well, I told you a lie ;) : KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm> does not really bind to "KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm>" but
3143
instead to "IDL:KDesktopIf:1.0" , but since there's no naming convention
3144
for the naming I have choosen a more readable name, IMHO of course :-) (don't
3145
mind me David :] ) . I personally prefer human readable names ;) , in contrary
3146
to repository ids with tags.</para>
3148
<para>Back to KNaming <indexterm remap="idx"><primary>KNaming</primary></indexterm> and KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm>: Now any client application, kfmclient for example,
3149
can "connect" to KDesktop <indexterm remap="idx"><primary>KDesktop</primary></indexterm>. Just like this:
3151
KNaming *knaming = KdedInstance::self()->knaming();
3153
CORBA::Object_var obj = knaming->resolve( "KDesktop" );
3154
KDesktopIf_var kdesky = KDesktopIf::_narrow( obj );
3155
kdesky->selectAll(); //let's confuse the user by selecting all icons ;-)
3156
...</programlisting>
3162
<title>DCOP: Desktop COmmunications Protocol</title>
3164
<para>Preston Brown <ulink url="mailto:pbrown@kde.org"><pbrown@kde.org></ulink></para>
3166
<para>Version 1.0, October 14, 1999</para>
3168
<para><emphasis>Howto for the KDE Desktop COmmunincations Protocol implementation</emphasis></para>
3170
<sect1 id="motivation-and-background">
3171
<title>Motivation and Background</title>
3173
<para>The motivation behind building a protocol like DCOP is simple. For
3174
the past year, we have been attempting to enable interprocess
3175
communication between KDE applications. KDE already has an extremely
3176
simple IPC mechanism called KWMcom, which is (was!) used for communicating
3177
between the panel and the window manager for instance. It is about as
3178
simple as it gets, passing messages via X Atoms. For this reason it
3179
is limited in the size and complexity of the data that can be passed
3180
(X atoms must be small to remain efficient) and it also makes it so
3181
that X is required. CORBA was thought to be a more effective IPC/RPC
3182
solution. However, after a year of attempting to make heavy use of
3183
CORBA in KDE, we have realized that it is a bit slow and memory
3184
intensive for simple use. It also has no authentication available.</para>
3186
<para>What we really needed was an extremely simple protocol with basic
3187
authorization, along the lines of MIT-MAGIC-COOKIE, as used by X. It
3188
would not be able to do NEARLY what CORBA was able to do, but for the
3189
simple tasks required it would be sufficient. Some examples of such
3190
tasks might be an application sending a message to the panel saying,
3191
"I have started, stop displaying the 'application starting' wait
3192
state," or having a new application that starts query to see if any
3193
other applications of the same name are running. If they are, simply
3194
call a function on the remote application to create a new window,
3195
rather than starting a new process.</para>
3198
<sect1 id="implementation">
3199
<title>Implementation</title>
3201
<para>DCOP is a simple IPC/RPC mechanism built to operate over sockets.
3202
Either unix domain sockets or tcp/ip sockets are supported. DCOP is
3203
built on top of the Inter Client Exchange (ICE) protocol, which comes
3204
standard as a part of X11R6 and later. It also depends on Qt, but
3205
beyond that it does not require any other libraries. Because of this,
3206
it is extremely lightweight, enabling it to be linked into all KDE
3207
applications with low overhead.</para>
3210
<title>Model</title>
3212
<para>The model is simple. Each application using DCOP is a client. They
3213
communicate to each other through a DCOP server, which functions like
3214
a traffic director, dispatching messages/calls to the proper
3215
destinations. All clients are peers of each other.</para>
3217
<para>Two types of actions are possible with DCOP: "send and forget"
3218
messages, which do not block, and "calls," which block waiting for
3219
some data to be returned.</para>
3221
<para>Any data that will be sent is serialized (marshalled, for you CORBA
3222
types) using the built-in QDataStream operators available in all of the
3223
Qt classes. This is fast and easy. Currently, there is no
3224
type checking or parameter checking available for RPC, but this may be
3225
provided at some time in the future in the form of a simple IDL-like
3226
compiler (NOTE: 5 days later the IDL compiler is already started;
3227
look in dcopidl/). Until that is available, you will have to code
3228
some things by hand that normally the compiler or CORBA take care of
3229
automatically, but it is not a lot of work.</para>
3232
<sect2 id="establishing-the-connection">
3233
<title>Establishing the Connection</title>
3235
<para>KApplication has gained a method called "KApplication::dcopClient()"
3236
which returns a pointer to a DCOPClient instance. The first time this
3237
method is called, the client class will be created. DCOPClients have
3238
unique identifiers attached to them which are based on what
3239
KApplication::name() returns. In fact, if there is only a single
3240
instance of the program running, the appId will be equal to
3241
KApplication::name().</para>
3243
<para>To actually enable DCOP communication to begin, you must use
3244
DCOPClient::attach(). This will attempt to attach to the DCOP server.
3245
If no server is found or there is any other type of error, attach()
3246
will return false. Applications which are DCOP-enabled should
3247
probably do something like this at startup time:</para>
3249
<para><programlisting>client = kApp->dcopClient();
3250
if (!client->attach()) {
3251
QMessageBox::error(this, i18n("Error connecting to DCOP server"),
3252
i18n("There was an error connecting to the Desktop\n"
3253
"communications server. Please make sure that\n"
3254
"the 'dcopserver' process has been started, and\n"
3255
"then try again.\n"));
3260
<para>After connecting with the server via DCOPClient::attach(), you need to
3261
register this appId with the server so it knows about you. Otherwise,
3262
you are communicating anonymously. Use the
3263
DCOPClient::registerAs(const QCString &&;name) to do so. In the simple
3266
* returns the appId that is actually registered, which _may_ be
3267
* different from what you passed
3269
appId = client->registerAs(kApp->name());</programlisting>
3272
<para>If you never retrieve the DCOPClient pointer from KApplication, the
3273
object will not be created and thus there will be no memory overhead.</para>
3275
<para>You may also detach from the server by calling DCOPClient::detach().
3276
If you wish to attach again you will need to re-register as well. If
3277
you only wish to change the ID under which you are registered, simply
3278
call DCOPClient::registerAs() with the new name.</para>
3281
<sect2 id="sending-data-to-a-remote-application">
3282
<title>Sending Data to a Remote Application</title>
3284
<para>To actually communicate, you have one of two choices. You may either
3285
call the "send" or the "call" method. Both methods require three
3286
identification parameters: an application identifier, a remote object,
3287
a remote function. Sending is asynchronous (i.e. it returns immediately)
3288
and may or may not result in your own application being sent a message at
3289
some point in the future. Then "send" requires one and "call" requires
3290
two data parameters.</para>
3292
<para>The remote object must be specified as an object hierarchy. That is,
3293
if the toplevel object is called "fooObject" and has the child
3294
"barObject", you would reference this object as "fooObject/barObject".
3295
Functions must be described by a full function signature. If the
3296
remote function is called "doIt", and it takes an int, it would be
3297
described as "doIt(int)". Please note that the return type is not
3298
specified here, as it is not part of the function signature (or at
3299
least the C++ understanding of a function signature). You will get
3300
the return type of a function back as an extra parameter to
3301
DCOPClient::call(). See the section on call() for more details.</para>
3303
<para>In order to actually get the data to the remote client, it must be
3304
"serialized" via a QDataStream operating on a QByteArray. This is how
3305
the data parameter is "built". A few examples will make clear how this
3308
<para>Say you want to call "doIt" as described above, and not block (or wait
3309
for a response). You will not receive the return value of the remotely
3310
called function, but you will not hang while the RPC is processed either.
3311
The return value of send() indicates whether DCOP communication succeeded
3314
<para><programlisting>QByteArray params;
3315
QDataStream stream(params, IO_WriteOnly);
3317
if (!client->send("someAppId", "fooObject/barObject", "QString doIt(int)",
3319
qDebug("there was some error using DCOP.");</programlisting>
3322
<para>OK, now let's say we wanted to get the data back from the remotely
3323
called function. You have to execute a call() instead of a send().
3324
The returned value will then be available in the data parameter "reply".
3325
The actual return value of call() is still whether or not DCOP
3326
communication was successful.</para>
3328
<para><programlisting>QByteArray params, reply;
3330
QDataStream stream(params, IO_WriteOnly);
3332
if (!client->call("someAppId", "fooObject/barObject", "doIt(int)",
3333
params, replyType, reply))
3334
qDebug("there was some error using DCOP.");
3336
QDataStream stream2(reply, IO_ReadOnly);
3337
if (replyType == "QString") {
3339
stream2 >> result;
3340
print("the result is: %s",result.latin1());
3342
qDebug("doIt returned an unexpected type of reply!");
3348
<sect2 id="receiving-data-via-dcop">
3349
<title>Receiving Data via DCOP</title>
3351
<para>Currently the only real way to receive data from DCOP is to multiply
3352
inherit from the normal class that you are inheriting (usually some
3353
sort of QWidget subclass or QObject) as well as the DCOPObject class.
3354
DCOPObject provides one very important method: DCOPObject::process().
3355
This is a pure virtual method that you must implement in order to
3356
process DCOP messages that you receive. It takes a function
3357
signature, QByteArray of parameters, and a reference to a QByteArray
3358
for the reply data that you must fill in.</para>
3360
<para>Think of DCOPObject::process() as a sort of dispatch agent. In the
3361
future, there will probably be a precompiler for your sources to write
3362
this method for you. However, until that point you need to examine
3363
the incoming function signature and take action accordingly. Here is
3364
an example implementation.</para>
3366
<para><programlisting>bool BarObject::process(const QCString &&;fun, const QByteArray &&;data,
3367
QCString &&;replyType, QByteArray &&;replyData)
3369
if (fun == "doIt(int)") {
3370
QDataStream stream(data, IO_ReadOnly);
3373
stream >> arg;
3374
res = self->doIt(arg);
3375
QDataStream stream2(replyData, IO_WriteOnly);
3376
stream2 << res;
3377
replyType = "QString";
3380
qDebug("unknown function call to BarObject::process()");
3388
<sect1 id="conclusion">
3389
<title>Conclusion</title>
3391
<para>Hopefully this document will get you well on your way into the world
3392
of inter-process communication with KDE! Please direct all comments
3393
and/or suggestions to Preston Brown <ulink url="mailto:pbrown@kde.org"><pbrown@kde.org></ulink>.</para>
3395
<sect2 id="performance-tests">
3396
<title>Performance Tests</title>
3398
<para>A few back-of-the-napkin tests folks:</para>
3401
<programlisting>#include <kapp.h>
3403
int main(int argc, char **argv)
3407
app = new KApplication(argc, argv, "testit");
3408
return app->exec();
3411
Compiled with:</para>
3413
<para>g++ -O2 -o testit testit.cpp -I$QTDIR/include -L$QTDIR/lib -lkdecore</para>
3415
<para>on Linux yields the following memory use statistics:
3416
<screen>VmSize: 8076 kB
3426
<para>If I create the KApplication's DCOPClient, and call attach() and
3427
registerAs(), it changes to this:</para>
3429
<para><screen>VmSize: 8080 kB
3439
<para>Basically it appears that using DCOP causes 100k more memory to be
3440
resident, but no more data or stack. So this will be shared between all
3441
processes, right? 100k to enable DCOP in all apps doesn't seem bad at
3444
<para>OK now for some timings. Just creating a KApplication and then exiting
3445
(i.e. removing the call to KApplication::exec) takes this much time:</para>
3447
<para>0.28user 0.02system 0:00.32elapsed 92&%;CPU (0avgtext+0avgdata 0maxresident)k
3448
0inputs+0outputs (1084major+62minor)pagefaults 0swaps</para>
3450
<para>I.e. about 1/3 of a second on my PII-233. Now, if we create our DCOP
3451
object and attach to the server, it takes this long:</para>
3453
<para>0.27user 0.03system 0:00.34elapsed 87&%;CPU (0avgtext+0avgdata 0maxresident)k
3454
0inputs+0outputs (1107major+65minor)pagefaults 0swaps</para>
3456
<para>I.e. about 1/3 of a second. Basically DCOPClient creation and attaching
3457
gets lost in the statistical variation ("noise"). I was getting times
3458
between .32 and .48 over several runs for both of the example programs, so
3459
obviously system load is more relevant than the extra two calls to
3460
DCOPClient::attach and DCOPClient::registerAs, as well as the actual
3461
DCOPClient constructor time.</para>
3466
<chapter id="copyright-0">
3467
<title>Copyright</title>
3470
KDevelop Copyright 1998, 1999, 2000 The KDevelop Team.
3472
This program is free software; you can redistribute it and/or modify
3473
it under the terms of the GNU General Public License as published by
3474
the Free Software Foundation; either version 2 of the License, or
3475
(at your option) any later version.
3477
This program is distributed in the hope that it will be useful,
3478
but WITHOUT ANY WARRANTY; without even the implied warranty of
3479
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3480
GNU General Public License for more details.
3482
You should have received a copy of the GNU General Public License
3483
along with this program; if not, write to the Free Software
3484
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3488
<para>Each chapter of this handbook contains the documentation of the according authors, therefore the copyright remains on the side of
3489
those. This handbook has been assembled by agreement with each author about the usage of his documentation. Reprint is therefore only
3490
allowed on agreement with the KDevelop Team and the authors of each chapter.</para>
3492
<para>KDevelop is Copyright 1998,1999,2000 The KDevelop Team.</para>
3494
<para>This handbook itself is part of the KDevelop Intergrated Development environment.</para>
3496
<para><link linkend="mini-HOWTO">The KDE Developer's mini-HOWTO</link> is copyright of David Sweet.<ulink url="mailto:dsweet@chaos.umd.edu"><dsweet@chaos.umd.edu></ulink></para>
3498
<para><link linkend="KOMOP">KDE KOM / OpenParts</link> is copyright of Torben Weis <ulink url="mailto:weis@kde.org"><weis@kde.org></ulink> and
3499
Bernd Wuebben <ulink url="mailto:wuebben@kde.org"><wuebben@kde.org></ulink></para>
3501
<para><link linkend="KOMHOWTO">Using KDE KOM / OpenParts HOWTO</link> and <link linkend="KDEDAEMON">The KDE Daemon</link> are copyright of Simon
3502
Hausmann <ulink url="mailto:hausmann@kde.org"><hausmann@kde.org></ulink></para>
3504
<para><link linkend="DCOP">DCOP: Desktop COmmunications Protocol</link> is copyright of Preston Brown <ulink url="mailto:pbrown@kde.org"><pbrown@kde.org></ulink></para>
3506
<appendix id="glossary">
3507
<title>Glossary</title>
3509
<para><variablelist>
3513
<para>Common Object Request Broker Architecture, standard introduced by the OMG for distributed components that can be used
3514
independently of platform, implementation and operating system. CORBA itself is only the standard which requires a corresponding
3515
implementation that fulfills the requirements of the standard. KDE uses the MICO implementation, which provides a C++ interface to
3516
CORBA services.</para>
3522
<para>Basic Object Adapter. Interface defined by the OMG, which offers fundamental operations for managing remote objects.</para>
3528
<para>Common Object Services. Collection of standard services to simplify developing standard applications. Naming, Event and
3529
Lifecycle-services are a part of the COS collection.</para>
3535
<para>Dynamic Invocation Interface, interface to execute dynamic invocations in opposition to static invocations (clent side)</para>
3539
<term>Dynamic Invocation</term>
3541
<para>Creation and execution of a request, whose signature is probably first known at runtime in opposition to
3542
static invocation.</para>
3548
<para>Dynamic Skeleton Interface. Server side in opposition to a DII.</para>
3554
<para>General-Inter-ORB-Protocol</para>
3560
<para>Internet-Inter-ORB-Protocol</para>
3566
<para>Implementation Repository</para>
3572
<para>Interoperable Object Reference. The reference is specificated in the two parts GIOP and IIOP.</para>
3578
<para>Interface Definition Language. C++-Syntax similar programming language to describe object interfaces. The implementation
3579
translates IDL's to their target programming language.</para>
3583
<term>Interface</term>
3585
<para>in CORBA, all exported methods and attributes of an object are called an interface, whereby these are defined in IDL.
3586
Elements which are not specified in the interface are not accessible by clients.</para>
3592
<para>Interoperability Profile</para>
3598
<para>free implementation of the CORBA standard. KDE's KOM/OpenParts technology is based on the MICO implementation.</para>
3604
<para>Object Management Architecture</para>
3610
<para>Object Management Group</para>
3616
<para>Object Request Broker, abstract name for the communication service between clients and remote objects.</para>
3622
<para>Portable Object Adapter. The POA extends the features the BOA provides; introduced in the CORBA 2.2 standard.</para>
3628
<![ %addindex; [ &docindex; ]]>
3635
sgml-general-insert-case: lower