windowing/windowserver/nga/CLIENT/WSGRAPHIC.CPP
changeset 0 5d03bc08d59c
child 121 d72fc2aace31
child 163 bbf46f59e123
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/CLIENT/WSGRAPHIC.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1117 @@
+// 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);
+	}
+