|
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), iWindowSizeCache(NULL) |
|
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 if (iWindowSizeCache) |
|
98 { |
|
99 iWindowSizeCache->Close(); |
|
100 delete iWindowSizeCache; |
|
101 iWindowSizeCache = NULL; |
|
102 } |
|
103 } |
|
104 |
|
105 void RWsBuffer::Destroy() |
|
106 { |
|
107 Flush(); |
|
108 Close(); |
|
109 delete this; |
|
110 } |
|
111 |
|
112 |
|
113 TInt RWsBuffer::Flush(const TIpcArgs* aIpcArgs,TBool aRequestFinish) |
|
114 { |
|
115 iBitmapArray.Reset(); |
|
116 iInvalidBitmapArray=EFalse; |
|
117 if (iBuf.Length()==0) |
|
118 { |
|
119 return(KErrNone); |
|
120 } |
|
121 TIpcArgs ipcArgs; |
|
122 if (aIpcArgs!=NULL) |
|
123 { |
|
124 ipcArgs=*aIpcArgs; |
|
125 // check that the caller hasn't used the first slot |
|
126 ipcArgs.Set(KBufferMessageSlot,TIpcArgs::ENothing); |
|
127 __ASSERT_ALWAYS(Mem::Compare(REINTERPRET_CAST(const TUint8*, &ipcArgs), sizeof(TIpcArgs), REINTERPRET_CAST(const TUint8*, aIpcArgs), sizeof(TIpcArgs))==0,Panic(EW32PanicUsingReservedIpcSlot)); |
|
128 } |
|
129 ipcArgs.Set(KBufferMessageSlot,&iBuf); |
|
130 TInt ret; |
|
131 if(aRequestFinish) |
|
132 ret=iSession->DoFlush(ipcArgs); |
|
133 else |
|
134 ret=iSession->DoSyncMsgBuf(ipcArgs); |
|
135 iBuf.Zero(); |
|
136 iPreviousHandle=0; |
|
137 return(ret); |
|
138 } |
|
139 |
|
140 void RWsBuffer::FlushAllBuffers(TInt aBitmapHandle) |
|
141 { |
|
142 for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) |
|
143 { |
|
144 if(!aBitmapHandle || buffer->iInvalidBitmapArray || (buffer->iBitmapArray.FindInOrder(aBitmapHandle)!=KErrNotFound)) |
|
145 |
|
146 buffer->Flush(); |
|
147 } |
|
148 } |
|
149 |
|
150 inline void RWsBuffer::SetAndLimitMaxBufSize(TInt aMaxBufSize) |
|
151 { // apply upper & lower limits to input buffer size |
|
152 if (aMaxBufSize < EMinBufferSize) |
|
153 { |
|
154 iMaxBufSize = EMinBufferSize; |
|
155 } |
|
156 else if (aMaxBufSize > EMaxBufferSize) |
|
157 { |
|
158 iMaxBufSize = EMaxBufferSize; |
|
159 } |
|
160 else |
|
161 { |
|
162 iMaxBufSize = aMaxBufSize; |
|
163 } |
|
164 } |
|
165 |
|
166 void RWsBuffer::SetBufferSizeL(TInt aBufSize) |
|
167 { |
|
168 SetAndLimitMaxBufSize(aBufSize); |
|
169 ReAllocBufferL(iMaxBufSize); |
|
170 } |
|
171 |
|
172 void RWsBuffer::SetMaxBufferSizeL(TInt aMaxBufSize) |
|
173 { |
|
174 SetAndLimitMaxBufSize(aMaxBufSize); |
|
175 |
|
176 if (iMaxBufSize < iBufSize) |
|
177 { // shrink to new maximum |
|
178 ReAllocBufferL(iMaxBufSize); |
|
179 } |
|
180 else |
|
181 { |
|
182 // initial allocation should be (at least) a quarter of the requested size |
|
183 TInt minSize = Max( (iMaxBufSize + 3) >> 2, EMinBufferSize); |
|
184 if (minSize > iBufSize) |
|
185 { // new or enlarged buffer |
|
186 ReAllocBufferL(minSize); |
|
187 } |
|
188 } |
|
189 |
|
190 __ASSERT_DEBUG((iBufSize >= EMinBufferSize) && (iBufSize <= iMaxBufSize), Assert(EW32AssertBufferLogic)); |
|
191 } |
|
192 |
|
193 // Flush() buffer, try to ReAlloc, Leave if the ReAlloc fails. |
|
194 void RWsBuffer::ReAllocBufferL(TInt aNewSize) |
|
195 { |
|
196 if (aNewSize != iBufSize) |
|
197 { |
|
198 Flush(); |
|
199 if (!ReAllocBuffer(aNewSize)) |
|
200 { |
|
201 User::LeaveNoMemory(); |
|
202 } |
|
203 } |
|
204 } |
|
205 |
|
206 TBool RWsBuffer::ReAllocBuffer(TInt aNewSize) |
|
207 { |
|
208 TUint8* ptr = const_cast<TUint8*>(iBuf.Ptr()); |
|
209 __ASSERT_DEBUG((iBufSize == 0) || (ptr != NULL), Assert(EW32AssertBufferLogic)); |
|
210 const TInt len = iBuf.Length(); |
|
211 TUint8* newPtr = static_cast<TUint8*>(User::ReAlloc(ptr, aNewSize)); |
|
212 if (newPtr != NULL) |
|
213 { // realloc was successful |
|
214 iBuf.Set(newPtr, len, aNewSize); |
|
215 iBufSize = aNewSize; |
|
216 return ETrue; |
|
217 } |
|
218 return EFalse; |
|
219 } |
|
220 |
|
221 /* Expand the buffer, to allow new drawing command to fit. |
|
222 |
|
223 Called either when trying to store additional commands to queue for Wserv, or |
|
224 the trying to send a command bigger than the current buffer size. |
|
225 |
|
226 Failure to expand the buffer is a minor problem in the first case but a big |
|
227 problem in the second. |
|
228 |
|
229 @param aRequiredSpace Size of buffer increase required. |
|
230 @param aMsgSize If expanding the buffer fails then needs this value to know whether Flush() is good enough. |
|
231 @return ETrue if there is enough space, EFalse if not. |
|
232 */ |
|
233 void RWsBuffer::GrowBuffer(TInt aRequiredSpace, TInt aMsgSize) |
|
234 { |
|
235 __ASSERT_DEBUG(iBufSize < iMaxBufSize, Assert(EW32AssertBufferLogic)); |
|
236 // maximum size will be big enough? |
|
237 __ASSERT_ALWAYS(aMsgSize <= iMaxBufSize, Panic(EW32PanicDataExceedsBufferLength)); |
|
238 |
|
239 // double or quad the current size, then limit it |
|
240 TInt newSize = Min((iBufSize >= aRequiredSpace) ? iBufSize << 1 : iBufSize << 2, iMaxBufSize); |
|
241 |
|
242 if (!ReAllocBuffer(newSize)) |
|
243 { // OOM error |
|
244 Flush(); |
|
245 if (aMsgSize > iBufSize) |
|
246 { // message is too big for buffer |
|
247 Panic(EW32PanicDataExceedsBufferLength); |
|
248 } |
|
249 } |
|
250 } |
|
251 |
|
252 |
|
253 TBool RWsBuffer::SetAutoFlush(TBool aState) |
|
254 { |
|
255 TBool old; |
|
256 |
|
257 old=iAutoFlush; |
|
258 #if defined(__AUTO_FLUSH) |
|
259 if (aState) |
|
260 #else |
|
261 iAutoFlush=aState; |
|
262 if (iAutoFlush) |
|
263 #endif |
|
264 Flush(); |
|
265 return(old); |
|
266 } |
|
267 |
|
268 TInt RWsBuffer::DoWrite(TInt aHandle, TUint aOpcode, TBool aFlush, const TIpcArgs* aIpcArgs, const TAny* aData, TInt aLength, const TAny* aData2, TInt aLength2) |
|
269 { |
|
270 __ASSERT_DEBUG(((TUint32) aOpcode) < 0x8000, Assert(EW32AssertIllegalOpcode)); |
|
271 __ASSERT_DEBUG((aLength&0x3) == 0, Assert(EW32AssertOddLengthData)); |
|
272 TInt xtra(0); |
|
273 if (aLength2 > 0) |
|
274 { |
|
275 xtra = 4 - (aLength2&0x3); // Round data upto a multiple of 4 |
|
276 if (xtra==4) |
|
277 { |
|
278 xtra=0; |
|
279 } |
|
280 } |
|
281 |
|
282 const TInt msgSize = aLength + aLength2 + xtra + static_cast<TInt>(sizeof(TWsCmdHeader)); |
|
283 TInt available = iBuf.MaxLength() - iBuf.Length(); |
|
284 if (msgSize > available) |
|
285 { |
|
286 if (iBufSize >= iMaxBufSize) |
|
287 { // buffer is maximum size already |
|
288 Flush(); |
|
289 } |
|
290 else |
|
291 { // try to grow buffer |
|
292 if ( (iBuf.Length() + msgSize) > iMaxBufSize) |
|
293 { // growing alone will not make enough extra space |
|
294 Flush(); |
|
295 available = iBufSize; |
|
296 } |
|
297 |
|
298 const TInt requiredSpace = msgSize - available; |
|
299 if (requiredSpace > 0) |
|
300 { |
|
301 GrowBuffer(requiredSpace, msgSize); |
|
302 } |
|
303 } |
|
304 } |
|
305 |
|
306 TWsCmdHeader cmdHeader; |
|
307 cmdHeader.iBase.iOpcode = (TInt16)aOpcode; |
|
308 cmdHeader.iBase.iCmdLength = (TInt16)(aLength + aLength2 + xtra); |
|
309 |
|
310 // For performance reasons we only pass in the handle if it is different |
|
311 // from the previous command |
|
312 if (aHandle == iPreviousHandle) |
|
313 { |
|
314 iBuf.Append((TUint8 *)&cmdHeader.iBase,sizeof(cmdHeader.iBase)); |
|
315 } |
|
316 else |
|
317 { |
|
318 iPreviousHandle = aHandle; |
|
319 cmdHeader.iBase.iOpcode|=EWsOpcodeHandle; |
|
320 cmdHeader.iDestHandle = aHandle; |
|
321 iBuf.Append((TUint8 *)&cmdHeader,sizeof(cmdHeader)); |
|
322 } |
|
323 |
|
324 if (aLength) |
|
325 { |
|
326 iBuf.Append((TUint8 *)aData, aLength); |
|
327 } |
|
328 if (aLength2 > 0) |
|
329 { |
|
330 iBuf.Append((TUint8 *)aData2, aLength2); |
|
331 iBuf.AppendFill(0,xtra); |
|
332 } |
|
333 |
|
334 if (aFlush) |
|
335 { |
|
336 return Flush(aIpcArgs); |
|
337 } |
|
338 return KErrNone; |
|
339 } |
|
340 |
|
341 void RWsBuffer::Write(TInt handle,TUint opcode) |
|
342 { |
|
343 DoWrite(handle, opcode, iAutoFlush, NULL); |
|
344 } |
|
345 |
|
346 void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length) |
|
347 { |
|
348 DoWrite(handle, opcode, iAutoFlush, NULL, pData, length); |
|
349 } |
|
350 |
|
351 void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length,const TAny *pData2, TInt length2) |
|
352 { |
|
353 DoWrite(handle, opcode, iAutoFlush, NULL, pData, length, pData2, length2); |
|
354 } |
|
355 |
|
356 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TIpcArgs* aIpcArgs) |
|
357 { |
|
358 return DoWrite(handle, opcode, ETrue, aIpcArgs); |
|
359 } |
|
360 |
|
361 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData, TInt length,const TIpcArgs* aIpcArgs) |
|
362 { |
|
363 return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length); |
|
364 } |
|
365 |
|
366 TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData,TInt length,const TAny *pData2,TInt length2,const TIpcArgs* aIpcArgs) |
|
367 { |
|
368 return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length, pData2, length2); |
|
369 } |
|
370 |
|
371 TInt RWsBuffer::WriteReplyP(TInt aHandle, TUint aOpcode, const TWriteDescriptorType& aReplyBuffer) |
|
372 { |
|
373 TIpcArgs ipcArgs; |
|
374 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
375 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs); |
|
376 } |
|
377 |
|
378 TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData,TInt aLength,const TWriteDescriptorType& aReplyBuffer) |
|
379 { |
|
380 TIpcArgs ipcArgs; |
|
381 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
382 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); |
|
383 } |
|
384 |
|
385 TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData1,TInt aLengthData1,const TAny *aData2,TInt aLengthData2,const TWriteDescriptorType& aReplyBuffer) |
|
386 { |
|
387 TIpcArgs ipcArgs; |
|
388 aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
389 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData1, aLengthData1, aData2, aLengthData2); |
|
390 } |
|
391 |
|
392 TInt RWsBuffer::WriteReplyWs(TUint opcode) |
|
393 // |
|
394 // Do a WriteReply using the sessions handle |
|
395 // |
|
396 { |
|
397 return(iSession->WriteReply(opcode)); |
|
398 } |
|
399 |
|
400 TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, TUint aOpcode) |
|
401 // |
|
402 // Do a WriteReply using the sessions handle |
|
403 // |
|
404 { |
|
405 return(iSession->WriteReply(pData,aLength,aOpcode)); |
|
406 } |
|
407 |
|
408 TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, const TAny *pData2, TInt aLength2, TUint aOpcode) |
|
409 // |
|
410 // Do a WriteReply using the sessions handle |
|
411 // |
|
412 { |
|
413 return(iSession->WriteReply(pData,aLength,pData2,aLength2,aOpcode)); |
|
414 } |
|
415 |
|
416 TInt RWsBuffer::WriteReplyByProvidingRemoteReadAccess(TInt aHandle,TUint aOpcode,const TAny *aData, TInt aLength,const TReadDescriptorType& aRemoteReadBuffer) |
|
417 { |
|
418 TIpcArgs ipcArgs; |
|
419 aRemoteReadBuffer.SetDescriptorOnIpcArgs(ipcArgs); |
|
420 return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); |
|
421 } |
|
422 |
|
423 void RWsBuffer::AddToBitmapArray(TInt aBitmapHandle) |
|
424 { |
|
425 if(aBitmapHandle && !iInvalidBitmapArray) |
|
426 { |
|
427 if(iBitmapArray.InsertInOrder(aBitmapHandle)==KErrNoMemory) |
|
428 |
|
429 iInvalidBitmapArray=ETrue; |
|
430 } |
|
431 } |
|
432 |
|
433 void RWsBuffer::SetWsGraphicManager(CWsGraphic::CManager* aManager) |
|
434 { |
|
435 __ASSERT_DEBUG(!WsGraphicManager(),Panic(EW32PanicGraphicInternal)); |
|
436 iManager = aManager; |
|
437 } |
|
438 |
|
439 CWsGraphic::CManager* RWsBuffer::WsGraphicManager() |
|
440 { |
|
441 for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) |
|
442 if (buffer->iManager) |
|
443 return buffer->iManager; |
|
444 return NULL; // does not yet exist |
|
445 } |
|
446 |
|
447 void RWsBuffer::AsyncRequest(TInt aHandle, TUint aOpcode, TRequestStatus& aStatus) |
|
448 { |
|
449 aStatus = KRequestPending; |
|
450 __ASSERT_DEBUG((aOpcode&EWservMessAsynchronousService)==0, Assert(EW32AssertIllegalOpcode)); |
|
451 Flush(); |
|
452 |
|
453 const TInt function = EWservMessAsynchronousService | aOpcode; |
|
454 TIpcArgs ipcArgs(aHandle); |
|
455 |
|
456 iSession->SendReceive(function, ipcArgs, aStatus); |
|
457 } |
|
458 |
|
459 void RWsBuffer::EnableWindowSizeCacheL() |
|
460 { |
|
461 if (iWindowSizeCache == NULL) |
|
462 { |
|
463 iWindowSizeCache = new (ELeave) RHashMap<TInt, TWindowSizeCacheEntry>(); |
|
464 } |
|
465 } |