author | Gareth Stockwell <gareth.stockwell@accenture.com> |
Fri, 22 Oct 2010 11:38:29 +0100 | |
branch | bug235_bringup_0 |
changeset 206 | c170e304623f |
parent 0 | 5d03bc08d59c |
permissions | -rw-r--r-- |
// 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> /** Panics the client. This will result in the client thread being destroyed. */ GLREF_C void Panic(TW32Panic aPanic); 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 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 { 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); }