diff -r 000000000000 -r bde4ae8d615e os/graphics/windowing/windowserver/nga/CLIENT/WSGRAPHIC.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/windowing/windowserver/nga/CLIENT/WSGRAPHIC.CPP Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1118 @@ +// 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 +#include "../SERVER/w32cmd.h" +#include "w32comm.h" +#include "CLIENT.H" +#include +#include + +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(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 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); + // coverity[negative_returns] + 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; iiPimpl && (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(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(); + 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(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 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(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(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(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 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(&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); + } +