[prev in list] [next in list] [prev in thread] [next in thread]
List: kfm-devel
Subject: Re: using qcom interfaces wit parts (was Re: Plugins for non-major Parts)
From: Simon Hausmann <hausmann () kde ! org>
Date: 2001-09-13 13:01:48
[Download RAW message or body]
On Thu, Sep 13, 2001 at 01:08:13PM +0200, Simon Hausmann wrote:
> Hi,
>
> I keep on thinking and thinking about it but I can't seem to find an obvious solution to
> the ownership problem...
>
> What I have in mind is a virtual QUnknownInterface *qcomInterface() method in KParts::Part,
> with a default implementation returning 0.
>
> A real implementation could look like this:
>
> QUnknownInterface *MyPart::qcomInterface()
> {
> Q_CREATE_INSTANCE( MyInterfaceImplementation )
> }
>
> Or in expanded form
>
> QUnknownInterface *MyPart::qcomInterface()
> {
> MyInterfaceImplementation *impl = new MyInterfaceImplementation;
> QUnknownInterface *result = 0;
> impl->queryInterface( IID_QUnknown, &result );
> return result;
> }
>
> The problem with this is that it's a bit wrong :) We don't really want to
> instantiate an interface implementation each time nor do we want to
> return an already ref'ed object (and we can't just return new MyInterfaceImpl
> because it requires casting in case of multiple inheritance and that's
> already implemented in MyInterfaceImpl's queryInterface, so we should re-use
> that)
>
> So what we could do is to add a level of indirection:
>
> (non-virtual!)
> QUnknownInterface *Part::qcomInterface()
> {
> if ( !d->m_qcomInterface )
> d->m_qcomInterface = createQComInterface();
> return d->m_qcomInterface;
> }
>
> With d->m_qcomInterface being a QUnknownInterface * and with
> createQComInterface() being a virtual factory method which does
> the above Q_CREATE_INSTANCE. Also we would have to do
>
> Part::~Part()
> {
> ...
> if ( d->m_qcomInterface )
> d->m_qcomInterface->release();
> ...
> }
>
> for proper refcounting (the factory returns an initial object with
> refcount == 1, due to the queryInterface call, so we have to
> deref)
>
> The main problem I have with that is that it means that this looks
> nice from a kparts point of view, but it means there's an ugly
> side-effect from the component implementation point of view:
> The component destructor (the one implementation the QUI based interfaces)
> is likely to be called from the KParts::Part::~Part() destructor.
> I would quite often expect a component implementation to either
>
> a) depend on the part component, by having a pointer to it and
> calling methods on it
>
> or
>
> b) be the part itself, using multiple inheritance.
>
> The problem with a) is that it means that the component destructor
> has to be _very_ careful about not calling anything on the part,
> because it's too late (we're called from the ~Part dtor already) .
>
> The problem with b) is that it means that we will never get
> deleted because the Part baseclass holds a reference to itself.
>
>
> So I for one am a bit lost how to solve this in a clean way. I think it
> is definitely desirable to have support for pure abstract interfaces
> to allow writing plugins without a binary library dependency. And for
> that it would just make sense to re-use QUI (re-inventing that wheel
> would be stupid IMHO) . Also it would make sense IMHO if we would have
> a method to discover/retrieve an initial QUI object in our base
> classes/interfaces, KParts::Part so to say (well, in PartBase in fact,
> to automatically have it in MainWindow and KoView, too, but that's
> unrelated to the actual above described ownership problem) .
>
> (in addition we have the problem of library unloading, described in
> the previous mail, which doesn't seem easy to me either, but I might
> be missing something)
...hm, another idea:
(virtual)
QRESULT Part::queryQComInterface( const QUuid &iid, QUnknownInterface **iface )
{
*iface = 0;
return QS_FALSE; // (or something like that ;)
}
Then a part can implement it as:
QRESULT MyPart::queryQComInterface( const QUuid &iid, QUnknownInterface **iface )
{
if ( !m_iface )
{
m_iface = new MyInterfaceImplementation;
m_iface->addRef();
}
return m_iface->queryInterface( iid, iface );
}
MyPart::MyPart()
: KParts::Part( ... ), m_iface( 0 )
{
...
}
MyPart::~MyPart()
{
if ( m_iface )
m_iface->release();
}
For initial discovery a client then just does something along the lines of
void MyPlugin::foo()
{
KParts::Part *part = dynamic_cast<KParts::Part *>( parent() );
if ( !part ) return; // something really went wrong...
QInterfacePtr<MyPluginInterface> iface;
if ( part->queryQComInterface( IID_MyPlugin, &iface ) != QS_OK )
return;
doIt( iface );
}
This solves a) and b) in such a way that the part implementation has full control.
The disadvantage is that queryQComInterface violates the five principles of
QCom's queryInterface (see QUI docu) . In a rather rough way, I admit :)
Maybe that could be expressed by choosing a different naming, maybe something along
the lines of queryInitialQComInterface?
Thoughts, anyone?
(the overall goal for that is to solve Kurt's library dependency problem when writing
plugins then)
Simon
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic