|
1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // RWsBuffer class, handles buffering and flushing of window server commands |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32std.h> |
|
19 #include "../SERVER/w32cmd.h" |
|
20 #include "CLIENT.H" |
|
21 #include "w32comm.h" |
|
22 |
|
23 // Global functions |
|
24 |
|
25 GLDEF_C void Assert(TW32Assert aAssert) |
|
26 { |
|
27 _LIT(KW32AssertCategory,"W32 Assert"); |
|
28 User::Panic(KW32AssertCategory,aAssert); |
|
29 } |
|
30 |
|
31 GLDEF_C void Panic(TW32Panic aPanic) |
|
32 { |
|
33 _LIT(KW32PanicCategory,"W32"); |
|
34 User::Panic(KW32PanicCategory,aPanic); |
|
35 } |
|
36 |
|
37 // Public functions |
|
38 |
|
39 RWsBuffer::RWsBuffer(RWsSession *aSession) : iSession(aSession), iManager(NULL), |
|
40 #if defined(__AUTO_FLUSH) |
|
41 iAutoFlush(ETrue), |
|
42 #else |
|
43 iAutoFlush(EFalse), |
|
44 #endif |
|
45 iBuf(NULL,0,0), iNext(NULL), iPreviousHandle(0), iBufSize(0), iMaxBufSize(EMinBufferSize), |
|
46 iDirectAcessCount(0), iInvalidBitmapArray(EFalse) |
|
47 { |
|
48 } |
|
49 |
|
50 TInt WsFbsDestroyCallBack(TAny* aBitmapHandle) |
|
51 { |
|
52 TInt* bitmapHandle=static_cast<TInt*>(aBitmapHandle); |
|
53 RWsBuffer::FlushAllBuffers(aBitmapHandle ? *bitmapHandle : 0); |
|
54 |
|
55 return(0); |
|
56 } |
|
57 |
|
58 void RWsBuffer::SetCallBack() |
|
59 { |
|
60 for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) |
|
61 if (buffer==this) |
|
62 return; // Already linked |
|
63 iNext=(RWsBuffer *)Dll::Tls(); |
|
64 Dll::SetTls(this); |
|
65 if (iNext==NULL) // First connection so set callback |
|
66 RFbsSession::GetSession()->SetCallBack(TCallBack(WsFbsDestroyCallBack,NULL)); |
|
67 } |
|
68 |
|
69 void RWsBuffer::CancelCallBack() |
|
70 { |
|
71 RWsBuffer *buffer=(RWsBuffer *)Dll::Tls(); |
|
72 if (buffer==this) |
|
73 { |
|
74 Dll::SetTls(iNext); |
|
75 if (iNext==NULL) |
|
76 RFbsSession::GetSession()->ResetCallBack(); // Last connection closing so cancel the callback |
|
77 } |
|
78 else |
|
79 { |
|
80 RWsBuffer *prev; |
|
81 while(buffer) |
|
82 { |
|
83 prev=buffer; |
|
84 buffer=buffer->iNext; |
|
85 if (buffer==this) |
|
86 { |
|
87 prev->iNext=iNext; |
|
88 break; |
|
89 } |
|
90 } |
|
91 } |
|
92 } |
|
93 |
|
94 void RWsBuffer::Close() |
|
95 { |
|
96 User::Free((TAny *)iBuf.Ptr()); |
|
97 } |
|
98 |
|
99 void RWsBuffer::Destroy() |
|
100 { |
|
101 Flush(); |
|
102 Close(); |
|
103 delete this; |
|
104 } |
|
105 |
|
106 |
|
107 TInt RWsBuffer::Flush(const TIpcArgs* aIpcArgs,TBool aRequestFinish) |
|
108 { |
|
109 iBitmapArray.Reset(); |
|
110 iInvalidBitmapArray=EFalse; |
|
111 if (iBuf.Length()==0) |
|
112 { |
|
113 return(KErrNone); |
|
114 } |
|
115 TIpcArgs ipcArgs; |
|
116 if (aIpcArgs!=NULL) |
|
117 { |
|
118 ipcArgs=*aIpcArgs; |
|
119 // check that the caller hasn't used the first slot |
|
120 ipcArgs.Set(KBufferMessageSlot,TIpcArgs::ENothing); |
|
121 __ASSERT_ALWAYS(Mem::Compare(REINTERPRET_CAST(const TUint8*, &ipcArgs), sizeof(TIpcArgs), REINTERPRET_CAST(const TUint8*, aIpcArgs), sizeof(TIpcArgs))==0,Panic(EW32PanicUsingReservedIpcSlot)); |
|
122 } |
|
123 ipcArgs.Set(KBufferMessageSlot,&iBuf); |
|
124 TInt ret; |
|
125 if(aRequestFinish) |
|
126 ret=iSession->DoFlush(ipcArgs); |
|
127 else |
|
128 ret=iSession->DoSyncMsgBuf(ipcArgs); |
|
129 iBuf.Zero(); |
|
130 iPreviousHandle=0; |
|
131 return(ret); |
|
132 } |
|
133 |
|
134 void RWsBuffer::FlushAllBuffers(TInt aBitmapHandle) |
|
135 { |
|
136 for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) |
|
137 { |
|
138 if(!aBitmapHandle || buffer->iInvalidBitmapArray || (buffer->iBitmapArray.FindInOrder(aBitmapHandle)!=KErrNotFound)) |
|
139 |
|
140 buffer->Flush(); |
|
141 } |
|
142 } |
|
143 |
|
144 inline void RWsBuffer::SetAndLimitMaxBufSize(TInt aMaxBufSize) |
|
145 { // apply upper & lower limits to input buffer size |
|
146 if (aMaxBufSize < EMinBufferSize) |
|
147 { |
|
148 iMaxBufSize = EMinBufferSize; |
|
149 } |
|
150 else if (aMaxBufSize > EMaxBufferSize) |
|
151 { |
|
152 iMaxBufSize = EMaxBufferSize; |
|
153 } |
|
154 else |
|
155 { |
|
156 iMaxBufSize = aMaxBufSize; |
|
157 } |
|
158 } |
|
159 |
|
160 void RWsBuffer::SetBufferSizeL(TInt aBufSize) |
|
161 { |
|
162 SetAndLimitMaxBufSize(aBufSize); |
|
163 ReAllocBufferL(iMaxBufSize); |
|
164 } |
|
165 |
|
166 void RWsBuffer::SetMaxBufferSizeL(TInt aMaxBufSize) |
|
167 { |
|
168 SetAndLimitMaxBufSize(aMaxBufSize); |
|
169 |
|
170 if (iMaxBufSize < iBufSize) |
|
171 { // shrink to new maximum |
|
172 ReAllocBufferL(iMaxBufSize); |
|
173 } |
|
174 else |
|
175 { |
|
176 // initial allocation should be (at least) a quarter of the requested size |
|
177 TInt minSize = Max( (iMaxBufSize + 3) >> 2, EMinBufferSize); |
|
178 if (minSize > iBufSize) |
|
179 { // new or enlarged buffer |
|
180 ReAllocBufferL(minSize); |
|
181 } |
|
182 } |
|
183 |
|
184 __ASSERT_DEBUG((iBufSize >= EMinBufferSize) && (iBufSize <= iMaxBufSize), Assert(EW32AssertBufferLogic)); |
|
185 } |
|
186 |
|
187 // Flush() buffer, try to ReAlloc, Leave if the ReAlloc fails. |
|
188 void RWsBuffer::ReAllocBufferL(TInt aNewSize) |
|
189 { |
|
190 if (aNewSize != iBufSize) |
|
191 { |
|
192 Flush(); |
|
193 if (!ReAllocBuffer(aNewSize)) |
|
194 { |
|
195 User::LeaveNoMemory(); |
|
196 } |
|
197 } |
|
198 } |
|
199 |
|
200 TBool RWsBuffer::ReAllocBuffer(TInt aNewSize) |
|
201 { |
|
202 TUint8* ptr = const_cast<TUint8*>(iBuf.Ptr()); |
|
203 __ASSERT_DEBUG((iBufSize == 0) || (ptr != NULL), Assert(EW32AssertBufferLogic)); |
|
204 const TInt len = iBuf.Length(); |
|
205 TUint8* newPtr = static_cast<TUint8*>(User::ReAlloc(ptr, aNewSize)); |
|
206 if (newPtr != NULL) |
|
207 { // realloc was successful |
|
208 iBuf.Set(newPtr, len, aNewSize); |
|
209 iBufSize = aNewSize; |
|
210 return ETrue; |
|
211 } |
|
212 return EFalse; |
|
213 } |
|
214 |
|
215 /* Expand the buffer, to allow new drawing command to fit. |
|
216 |
|
217 Called either when trying to store additional commands to queue for Wserv, or |
|
218 the trying to send a command bigger than the current buffer size. |
|
219 |
|
220 Failure to expand the buffer is a minor problem in the first case but a big |
|
221 problem in the second. |
|
222 |
|
223 @param aRequiredSpace Size of buffer increase required. |
|
224 @param aMsgSize If expanding the buffer fails then needs this value to know whether Flush() is good enough. |
|
225 @return ETrue if there is enough space, EFalse if not. |
|
226 */ |
|
227 void RWsBuffer::GrowBuffer(TInt aRequiredSpace, TInt aMsgSize) |
|
228 { |
|
229 __ASSERT_DEBUG(iBufSize < iMaxBufSize, Assert(EW32AssertBufferLogic)); |
|
230 // maximum size will be big enough? |
|
231 __ASSERT_ALWAYS(aMsgSize <= iMaxBufSize, Panic(EW32PanicDataExceedsBufferLength)); |
|
232 |
|
233 // double or quad the current size, then limit it |
|
234 TInt newSize = Min((iBufSize >= aRequiredSpace) ? iBufSize << 1 : iBufSize << 2, iMaxBufSize); |
|
235 |
|
236 if (!ReAllocBuffer(newSize)) |
|
237 { // OOM error |
|
238 Flush(); |
|
239 if (aMsgSize > iBufSize) |
|
240 { // message is too big for buffer |
|
241 Panic(EW32PanicDataExceedsBufferLength); |
|
242 } |
|
243 } |
|
244 } |
|
245 |
|
246 |
|
247 TBool RWsBuffer::SetAutoFlush(TBool aState) |
|
248 { |
|
249 TBool old; |
|
250 |
|
251 old=iAutoFlush; |
|
252 #if defined(__AUTO_FLUSH) |
|
253 if (aState) |
|
254 #else |
|
255 iAutoFlush=aState; |
|
256 if (iAutoFlush) |
|
257 #endif |
|
258 Flush(); |
|
259 return(old); |
|
260 } |
|
261 |
|
262 TInt RWsBuffer::DoWrite(TInt aHandle, TUint aOpcode, TBool aFlush, const TIpcArgs* aIpcArgs, const TAny* aData, TInt aLength, const TAny* aData2, TInt aLength2) |
|
263 { |
|
264 __ASSERT_DEBUG(((TUint32) aOpcode) < 0x8000, Assert(EW32AssertIllegalOpcode)); |
|
265 __ASSERT_DEBUG((aLength&0x3) == 0, Assert(EW32AssertOddLengthData)); |
|
266 TInt xtra(0); |
|
267 if (aLength2 > 0) |
|
268 { |
|
269 xtra = 4 - (aLength2&0x3); // Round data upto a multiple of 4 |
|
270 if (xtra==4) |
|
271 { |
|
272 xtra=0; |
|
273 } |
|
274 } |
|
275 |
|
276 const TInt msgSize = aLength + aLength2 + xtra + static_cast<TInt>(sizeof(TWsCmdHeader)); |
|
277 TInt available = iBuf.MaxLength() - iBuf.Length(); |
|
278 if (msgSize > available) |
|
279 { |
|
280 if (iBufSize >= iMaxBufSize) |
|
281 { // buffer is maximum size already |
|
282 Flush(); |
|
283 } |
|
284 else |
|
285 { // try to grow buffer |
|
286 if ( (iBuf.Length() + msgSize) > iMaxBufSize) |
|
287 { // growing alone will not make enough extra space |
|
288 Flush(); |
|
289 available = iBufSize; |
|
290 } |
|
291 |
|
292 const TInt requiredSpace = msgSize - available; |
|
293 if (requiredSpace > 0) |
|
294 { |
|
295 GrowBuffer(requiredSpace, msgSize); |
|
296 } |
|
297 } |
|
298 } |
|
299 |
|
300 TWsCmdHeader cmdHeader; |
|
301 cmdHeader.iBase.iOpcode = (TInt16)aOpcode; |
|
302 cmdHeader.iBase.iCmdLength = (TInt16)(aLength + aLength2 + xtra); |
|
303 |
|
304 // For performance reasons we only pass in the handle if it is different |
|
305 // from the previous command |
|
306 if (aHandle == iPreviousHandle) |
|
307 { |
|
308 iBuf.Append((TUint8 *)&cmdHeader.iBase,sizeof(cmdHeader.iBase)); |
|
309 } |
|
310 else |
|
311 { |
|
312 iPreviousHandle = aHandle; |
|
313 cmdHeader.iBase.iOpcode|=EWsOpcodeHandle; |
|
314 cmdHeader.iDestHandle = aHandle; |
|
315 iBuf.Append((TUint8 *)&cmdHeader,sizeof(cmdHeader)); |
|
316 } |
|
317 |
|
318 if (aLength) |
|
319 { |
|
320 iBuf.Append((TUint8 *)aData, aLength); |
|
321 } |
|
322 if (aLength2 > 0) |
|
323 { |
|
324 iBuf.Append((TUint8 *)aData2, aLength2); |
|
325 iBuf.AppendFill(0,xtra); |
|
326 } |
|
327 |
|
328 if (aFlush) |
|
329 { |
|
330 return Flush(aIpcArgs); |
|
331 } |
|
332 return KErrNone; |
|
333 } |
|
334 |
|
335 void RWsBuffer::Write(TInt handle,TUint opcode) |
|
336 { |
|
337 DoWrite(handle, opcode, iAutoFlush, NULL); |
|
338 } |
|
339 |
|
340 void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length) |
|
341 { |
|
342 DoWrite(handle, opcode, iAutoFlush, NULL, pData, length); |
|
343 } |
|
344 |
|
345 void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length,const TAny *pData2, TInt length2) |
|
346 { |
|
347 DoWrite(handle, opcode, iAutoFlush, NULL, pData, length, pData2, length2); |
|
348 } |
|
349 |
|
350 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TIpcArgs* aIpcArgs) |
|
351 { |
|
352 return DoWrite(handle, opcode, ETrue, aIpcArgs); |
|
353 } |
|
354 |
|
355 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData, TInt length,const TIpcArgs* aIpcArgs) |
|
356 { |
|
357 return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length); |
|
358 } |
|
359 |
|
360 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData,TInt length,const TAny *pData2,TInt length2,const TIpcArgs* aIpcArgs) |
|
361 { |
|
362 return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length, pData2, length2); |
|
363 } |
|
364 |
|
365 TInt RWsBuffer::WriteReplyP(TInt aHandle, TUint aOpcode, const TWriteDescriptorType& aReplyBuffer) |
|
366 { |
|
367 TIpcArgs ipcArgs; |
|
368 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
369 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs); |
|
370 } |
|
371 |
|
372 TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData,TInt aLength,const TWriteDescriptorType& aReplyBuffer) |
|
373 { |
|
374 TIpcArgs ipcArgs; |
|
375 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
376 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); |
|
377 } |
|
378 |
|
379 TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData1,TInt aLengthData1,const TAny *aData2,TInt aLengthData2,const TWriteDescriptorType& aReplyBuffer) |
|
380 { |
|
381 TIpcArgs ipcArgs; |
|
382 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
383 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData1, aLengthData1, aData2, aLengthData2); |
|
384 } |
|
385 |
|
386 TInt RWsBuffer::WriteReplyWs(TUint opcode) |
|
387 // |
|
388 // Do a WriteReply using the sessions handle |
|
389 // |
|
390 { |
|
391 return(iSession->WriteReply(opcode)); |
|
392 } |
|
393 |
|
394 TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, TUint aOpcode) |
|
395 // |
|
396 // Do a WriteReply using the sessions handle |
|
397 // |
|
398 { |
|
399 return(iSession->WriteReply(pData,aLength,aOpcode)); |
|
400 } |
|
401 |
|
402 TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, const TAny *pData2, TInt aLength2, TUint aOpcode) |
|
403 // |
|
404 // Do a WriteReply using the sessions handle |
|
405 // |
|
406 { |
|
407 return(iSession->WriteReply(pData,aLength,pData2,aLength2,aOpcode)); |
|
408 } |
|
409 |
|
410 TInt RWsBuffer::WriteReplyByProvidingRemoteReadAccess(TInt aHandle,TUint aOpcode,const TAny *aData, TInt aLength,const TReadDescriptorType& aRemoteReadBuffer) |
|
411 { |
|
412 TIpcArgs ipcArgs; |
|
413 aRemoteReadBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
414 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); |
|
415 } |
|
416 |
|
417 void RWsBuffer::AddToBitmapArray(TInt aBitmapHandle) |
|
418 { |
|
419 if(aBitmapHandle && !iInvalidBitmapArray) |
|
420 { |
|
421 if(iBitmapArray.InsertInOrder(aBitmapHandle)==KErrNoMemory) |
|
422 |
|
423 iInvalidBitmapArray=ETrue; |
|
424 } |
|
425 } |
|
426 |
|
427 void RWsBuffer::SetWsGraphicManager(CWsGraphic::CManager* aManager) |
|
428 { |
|
429 __ASSERT_DEBUG(!WsGraphicManager(),Panic(EW32PanicGraphicInternal)); |
|
430 iManager = aManager; |
|
431 } |
|
432 |
|
433 CWsGraphic::CManager* RWsBuffer::WsGraphicManager() |
|
434 { |
|
435 for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) |
|
436 if (buffer->iManager) |
|
437 return buffer->iManager; |
|
438 return NULL; // does not yet exist |
|
439 } |