// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// The client-side representation of a WsGraphic artwork
//
//
#include <w32std.h>
#include "../SERVER/w32cmd.h"
#include "w32comm.h"
#include "CLIENT.H"
#include <s32mem.h>
#include <Graphics/WSGRAPHICDRAWERINTERFACE.H>
NONSHARABLE_STRUCT(CWsGraphic::CPimpl): public CBase, public MWsClientClass
/** @internalComponent @released */
{
friend class CWsGraphic;
enum
{
/** is registered in the graphic manager's array */
ERegistered = 0x01,
/** has a peer CWsGraphicDrawer on the server */
EHasPeer = 0x02
};
CPimpl(CWsGraphic& aGraphic);
~CPimpl();
void ConstructL(); //LeaveScan: Member of macroised structure declaration.
CManager* iManager;
TInt WriteCreateGraphic(TWsClCmdCreateGraphic& aCreateGraphic,const TDesC8& aData,TInt aWsHandle) const;
CWsGraphic& iGraphic;
TWsGraphicId iId;
TUint iFlags;
MWsObjectProvider* iExt;
};
LOCAL_C void MWsGraphicMessageAllocRelease(TAny* aAny)
{
MWsGraphicMessageAlloc::MBuffer* buf = static_cast<MWsGraphicMessageAlloc::MBuffer*>(aAny);
if(buf)
{
buf->Release();
}
}
NONSHARABLE_CLASS(CWsGraphic::CManager): private CActive, public RWsSession
/** Client-side manager singleton for marshalling messages for all CWsGraphics owned by a client
@publishedAll
@released
*/ {
public:
static CManager* StaticL(); //LeaveScan: Member of macroised structure declaration.
// used by CWsGraphic
void AddL(CWsGraphic* aGraphic); //LeaveScan: Member of macroised structure declaration.
void Replace(CWsGraphic* aGraphic);
void Remove(CWsGraphic* aGraphic);
CWsGraphic* Find(const TWsGraphicId& aId);
void Inc();
void Dec();
RWsBuffer* Buffer();
void ScheduleFlush();
private:
CManager();
~CManager();
void ConstructL(); //LeaveScan: Member of macroised structure declaration.
void Queue();
void RunL(); //LeaveScan: Member of macroised structure declaration.
void DoCancel();
static TInt GraphicCompare(const CWsGraphic& aFirst,const CWsGraphic& aSecond);
static TInt FlushOnIdle(TAny* aArg);
private:
TInt iRefCount;
RPointerArray<CWsGraphic> iArray;
CIdle* iFlusher;
TBool iFlushScheduled;
};
// TWsGraphicId \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C TWsGraphicId::TWsGraphicId(TUid aUid):
/** Construct a UID
@param aUid UID of the graphic artwork.
@publishedAll @released
*/ iFlags(EWsGraphicIdUid), iId(aUid.iUid)
{
}
EXPORT_C TWsGraphicId::TWsGraphicId(TInt aId):
/** Construct a transient Id
@publishedAll @released
*/ iFlags(EWsGraphicIdTransient), iId(aId)
{
}
/**
Copy constructor.
@param aCopy Graphic artwork Id.
*/
EXPORT_C TWsGraphicId::TWsGraphicId(const TWsGraphicId& aCopy):
iFlags(aCopy.iFlags), iId(aCopy.iId)
{
}
EXPORT_C TUid TWsGraphicId::Uid() const
/** Returns UID.
@return UID of graphic artwork. KNullUid if graphic artwork is transient.
@publishedAll @released
*/ {
if(IsUid())
{
return TUid::Uid(iId);
}
return KNullUid;
}
EXPORT_C TBool TWsGraphicId::IsUid() const
/** Identifies whether graphic artwork is non-transient.
@return ETrue if graphic artwork is non-transient.
@publishedAll @released
*/ {
return (iFlags & EWsGraphicIdUid);
}
EXPORT_C void TWsGraphicId::Set(TUid aUid)
/** Set to be a UID
@publishedAll @released
*/ {
iId = aUid.iUid;
iFlags = EWsGraphicIdUid;
}
EXPORT_C TInt TWsGraphicId::Id() const
/** Returns the transient Id.
@return Id of transient graphic artwork. Zero if graphic artwork is non-transient.
@publishedAll @released
*/ {
if(IsId())
{
return iId;
}
return 0;
}
EXPORT_C TBool TWsGraphicId::IsId() const
/** Identifies whether graphic artwork is transient.
@return ETrue if graphic artwork is transient.
@publishedAll @released
*/ {
return (iFlags & EWsGraphicIdTransient);
}
EXPORT_C void TWsGraphicId::Set(TInt aId)
/** Set to be a transient Id
@publishedAll @released
*/ {
iId = aId;
iFlags = EWsGraphicIdTransient;
}
EXPORT_C TInt TWsGraphicId::Compare(const TWsGraphicId& aOther) const
/** Compares another Id with this one.
@return 0 if the other Id is identical, else -1 if the other Id is to greater than or 1 if the other Id is less than
@publishedAll @released
*/ {
if(iId < aOther.iId)
{
return -1;
}
else if(iId > aOther.iId)
{
return 1;
}
// else we have to compare the iIsUid flag too; again, expect it to be a match 99.99% of these times
else if(IsUid() == aOther.IsUid())
{
return 0;
}
// collisions of id but not iIsUid are going to be really really rare
else if(IsUid())
{
return 1;
}
else
{
return -1;
}
}
// CWsGraphicManager \\\\\\\\\\\\\\\\\\\\\\\\
CWsGraphic::CManager* CWsGraphic::CManager::StaticL()
{
CManager* singleton = RWsBuffer::WsGraphicManager();
if(!singleton)
{
singleton = new(ELeave) CManager;
CleanupStack::PushL(singleton);
singleton->ConstructL();
CleanupStack::Pop(singleton);
__ASSERT_DEBUG(singleton == RWsBuffer::WsGraphicManager(),Panic(EW32PanicGraphicInternal));
}
return singleton;
}
CWsGraphic::CManager::~CManager()
{
__ASSERT_DEBUG(!ResourceCount(),Panic(EW32PanicGraphicInternal));
__ASSERT_DEBUG(!iArray.Count(),Panic(EW32PanicGraphicOrphaned));
Close();
__ASSERT_DEBUG(!RWsBuffer::WsGraphicManager(),Panic(EW32PanicGraphicInternal));
iArray.Close();
delete iFlusher;
}
CWsGraphic::CManager::CManager(): CActive(CActive::EPriorityStandard)
{
}
void CWsGraphic::CManager::ConstructL()
{
User::LeaveIfError(Connect());
iBuffer->SetWsGraphicManager(this);
CActiveScheduler::Add(this);
iFlusher = CIdle::NewL(CActive::EPriorityIdle);
}
void CWsGraphic::CManager::Inc()
{
iRefCount++;
}
void CWsGraphic::CManager::Dec()
{
if(!--iRefCount)
{
delete this;
}
}
RWsBuffer* CWsGraphic::CManager::Buffer()
{
return iBuffer;
}
// used by CWsGraphic
void CWsGraphic::CManager::AddL(CWsGraphic* aGraphic)
/** Leaves if the graphic couldn't be added to the list
@internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(!(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
iArray.InsertInOrderL(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= iArray.FindInOrder(aGraphic,GraphicCompare),Panic(EW32PanicGraphicInternal));
aGraphic->iPimpl->iFlags |= CWsGraphic::CPimpl::ERegistered;
Queue();
}
void CWsGraphic::CManager::Replace(CWsGraphic* aGraphic)
/** @internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(!(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
const TInt idx = iArray.FindInOrder(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= idx,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(iArray[idx]->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered,Panic(EW32PanicGraphicInternal));
iArray[idx]->iPimpl->iFlags &= ~CWsGraphic::CPimpl::ERegistered;
iArray[idx] = aGraphic;
iArray[idx]->iPimpl->iFlags |= CWsGraphic::CPimpl::ERegistered;
Queue();
}
void CWsGraphic::CManager::Remove(CWsGraphic* aGraphic)
/** @internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered,Panic(EW32PanicGraphicInternal));
const TInt idx = iArray.FindInOrder(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= idx,Panic(EW32PanicGraphicInternal));
iArray[idx]->iPimpl->iFlags &= ~CWsGraphic::CPimpl::ERegistered;
iArray.Remove(idx);
if(!iArray.Count())
{
Cancel();
}
}
CWsGraphic* CWsGraphic::CManager::Find(const TWsGraphicId& aId)
/** Find the active artwork identified by the Id
@return NULL if no active artwork has the Id
@publishedAll @released */
{
/* RPointerArray can only FindInOrder other T*, which is a needless shame. Therefore this search is
dumb sequential */
const TInt count = iArray.Count();
for(TInt i=0; i<count; i++)
{
CWsGraphic* graphic = iArray[i];
__ASSERT_ALWAYS(graphic && graphic->iPimpl && (graphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
const TWsGraphicId& candidate = graphic->Id();
if(0 == candidate.Compare(aId))
{
// found
__ASSERT_DEBUG(i == iArray.FindInOrder(graphic,GraphicCompare),Panic(EW32PanicGraphicInternal));
return graphic;
}
}
// not found
return NULL;
}
void CWsGraphic::CManager::Queue()
{
if(!IsActive())
{
GraphicMessageReady(&iStatus);
SetActive();
}
}
void CWsGraphic::CManager::RunL()
{
if(0 < iStatus.Int())
{
// a message to fetch!
const TInt msgLen = iStatus.Int();
TPtr8 buf(NULL,0);
MWsGraphicMessageAlloc* allocator = NULL;
MWsGraphicMessageAlloc::MBuffer* theirBuf = NULL;
HBufC8* ourBuf = HBufC8::New(msgLen);
if(ourBuf)
{
CleanupStack::PushL(ourBuf);
buf.Set(ourBuf->Des());
}
else // try to see if the destination CWsGraphic can allocate for us
{
const TInt handle = GraphicFetchHeaderMessage();
CWsGraphic* dest = reinterpret_cast<CWsGraphic*>(handle & ~0x03);
// check if it's valid
if(KErrNotFound != iArray.Find(dest) && dest->iPimpl && dest->iPimpl->iExt)
{
// check if the client is able to alloc memory for us
allocator = dest->iPimpl->iExt->ObjectInterface<MWsGraphicMessageAlloc>();
if(allocator)
{
// allocate memory
theirBuf = allocator->Alloc(msgLen);
if(theirBuf)
{
CleanupStack::PushL(TCleanupItem(MWsGraphicMessageAllocRelease,theirBuf));
buf.Set(theirBuf->Buffer());
}
}
}
}
if(!ourBuf && !theirBuf)
{
GraphicMessageCancel();
GraphicAbortMessage(KErrNoMemory);
}
else
{
GetGraphicMessage(buf);
// decode header and body
RDesReadStream in(buf);
in.PushL();
const TInt header = in.ReadInt32L();
__ASSERT_COMPILE(sizeof(header) == sizeof(TInt32));
const TInt clientHandle = (header & ~0x03);
const TInt msgType = (header & 0x03);
const TPtr8 body = buf.MidTPtr(sizeof(header));
// dispatch
CWsGraphic* dest = (CWsGraphic*)clientHandle;
if(KErrNotFound != iArray.Find(dest))
{
switch(msgType)
{
case EWsGraphMessageTypeUser:
dest->HandleMessage(body);
break;
default:
Panic(EW32PanicGraphicInternal);
}
}
// done
in.Pop();
}
if(ourBuf)
{
CleanupStack::PopAndDestroy(ourBuf);
}
else if(theirBuf)
{
CleanupStack::PopAndDestroy(theirBuf);
}
// done, wait for next message
Queue();
}
}
void CWsGraphic::CManager::DoCancel()
{
GraphicMessageCancel();
}
TInt CWsGraphic::CManager::GraphicCompare(const CWsGraphic& aFirst,const CWsGraphic& aSecond)
/** Compares two graphics for id equality
@internalComponent
@released
*/ {
return aFirst.Id().Compare(aSecond.Id());
}
void CWsGraphic::CManager::ScheduleFlush()
/** Request to schedule flush when idle
@internalComponent
@released
*/
{
if (iFlushScheduled)
return;
iFlushScheduled = ETrue;
iFlusher->Start(TCallBack(CWsGraphic::CManager::FlushOnIdle,this));
}
TInt CWsGraphic::CManager::FlushOnIdle(TAny* aArg)
/** Flush buffer when idle and there is outstanding data in it
@internalComponent
@released
*/
{
CWsGraphic::CManager* mgr = reinterpret_cast<CWsGraphic::CManager*>(aArg);
if (mgr)
{
mgr->iFlushScheduled = EFalse;
if (mgr->iBuffer && !mgr->iBuffer->IsEmpty())
mgr->iBuffer->Flush();
}
return 0; // complete
}
// CWsGraphic::CPimpl \\\\\\\\\\\\\\\\\\\\\\\\
CWsGraphic::CPimpl::CPimpl(CWsGraphic& aGraphic):
iGraphic(aGraphic), iId(TWsGraphicId::EUninitialized)
{
}
CWsGraphic::CPimpl::~CPimpl()
{
if(iManager)
{
iManager->Dec();
}
}
void CWsGraphic::CPimpl::ConstructL()
{
iManager = CManager::StaticL();
iManager->Inc();
iBuffer = iManager->Buffer();
}
TInt CWsGraphic::CPimpl::WriteCreateGraphic(TWsClCmdCreateGraphic& aCreateGraphic,const TDesC8& aData,TInt aWsHandle) const
/** Writes the CreateGraphic message to the server. If the data will not fit in the buffer, uses remote-read
@internalComponent @released */
{
aCreateGraphic.iDataLen = aData.Size();
aCreateGraphic.iRemoteReadData = ((aData.Size()+sizeof(aCreateGraphic))>(TInt)(iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(aCreateGraphic.iRemoteReadData)
{
return iBuffer->WriteReplyByProvidingRemoteReadAccess(aWsHandle,EWsClOpCreateGraphic,&aCreateGraphic,sizeof(aCreateGraphic),&aData);
}
else if(aCreateGraphic.iDataLen)
{
return iBuffer->WriteReplyWs(&aCreateGraphic,sizeof(aCreateGraphic),aData.Ptr(),aData.Size(),EWsClOpCreateGraphic);
}
else
{
return iBuffer->WriteReplyWs(&aCreateGraphic,sizeof(aCreateGraphic),EWsClOpCreateGraphic);
}
}
// CWsGraphic \\\\\\\\\\\\\\\\\\\\\\\\
/**
Default Constructor.
*/
EXPORT_C CWsGraphic::CWsGraphic()
{
}
/**
Destructor.
*/
EXPORT_C CWsGraphic::~CWsGraphic()
{
Destroy();
delete iPimpl;
}
/**
Completes construction of the baseclass. All the overloaded BaseConstructL() methods
should invoke this method to complete the construction of the baseclass.
*/
void CWsGraphic::BaseConstructL()
{
iPimpl = new(ELeave) CPimpl(*this);
iPimpl->ConstructL();
}
EXPORT_C void CWsGraphic::BaseConstructL(TUid aUid,TUid aType,const TDesC8& aData)
/**
Constructs a piece of non-transient graphic artwork.
@capability ProtServ
@param aUid Graphic artwork UID.
@param aType Graphic artwork type.
@param aData User specific data.
*/ {
BaseConstructL();
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicIdUid;
createGraphic.iId = aUid.iUid;
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
User::LeaveIfError(ret);
iPimpl->iWsHandle=ret;
iPimpl->iId = aUid;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->AddL(this);
}
EXPORT_C void CWsGraphic::BaseConstructL(TUid aType,const TDesC8& aData)
/**
Constructs a piece of transient graphic artwork.
@param aType Graphic artwork type.
@param aData User specific data.
*/
{
BaseConstructL();
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicIdTransient;
createGraphic.iId = 0;
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
User::LeaveIfError(ret);
iPimpl->iWsHandle = ret;
// fetch id from server
TPckgBuf<TWsClCmdGdGetId> cmd;
User::LeaveIfError(iPimpl->WriteReplyP(TWriteDescriptorType(&cmd),EWsGdOpGetGraphicId));
if(cmd().iIsUid)
{
__DEBUG_ONLY(Panic(EW32PanicGraphicInternal));
User::Leave(KErrGeneral);
}
iPimpl->iId = cmd().iId;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->AddL(this);
}
EXPORT_C void CWsGraphic::BaseConstructL(const TWsGraphicId& aReplace,TUid aType,const TDesC8& aData)
/**
Atomically replace the artwork that already exists with this artwork.
If failure to properly construct the replacement artwork occurs, the replacee artwork will remain
@param aReplace Graphic artwork which will be replaced.
@param aType New graphic artwork type.
@param aData User specific data.
*/
{
BaseConstructL();
CWsGraphic* dup = iPimpl->iManager->Find(aReplace);
if(!dup || !dup->iPimpl)
{
Panic(EW32PanicGraphicInternal);
}
const TUint flags = aReplace.IsUid()?EWsGraphicIdUid:EWsGraphicIdTransient;
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicReplace|flags;
createGraphic.iId = aReplace.IsUid()?aReplace.Uid().iUid:aReplace.Id();
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
if(0 > ret)
{
User::Leave(ret);
}
iPimpl->iWsHandle = ret;
iPimpl->iId = aReplace;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->Replace(this);
// when WriteCreateGraphic succeeds, the replacee drawer has already been destroyed serverside
// so this cleanup is not quite the same as Destroy(), as it doesn't free server side
// coverity[var_deref_op]
dup->iPimpl->iWsHandle = 0;
dup->OnReplace();
dup->iPimpl->iFlags &= ~CPimpl::EHasPeer;
}
/**
Shares the graphic artwork with all the client sessions.
Sharing globally trumps explicit shares.
@return KErrNone if the graphic is globally shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::ShareGlobally()
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(EWsGdOpShareGlobally);
}
/**
Prevents this graphic artwork from being shared with all the client sessions.
A graphic artwork that isn't shared explicitly is only available to clients it
has been explicitly shared with using Share().
@return KErrNone if the graphic is not globally shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::UnShareGlobally()
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(EWsGdOpUnShareGlobally);
}
/**
Explicitly shares this graphic artwork with client sessions with the specified Secure ID.
@param aClientId the Secure ID of the client sessions to share with.
@return KErrNone If the graphic artwork was shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::Share(TSecureId aClientId)
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(&aClientId,sizeof(TSecureId),EWsGdOpShare);
}
/**
Stops this graphic artwork from being shared with all client sessions with the specific Secure ID.
ShareGlobally() trumps explicit sharing.
@param aClientId the Secure ID of the client sessions to not share with
@return KErrNone if the graphic artwork is no longer shared, KErrNotFound if the graphic was not shared anyway, else one of the system-wide error codes
*/
EXPORT_C TInt CWsGraphic::UnShare(TSecureId aClientId)
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(&aClientId,sizeof(TSecureId),EWsGdOpUnShare);
}
/**
Returns graphic artwork Id.
@return Graphic artwork Id. KNullWsGraphicId if graphic artwork is not active.
*/
EXPORT_C const TWsGraphicId& CWsGraphic::Id() const
{
if(IsActive())
{
return iPimpl->iId;
}
else
{
// fallback
static const TInt KNullWsGraphicId[4] = //binary compatible with TWsGraphicId
{
0, 0, 0, 0
};
__ASSERT_COMPILE(sizeof(KNullWsGraphicId) == sizeof(TWsGraphicId));
return reinterpret_cast<const TWsGraphicId&>(KNullWsGraphicId);
}
}
/**
Checks whether a peer of this graphic artwork has been fully constructed on the server.
@return ETrue if this graphic artwork has a peer CWsGraphic on the server.
*/
EXPORT_C TBool CWsGraphic::IsActive() const
{
return (iPimpl && iPimpl->iWsHandle && (iPimpl->iFlags & CPimpl::EHasPeer));
}
/**
Derived class can override this method to provide custom operations when the client is closed.
*/
EXPORT_C void CWsGraphic::OnClientClose()
{
}
/**
Sends message to this graphic artwork peer on the server.
@param aData User specific data.
*/
EXPORT_C void CWsGraphic::SendMessage(const TDesC8& aData) const
{
TWsClCmdGdSendMessage cmd;
cmd.iDataLen = aData.Size();
__ASSERT_DEBUG(cmd.iDataLen, Panic(EW32PanicGraphicNullData));
cmd.iRemoteReadData = ((aData.Size()+sizeof(cmd))>(TInt)(iPimpl->iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(cmd.iRemoteReadData)
{
iPimpl->WriteReplyByProvidingRemoteReadAccess(&cmd,sizeof(cmd),&aData,EWsGdOpSendMsg);
//ignore return value!
}
else
{
iPimpl->Write(&cmd,sizeof(cmd),aData.Ptr(),aData.Size(),EWsGdOpSendMsg);
}
}
EXPORT_C TInt CWsGraphic::SendSynchronMessage(const TDesC8& aData) const
{
TWsClCmdGdSendMessage cmd;
cmd.iDataLen = aData.Size();
__ASSERT_DEBUG(cmd.iDataLen, Panic(EW32PanicGraphicNullData));
cmd.iRemoteReadData = ((aData.Size()+sizeof(cmd))>(TInt)(iPimpl->iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(cmd.iRemoteReadData)
{
return iPimpl->WriteReplyByProvidingRemoteReadAccess(&cmd,sizeof(cmd),&aData,EWsGdOpSendSynchronMsg);
}
else
{
return iPimpl->WriteReply(&cmd,sizeof(cmd),aData.Ptr(),aData.Size(),EWsGdOpSendSynchronMsg);
}
}
/**
Flushes window server command buffer
@return One of system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::Flush() const
{
return iPimpl->iBuffer->Flush();
}
EXPORT_C void CWsGraphic::Destroy()
/** Destroys the corresponding CWsGraphicDrawer instance on the server
@released
@publishedAll
*/ {
if(iPimpl && (iPimpl->iFlags & CPimpl::ERegistered))
{
iPimpl->iManager->Remove(this);
}
if(IsActive()) // if iPimpl==NULL, IsActive() returns false
{
__ASSERT_DEBUG(iPimpl != NULL, Panic(EW32PanicGraphicInternal));
iPimpl->Write(EWsGdOpFree);
iPimpl->iWsHandle = 0;
iPimpl->iFlags &= ~CPimpl::EHasPeer;
iPimpl->iManager->ScheduleFlush();
}
}
EXPORT_C void CWsGraphic::SetGraphicExtension(MWsObjectProvider* aExt)
{
iPimpl->iExt = aExt;
}
EXPORT_C RWsSession& CWsGraphic::Session()
{
return *iPimpl->iManager;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved1()
{
return KErrNotSupported;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved2()
{
return KErrNotSupported;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved3()
{
return KErrNotSupported;
}
// TWsGraphicMsgFixedBase \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C TWsGraphicMsgFixedBase::TWsGraphicMsgFixedBase(TUid aTypeId,TInt aSizeOfDerived):
/** Protected constructor for subclasses to call
@param aTypeId The UID representing this type of data
@param aSizeOf The size of the derived class
Example:
@code
TMyDerivedFixedMsg::TMyDerivedFixedMsg(): TWsGraphicMsgFixedBase(KUidMyDerivedType,sizeof(TMyDerivedFixedMsg)), ...
@endcode
*/ iTypeId(aTypeId), iSize(aSizeOfDerived-sizeof(TWsGraphicMsgFixedBase))
{
__ASSERT_COMPILE(sizeof(*this) == (sizeof(TInt32)*2));
}
EXPORT_C TPtrC8 TWsGraphicMsgFixedBase::Pckg() const
/** @return this fixed message as a descriptor so that it can be passed as draw data in the CWindowGc::DrawWsGraphic command directly if only one such message is to be sent
*/ {
return TPtrC8(reinterpret_cast<const TUint8*>(this),sizeof(*this) + iSize);
}
EXPORT_C TUid TWsGraphicMsgFixedBase::TypeId() const
/** @return the UID identifying the type of the data that follows */
{
return iTypeId;
}
EXPORT_C TInt TWsGraphicMsgFixedBase::Size() const
/** @return the size of the derived class (not including this fixed base class size) */
{
return iSize;
}
// RWsGraphicMsgBuf \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C RWsGraphicMsgBuf::RWsGraphicMsgBuf()
/** Default Constructor */
{
}
TInt RWsGraphicMsgBuf::IntAt(TInt aOfs) const
/** @internalComponent @released */
{
if((aOfs < 0) || ((aOfs+sizeof(TInt)) > Length()))
{
Panic(EW32PanicGraphicBadBuffer);
}
TInt ret;
memcpy(&ret,Ptr()+aOfs,sizeof(TInt));
return ret;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,const TDesC8& aData)
/** Append a descriptor as data
@param aTypeId the type of the message to append
@param aData arbitrary length data consisting of the whole message
@return KErrNone if successful, else a system-wide error code
*/ {
TInt err = ExpandForAppend(aData.Length());
if (err)
{
return err;
}
WriteHeader(aTypeId,aData.Length());
// append data
Insert(Length(),aData);
return KErrNone;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,const TDesC16& aData)
/** Append a descriptor as data
@param aTypeId the type of the message to append
@param aData arbitrary length data consisting of the whole message
@return KErrNone if successful, else a system-wide error code
*/ {
TPtr8 data(NULL,0);
TInt err = Append(aTypeId,aData.Size(),data);
if (err)
{
return err;
}
// append data
data.Copy(reinterpret_cast<const TUint8*>(aData.Ptr()),aData.Size());
return KErrNone;
}
TInt RWsGraphicMsgBuf::ExpandForAppend(TInt aDataLen)
/** @internalComponent @released */
{
__ASSERT_COMPILE(sizeof(TInt) == sizeof(TInt32));
const TInt required = (sizeof(TUid) + sizeof(TInt) + aDataLen);
if(MaxLength() < (Length() + required))
{
TInt err = ReAlloc(Length()+required);
if(KErrNone != err)
{
return err;
}
}
return KErrNone;
}
void RWsGraphicMsgBuf::WriteHeader(TUid aTypeId,TInt aLen)
/** @internalComponent @released */
{
__ASSERT_COMPILE(sizeof(TInt) == sizeof(TInt32));
// append header
TPckgBuf<TInt32> i(aTypeId.iUid);
Insert(Length(),i);
i() = aLen;
Insert(Length(),i);
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,TInt aLen,TPtr8& aPtr)
/** Append a message of the specified length and type, and return a pointer to
allow client code to modify the message.
aPtr is only set if the append succeeds.
aPtr is only valid until the next message is appended to the buffer.
@param aTypeId the type of the message to append
@param aLen the length of the message to be reserved
@param aPtr a modifiable descriptor to be used by the client code to write into the message body
@return KErrNone if successful, else a system-wide error code
*/ {
TInt err = ExpandForAppend(aLen);
if (err)
{
return err;
}
WriteHeader(aTypeId,aLen);
// set aPtr
TInt usedLen = Length();
SetLength(usedLen+aLen);
aPtr.Set(MidTPtr(usedLen,aLen));
aPtr.Fill('_'); // prettier when debugging, but want consistant behaviour in release builds
aPtr.Zero();
return KErrNone;
}
EXPORT_C void RWsGraphicMsgBuf::Remove(TInt aIndex)
/** Remove a message from the buffer
@panic if the index is out of bounds
@param aIndex the ordinal position of message to be removed
*/ {
if((aIndex < 0) || (aIndex >= Count()))
{
Panic(EW32PanicGraphicBadBuffer);
}
TPtrC8 ptr = Data(aIndex);
const TInt ofs = (ptr.Ptr()-(sizeof(TInt)*2)-Ptr());
Delete(ofs,ptr.Length() + (sizeof(TInt)*2));
}
EXPORT_C TInt RWsGraphicMsgBuf::Count() const
/** Returns the number of messages in the buffer
@return the number of messages in the buffer
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
if(ofs != length)
{
Panic(EW32PanicGraphicBadBuffer);
}
return count;
}
EXPORT_C TUid RWsGraphicMsgBuf::TypeId(TInt aIndex) const
/** Returns the Type ID of a message in the buffer
@param aIndex the ordinal position of the message
@return the Type ID of the message
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return TUid::Uid(IntAt(ofs));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return KNullUid; //dumb compiler
}
EXPORT_C TPtrC8 RWsGraphicMsgBuf::Data(TInt aIndex) const
/** Returns a non-modifiable descriptor of a message body in the buffer
@param aIndex the ordinal position of the message
@return the message body
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return Mid(ofs+(sizeof(TInt)*2),IntAt(ofs+sizeof(TInt)));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return TPtrC8(KNullDesC8()); //dumb compiler
}
EXPORT_C TPtr8 RWsGraphicMsgBuf::Data(TInt aIndex)
/** Returns a modifiable descriptor of a message body in the buffer
The returned TPtr8 is only valid until the next message is appended to the buffer.
@param aIndex the ordinal position of the message
@return the message body
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return MidTPtr(ofs+(sizeof(TInt)*2),IntAt(ofs+sizeof(TInt)));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return TPtr8(NULL,0); //dumb compiler
}
EXPORT_C const TDesC8& RWsGraphicMsgBuf::Pckg() const
/** Returns the message buffer as a descriptor. Example:
@code
RWsGraphicMsgBuf msgBuf;
msgBuf.Append(...);
...
TWsGraphicId id(...);
SystemGc().DrawWsGraphic(id,Rect(),msgBuf.Pckg());
msgBuf.Close();
@endcode
@see CWindowGc::DrawWsGraphic
@see CCoeControl::Draw
@return the message buffer to be attached a command to draw a CWsGraphic
*/ {
return *this;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(const TWsGraphicMsgFixedBase& aMsg)
/** Append a fixed-size message
@param aMsg the fixed-size message to append
@return KErrNone if successful, else a system-wide error code
*/ {
__ASSERT_COMPILE(sizeof(TWsGraphicMsgFixedBase) == (sizeof(TInt)*2));
TInt err = ExpandForAppend(aMsg.Size());
if (err)
{
return err;
}
// append data
RBuf8::Append(reinterpret_cast<const TUint8*>(&aMsg),sizeof(TWsGraphicMsgFixedBase) + aMsg.Size());
Count();
return KErrNone;
}
EXPORT_C void RWsGraphicMsgBuf::GetFixedMsg(TWsGraphicMsgFixedBase& aMsg,TInt aIndex) const
/** Returns a copy of a fixed-size message in the buffer
@param a copy of the message
@param aIndex the ordinal position of the message
@panic if the index is out of bounds
@panic the message specified is not of the correct type
*/ {
__ASSERT_COMPILE(sizeof(TWsGraphicMsgFixedBase) == (sizeof(TInt32)*2));
const TInt KHeaderSize = sizeof(TWsGraphicMsgFixedBase);
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
if((TUid::Uid(IntAt(ofs)) != aMsg.TypeId()) ||
(IntAt(ofs+sizeof(TInt)) != aMsg.Size()) ||
((ofs + KHeaderSize + aMsg.Size()) > length))
{
Panic(EW32PanicGraphicBadBuffer);
}
memcpy(&aMsg,(Ptr()+ofs),KHeaderSize + aMsg.Size());
return;
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
}