|
1 // Copyright (c) 2006-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 // SCREEN_REDRAW.CPP |
|
15 // |
|
16 // |
|
17 |
|
18 #include "ScreenRedraw.h" |
|
19 |
|
20 #include <hal.h> |
|
21 |
|
22 #include "debugbar.h" |
|
23 #include "screen.h" |
|
24 #include "inifile.h" |
|
25 #include "offscreenbitmap.h" |
|
26 #include "wspluginmanager.h" |
|
27 #include "pointer.h" |
|
28 #include "rootwin.h" |
|
29 #include "walkwindowtree.h" |
|
30 #include "wstop.h" |
|
31 #include "WsMemMgr.h" |
|
32 #include "Graphics/WsRenderStageFactory.h" |
|
33 #include "Graphics/WsRenderStage.h" |
|
34 #include "EVENT.H" |
|
35 |
|
36 GLREF_D CDebugLogBase *wsDebugLog; |
|
37 |
|
38 #ifdef USE_DEBUG_REGIONS |
|
39 # define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg) |
|
40 # define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect) |
|
41 #else |
|
42 # define DEBUG_REGION(col,fill,reg) |
|
43 # define DEBUG_RECT(col,fill,rect) |
|
44 #endif |
|
45 |
|
46 #if defined(__WINS__) && defined(_DEBUG) |
|
47 # define DEBUGOSB { CWsOffScreenBitmap * ofb = iScreen.OffScreenBitmap(); if (ofb) ofb->Update(); } |
|
48 #else |
|
49 # define DEBUGOSB |
|
50 #endif |
|
51 |
|
52 #ifdef _DEBUG |
|
53 # define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}} |
|
54 # define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}} |
|
55 #else |
|
56 # define LOG_SCREEN_REDRAW_START |
|
57 # define LOG_SCREEN_REDRAW_END |
|
58 #endif |
|
59 |
|
60 CScreenRedraw::TTimedRect::TTimedRect(const TRect& aRect, const TTime& aTime): |
|
61 iRect(aRect), iTime(aTime) |
|
62 { |
|
63 } |
|
64 |
|
65 TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther) |
|
66 { |
|
67 if(aOne.iTime < aOther.iTime) |
|
68 return -1; |
|
69 else if(aOne.iTime > aOther.iTime) |
|
70 return 1; |
|
71 else |
|
72 return 0; |
|
73 } |
|
74 |
|
75 CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen) |
|
76 { |
|
77 CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen); |
|
78 CleanupStack::PushL(self); |
|
79 self->ConstructL(); |
|
80 CleanupStack::Pop(self); |
|
81 return self; |
|
82 } |
|
83 |
|
84 CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen) |
|
85 { |
|
86 } |
|
87 |
|
88 CScreenRedraw::~CScreenRedraw() |
|
89 { |
|
90 CWsRenderStage * stage = iRenderStages; |
|
91 while (stage!=NULL) |
|
92 { |
|
93 CWsRenderStage *next=stage->Next(); |
|
94 delete stage; |
|
95 stage=next; |
|
96 } |
|
97 iTimedDrawRect.Close(); |
|
98 iInvalid.Close(); |
|
99 iTopLayer.Close(); |
|
100 iBannedRegion.Close(); |
|
101 } |
|
102 |
|
103 void CScreenRedraw::ConstructL() |
|
104 { |
|
105 CWsPluginManager * pluginMgr = CWsTop::WindowServer()->PluginManager(); |
|
106 |
|
107 // Setup the render stages for this screen: |
|
108 _LIT(KDefaultRenderStages, "std"); |
|
109 _LIT(KDefaultFlickerFreeRenderStages, "flickerbuffer std"); |
|
110 _LIT(KRenderStages,"RENDERSTAGES"); |
|
111 TPtrC stagesString; |
|
112 const TBool customStages = WsIniFile->FindVar(iScreen.ScreenNumber(),KRenderStages,stagesString); |
|
113 |
|
114 // If noone specifies stages for this screen, assume the standard implementation: |
|
115 const TDesC * stages; |
|
116 if (customStages) |
|
117 stages = &stagesString; |
|
118 else if (iScreen.OffScreenBitmap()) |
|
119 stages = &KDefaultFlickerFreeRenderStages(); |
|
120 else |
|
121 stages = &KDefaultRenderStages(); |
|
122 |
|
123 CWsRenderStage * lastStage = 0; |
|
124 |
|
125 // Parse the string for implementation IDs: |
|
126 TLex lex(*stages); |
|
127 while(true) |
|
128 { |
|
129 TPtrC ptr = lex.NextToken(); |
|
130 if (ptr.Length() > 0) |
|
131 { |
|
132 TInt err = KErrNone; |
|
133 MWsRenderStageFactory * factory = pluginMgr->FindNamedImplementation<MWsRenderStageFactory>(ptr); |
|
134 if (factory) |
|
135 { |
|
136 CWsRenderStage * stage = 0; |
|
137 TRAP(err, stage = factory->CreateStageL(static_cast<MWsScreen*>(&iScreen), this)); |
|
138 if (err == KErrNone) |
|
139 { |
|
140 if (!stage) |
|
141 { |
|
142 err = KErrNotFound; |
|
143 } |
|
144 else |
|
145 { |
|
146 if (lastStage) |
|
147 lastStage->SetNext(stage); |
|
148 else |
|
149 iRenderStages = stage; |
|
150 lastStage = stage; |
|
151 } |
|
152 } |
|
153 } |
|
154 else |
|
155 { |
|
156 err = KErrNotFound; |
|
157 } |
|
158 |
|
159 if (wsDebugLog) |
|
160 { |
|
161 TBuf<64> buf; |
|
162 if (err == KErrNone) |
|
163 { |
|
164 _LIT(KAddedRenderStage,"Added render stage: "); |
|
165 buf.Append(KAddedRenderStage); |
|
166 buf.Append(ptr); |
|
167 wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf); |
|
168 } |
|
169 else |
|
170 { |
|
171 _LIT(KMissingRenderStage,"Failed to add render stage (%d): "); |
|
172 buf.Append(KMissingRenderStage); |
|
173 buf.Append(ptr); |
|
174 wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf,err); |
|
175 } |
|
176 } |
|
177 } |
|
178 else |
|
179 { |
|
180 break; |
|
181 } |
|
182 } |
|
183 } |
|
184 |
|
185 const TTime& CScreenRedraw::Now() const |
|
186 { |
|
187 if(!iAnimating) |
|
188 { |
|
189 iNow.UniversalTime(); |
|
190 } |
|
191 return iNow; |
|
192 } |
|
193 |
|
194 void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow) |
|
195 { |
|
196 iRenderScheduled = ETrue; |
|
197 TTime then(Now() + aFromNow); |
|
198 if ((!iScheduled) || then < iNext) |
|
199 iNext = then; |
|
200 iScheduled = ETrue; |
|
201 CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext); |
|
202 } |
|
203 |
|
204 void CScreenRedraw::ScheduleRedraw() |
|
205 { |
|
206 iNext = Now(); |
|
207 iScheduled = ETrue; |
|
208 |
|
209 // The other scheduler also removes future animations which this one encompasses. |
|
210 // We choose not to do the region calculations needed to achieve that here. |
|
211 MWsAnimationScheduler* animSched=CWsTop::WindowServer()->AnimationScheduler(); |
|
212 if (animSched) |
|
213 { |
|
214 animSched->ScheduleRedraw(iScreen,iNext); |
|
215 } |
|
216 } |
|
217 |
|
218 void CScreenRedraw::ScheduleAnimation(const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/) |
|
219 { |
|
220 TRect test(aRect); |
|
221 test.Intersection(iScreen.DrawableArea()); |
|
222 if(!test.IsEmpty()) |
|
223 { |
|
224 const TTime then(Now() + aFromNow); |
|
225 TTimedRect tRect(aRect, then); |
|
226 |
|
227 const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare); |
|
228 if (KErrNone == error) |
|
229 { |
|
230 if (iScheduled) |
|
231 { |
|
232 if (then < iNext) |
|
233 { |
|
234 iNext = then; |
|
235 } |
|
236 } |
|
237 else |
|
238 { |
|
239 iNext = then; |
|
240 iScheduled = ETrue; |
|
241 } |
|
242 // remove further futures that are completely contained |
|
243 TInt count = iTimedDrawRect.Count(); |
|
244 for(TInt i=0; i<count; i++) |
|
245 { |
|
246 const TTimedRect& future = iTimedDrawRect[i]; |
|
247 if(future.iTime.Int64() > then.Int64()) |
|
248 { |
|
249 TRect rect(aRect); |
|
250 rect.BoundingRect(future.iRect); |
|
251 if(rect == aRect) // future is completely contained within aRect |
|
252 { |
|
253 iTimedDrawRect.Remove(i); |
|
254 count--; |
|
255 i--; |
|
256 } |
|
257 } |
|
258 } |
|
259 CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext); |
|
260 |
|
261 // Blue rectangles for scheduled animations |
|
262 DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect); |
|
263 } |
|
264 } |
|
265 } |
|
266 |
|
267 // This adds a region to the stored invalid region. |
|
268 // The invalid region is the area of the screen that needs to be redrawn in addition to any animations. |
|
269 // The draw region is the area of the screen on which only the top window needs to be redrawn. |
|
270 // If the top window has transparency, this can only be true when it has been made newly visible. |
|
271 // The value of aSchedule could be determined automatically from iAnimating, but passing it this way |
|
272 // allows us to have the assert, which is a very valuable assert. |
|
273 void CScreenRedraw::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth) |
|
274 { |
|
275 WS_ASSERT_DEBUG(!iAnimating || !aSchedule, EWsPanicScheduledRedraw); |
|
276 |
|
277 if(aRegion.CheckError()) |
|
278 { |
|
279 iInvalid.ForceError(); |
|
280 |
|
281 if (aSchedule) |
|
282 ScheduleRedraw(); |
|
283 } |
|
284 else if(aRegion.Count()) // often called despite window not being visible |
|
285 { |
|
286 if (aDepth == ERedrawAll) |
|
287 { |
|
288 // red lines for an invalid region which is ready to be drawn |
|
289 DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x20),&aRegion); |
|
290 |
|
291 iInvalid.Union(aRegion); |
|
292 |
|
293 if (aSchedule) |
|
294 ScheduleRedraw(); |
|
295 } |
|
296 else |
|
297 { |
|
298 // yellow lines for a valid region which we will draw on top of |
|
299 DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x20),&aRegion); |
|
300 |
|
301 iTopLayer.Union(aRegion); |
|
302 |
|
303 if (aSchedule) |
|
304 ScheduleRedraw(); |
|
305 } |
|
306 } |
|
307 } |
|
308 |
|
309 // This causes any asynchronously scheduled redraw to happen immediately |
|
310 // It should be avoided where possible for performance reasons, but is |
|
311 // needed whenever the redraw store is discarded for a window which still |
|
312 // has a redraw region pending. |
|
313 void CScreenRedraw::DoRedrawNow() |
|
314 { |
|
315 if(!iAnimating) |
|
316 CWsTop::WindowServer()->AnimationScheduler()->DoRedrawNow(iScreen); |
|
317 } |
|
318 |
|
319 #ifdef USE_DEBUG_REGIONS |
|
320 void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect) |
|
321 { |
|
322 if (aRect) |
|
323 { |
|
324 CFbsBitGc * gc = iScreen.GetBitGc(); |
|
325 gc->SetPenColor(aColor); |
|
326 gc->SetPenStyle(CGraphicsContext::ESolidPen); |
|
327 gc->SetPenSize(TSize(2,2)); |
|
328 gc->SetBrushColor(aFill); |
|
329 gc->SetBrushStyle(CGraphicsContext::ESolidBrush); |
|
330 TRect smaller = *aRect; |
|
331 smaller.iBr.iX -= 1; |
|
332 smaller.iBr.iY -= 1; |
|
333 gc->DrawRect(smaller); |
|
334 iScreen.Update(); |
|
335 } |
|
336 } |
|
337 |
|
338 void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion) |
|
339 { |
|
340 if (aRegion) |
|
341 { |
|
342 CFbsBitGc * gc = iScreen.GetBitGc(); |
|
343 gc->SetPenColor(aColor); |
|
344 gc->SetPenStyle(CGraphicsContext::ESolidPen); |
|
345 gc->SetPenSize(TSize(2,2)); |
|
346 gc->SetBrushColor(aFill); |
|
347 gc->SetBrushStyle(CGraphicsContext::ESolidBrush); |
|
348 for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect) |
|
349 { |
|
350 TRect smaller = *rect; |
|
351 smaller.iBr.iX -= 1; |
|
352 smaller.iBr.iY -= 1; |
|
353 gc->DrawRect(smaller); |
|
354 } |
|
355 iScreen.Update(); |
|
356 } |
|
357 } |
|
358 #endif |
|
359 |
|
360 void CScreenRedraw::OnAnimation() |
|
361 { |
|
362 LOG_SCREEN_REDRAW_START |
|
363 ASSERT(!iAnimating); |
|
364 ASSERT(iScheduled); |
|
365 iAnimating = ETrue; |
|
366 iScheduled = EFalse; |
|
367 TBool futureAnimationRequired = EFalse; |
|
368 |
|
369 CWsActiveScheduler::Static()->PrepareDraw(); |
|
370 |
|
371 // Calculate any updates required by region changes: |
|
372 RegionUpdate(); |
|
373 |
|
374 // Add the timed rectangles to the invalid region: |
|
375 iNow.UniversalTime(); |
|
376 TInt count(iTimedDrawRect.Count()); |
|
377 while (0 < count) |
|
378 { |
|
379 if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64()) |
|
380 { |
|
381 iInvalid.AddRect(iTimedDrawRect[0].iRect); |
|
382 iTimedDrawRect.Remove(0); |
|
383 count--; |
|
384 } |
|
385 else |
|
386 { |
|
387 futureAnimationRequired = ETrue; |
|
388 break; |
|
389 } |
|
390 } |
|
391 |
|
392 // Animating rectangles could cause iInvalid to overlap iTopLayer, |
|
393 // in which case iTopLayer won't work. |
|
394 iTopLayer.SubRegion(iInvalid); |
|
395 iTopLayer.Intersect(iScreen.RootWindow()->WindowArea()); |
|
396 iTopLayer.Tidy(); |
|
397 // Anything in the top layer is implcitly invalid |
|
398 iInvalid.Union(iTopLayer); |
|
399 iInvalid.Intersect(iScreen.RootWindow()->WindowArea()); |
|
400 |
|
401 /* |
|
402 if (const CDebugBar* dbg = iScreen.DebugBar()) |
|
403 { |
|
404 iTopLayer.SubRect(dbg->Rect()); |
|
405 iInvalid.SubRect(dbg->Rect()); |
|
406 } |
|
407 */ |
|
408 |
|
409 iInvalid.Tidy(); |
|
410 |
|
411 if(iInvalid.CheckError()) //Will: agree with Andy, want bounding rects instead! |
|
412 { |
|
413 iTopLayer.Clear(); |
|
414 iInvalid.Clear(); |
|
415 iInvalid.Copy(iScreen.RootWindow()->WindowArea()); // assumed cannot fail, all regions can contain at least 1 rect.. |
|
416 } |
|
417 |
|
418 iInvalid.SubRegion( iBannedRegion ); |
|
419 iInvalid.Tidy(); |
|
420 iTopLayer.SubRegion( iBannedRegion ); |
|
421 iTopLayer.Tidy(); |
|
422 |
|
423 STACK_REGION invalidCopy; |
|
424 invalidCopy.Copy(iInvalid); |
|
425 TWalkWindowTreeScheduleRegions regionScheduler(&invalidCopy, iTopLayer); |
|
426 TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap()); |
|
427 TWalkWindowTreeSchedule * scheduler = ®ionScheduler; |
|
428 |
|
429 // At this point, if the DEBUG_REGION is being used: |
|
430 // Red represents invalid regions that need to be redrawn completely. |
|
431 // Yellow represents regions that only need the top window to be drawn. |
|
432 // Blue represents regions which are being animated server side. |
|
433 if (iRenderScheduled || !iInvalid.IsEmpty()) |
|
434 { |
|
435 iRenderScheduled = EFalse; |
|
436 // invalidCopy.ForceError(); //### DEBUG |
|
437 |
|
438 iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren); |
|
439 if (!regionScheduler.ScheduledRegionsOk()) |
|
440 { |
|
441 // our region calculations for what to draw failed at some point. |
|
442 // From this point on we MUST NOT rely on allocating memory |
|
443 // Andy - localRedrawRegion allocates |
|
444 // Andy - setPenSize allocates (even if you don't call it) |
|
445 // Andy - all draw commands add to a gdi dirty region (which allocates) |
|
446 // Andy - combining client clipping regions with window clipping regions allocates |
|
447 scheduler = &fallbackScheduler; |
|
448 iScreen.FallbackMap()->Prepare(); |
|
449 iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren); |
|
450 } |
|
451 |
|
452 CWsActiveScheduler::Static()->StartDraw(); |
|
453 CWsMemoryManager::Static()->EnableReserve(); |
|
454 |
|
455 if (&fallbackScheduler == scheduler) |
|
456 iAnimationRegion = iScreen.FallbackMap()->Region(); |
|
457 else |
|
458 iAnimationRegion = &iInvalid; |
|
459 |
|
460 // Redraw debug regions more brightly than before: |
|
461 DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),&iInvalid); |
|
462 DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopLayer); |
|
463 |
|
464 RWsRegion accumulatedDrawing; |
|
465 |
|
466 // Pipe the drawing into the first render stage: |
|
467 CFbsBitGc * stageGc = iRenderStages->Begin(); |
|
468 |
|
469 for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled()) |
|
470 { |
|
471 const TRegion * targetRegion = scheduler->Region(win); |
|
472 const TRect * screenRect = 0; |
|
473 if ((&fallbackScheduler == scheduler) && !targetRegion->IsContainedBy(iScreen.RootWindow()->Abs())) |
|
474 { |
|
475 screenRect = &iScreen.RootWindow()->Abs(); |
|
476 } |
|
477 if (!screenRect) |
|
478 { |
|
479 // Purple regions are about to be drawn |
|
480 DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),targetRegion); |
|
481 // Do the drawing |
|
482 stageGc->Reset(); |
|
483 win->Render(stageGc, *targetRegion); |
|
484 accumulatedDrawing.Union(*targetRegion); |
|
485 // Green regions have been drawn |
|
486 DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),targetRegion); |
|
487 } |
|
488 else |
|
489 { |
|
490 // Our region overlaps the edges of the screen, and we have no memory |
|
491 // to create a clipped one, so we will use a single-rect region for each rect |
|
492 // and call Draw multiple times. |
|
493 TRegionFix<1> rectRegion; |
|
494 for (const TRect * rect = targetRegion->RectangleList() + targetRegion->Count() - 1; rect >= targetRegion->RectangleList(); --rect) |
|
495 { |
|
496 rectRegion.Clear(); |
|
497 TRect combined(*screenRect); |
|
498 combined.Intersection(*rect); |
|
499 rectRegion.AddRect(combined); |
|
500 // Purple regions are about to be drawn |
|
501 DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),&rectRegion); |
|
502 // Do the drawing |
|
503 stageGc->Reset(); |
|
504 win->Render(stageGc, rectRegion); |
|
505 accumulatedDrawing.AddRect(combined); |
|
506 // Green regions have been drawn |
|
507 DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),&rectRegion); |
|
508 } |
|
509 } |
|
510 DEBUGOSB |
|
511 } |
|
512 |
|
513 DEBUGOSB |
|
514 iScreen.SpriteManager()->DrawFloatingSprites(stageGc,accumulatedDrawing); // we limit sprite drawing over only actually affected ares but necessary to all "planned" for redraw |
|
515 if (!accumulatedDrawing.CheckError() && iScreen.SpriteManager()->SpriteCount() == 0) |
|
516 { |
|
517 iAnimationRegion = &accumulatedDrawing; |
|
518 } |
|
519 |
|
520 // Tell the render stage we've finished: |
|
521 iRenderStages->End(); |
|
522 |
|
523 // We nolonger need the regions |
|
524 for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled()) |
|
525 { |
|
526 win->ClearScheduledRegion(); |
|
527 } |
|
528 |
|
529 CWsMemoryManager::Static()->DisableReserve(); |
|
530 |
|
531 if (const CDebugBar* dbg = iScreen.DebugBar()) |
|
532 { |
|
533 dbg->RedrawDebugBar(); |
|
534 } |
|
535 |
|
536 // At this point, if the DEBUG_REGION is being used, there should usually be only green regions |
|
537 // displayed. If we see red or yellow, then something didn't get redrawn that should have been. |
|
538 // If we see purple then a window has disobeyed the const setting on the region to draw. |
|
539 // Red or yellow is valid - a window can decide it isn't ready to draw yet - purple is very bad. |
|
540 iScreen.Update(); |
|
541 // At this point, if the DEBUG_REGION is being used, there should be no regions visible |
|
542 // of any colour. If we see green, then it means an area of the screen was drawn to which |
|
543 // wasn't invalid, or the screen update call failed. The former is more likely. |
|
544 // If we still see red or yellow it is a region that is not yet ready to draw. |
|
545 |
|
546 const TRect* rect = iAnimationRegion->RectangleList(); |
|
547 TInt pixels = 0; |
|
548 for(TInt r = iAnimationRegion->Count(); r>0; r--) |
|
549 { |
|
550 pixels += (rect->Width()*rect->Height()); |
|
551 rect++; |
|
552 } |
|
553 CWsActiveScheduler::Static()->StopDraw(pixels); |
|
554 |
|
555 TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion); |
|
556 |
|
557 iAnimationRegion = 0; |
|
558 accumulatedDrawing.Close(); |
|
559 iInvalid.Clear(); |
|
560 } |
|
561 else |
|
562 { |
|
563 CWsActiveScheduler::Static()->CancelPrepare(); |
|
564 } |
|
565 |
|
566 iInvalid.Clear(); |
|
567 iTopLayer.Clear(); |
|
568 invalidCopy.Close(); |
|
569 iAnimating = EFalse; |
|
570 |
|
571 if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled) |
|
572 { |
|
573 // If this flag is set then it means there were already some animations scheduled when we ran, |
|
574 // but they themselves didn't run. We need to make sure we have _something_ scheduled. |
|
575 CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime); |
|
576 iScheduled = ETrue; |
|
577 } |
|
578 |
|
579 if(iObserver) |
|
580 { |
|
581 iObserver->ScreenUpdated(iScreen.ScreenNumber()); |
|
582 iObserver=NULL; //once signalled we are never going to call it again |
|
583 } |
|
584 LOG_SCREEN_REDRAW_END |
|
585 } |
|
586 |
|
587 // |
|
588 void CScreenRedraw::DiscardAllSchedules() |
|
589 { |
|
590 ASSERT(!iAnimating); |
|
591 |
|
592 iTimedDrawRect.Reset(); |
|
593 iInvalid.Clear(); |
|
594 iInvalid.Tidy(); |
|
595 } |
|
596 |
|
597 /** |
|
598 Indicates that a window has moved or changed ordinal position so that the visible regions |
|
599 of all windows needs to be recalculated |
|
600 */ |
|
601 void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty) |
|
602 { |
|
603 iRegionUpdateScheduled = ETrue; |
|
604 ScheduleRedraw(); |
|
605 if(aDefinitelyDirty) |
|
606 { |
|
607 iInvalid.Union(*aDefinitelyDirty); |
|
608 // Cyan regions for invalidations caused by this: |
|
609 DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty); |
|
610 } |
|
611 } |
|
612 |
|
613 /** |
|
614 Recalculates visible regions and schedules redraws or queues redraw events in response to |
|
615 any changes |
|
616 */ |
|
617 void CScreenRedraw::RegionUpdate() |
|
618 { |
|
619 if (iRegionUpdateScheduled) |
|
620 { |
|
621 iRegionUpdateScheduled = EFalse; |
|
622 |
|
623 TWalkWindowTreeUpdateRegions updater(iScreen); |
|
624 updater.Walk(); |
|
625 |
|
626 WsPointer::ReLogCurrentWindow(); |
|
627 CWsTop::TriggerRedraws(iScreen.RootWindow()); |
|
628 } |
|
629 } |
|
630 |
|
631 void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver) |
|
632 { |
|
633 iObserver = aObserver; |
|
634 } |
|
635 |
|
636 TBool CScreenRedraw::IsUpdatePending() |
|
637 { |
|
638 if(iScheduled || iAnimating) |
|
639 return ETrue; |
|
640 else |
|
641 return EFalse; |
|
642 } |
|
643 |
|
644 /** |
|
645 Overidding MWsObjectProvider |
|
646 */ |
|
647 TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId) |
|
648 { |
|
649 TAny* interface = NULL; |
|
650 |
|
651 switch (aTypeId) |
|
652 { |
|
653 case KWsScreenRedraw: |
|
654 interface = static_cast<MWsScreenRedraw*>(this); |
|
655 break; |
|
656 } |
|
657 |
|
658 if (!interface) |
|
659 { |
|
660 interface = iRenderStages->ResolveObjectInterface(aTypeId); |
|
661 } |
|
662 |
|
663 return interface; |
|
664 } |
|
665 |
|
666 const TRegion * CScreenRedraw::AnimationRegion() const |
|
667 { |
|
668 if (iAnimating) |
|
669 return iAnimationRegion; |
|
670 else |
|
671 return 0; |
|
672 } |
|
673 |
|
674 void CScreenRedraw::UpdateDevice() |
|
675 { |
|
676 iScreen.Update(); |
|
677 } |
|
678 |
|
679 void CScreenRedraw::BanThisRegionUpdate( TRegion& aForbiddenRegion ) |
|
680 { |
|
681 iBannedRegion.Union( aForbiddenRegion ); |
|
682 iBannedRegion.Tidy(); |
|
683 } |
|
684 |
|
685 void CScreenRedraw::LiftRegionUpdateBan( TRegion& aFormerForbiddenRegion ) |
|
686 { |
|
687 iBannedRegion.SubRegion( aFormerForbiddenRegion ); |
|
688 iBannedRegion.Tidy(); |
|
689 } |
|
690 |
|
691 void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn, TBool aFadeBehind, TBool aIncludeChildren ) |
|
692 { |
|
693 if ( aFadeOn ) |
|
694 { |
|
695 TWalkWindowTreeScheduleFadeNoRedraw walkerFadeNoRedraw; |
|
696 if ( aFadeBehind ) |
|
697 { |
|
698 aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkBehind ); |
|
699 } |
|
700 else |
|
701 { |
|
702 if(aWin->WinType() != EWinTypeGroup) |
|
703 { |
|
704 ScheduleRegionUpdate( aWin->VisibleRegionIfValid() ); |
|
705 } |
|
706 |
|
707 if ( aIncludeChildren ) |
|
708 { |
|
709 aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkChildren ); |
|
710 } |
|
711 } |
|
712 } |
|
713 else |
|
714 { // fade off, just initiate redraw |
|
715 TWalkWindowTreeScheduleRedraws walkerRedraw( TWalkWindowTreeScheduleRedraws::ERedrawFilterOmitDSA ) ; |
|
716 if ( aFadeBehind ) |
|
717 { |
|
718 aWin->WalkWindowTree( walkerRedraw, EWalkBehind ); |
|
719 } |
|
720 else |
|
721 { // fade this win not behind |
|
722 if ( !aWin->IsDSAHost() ) |
|
723 { |
|
724 AddRedrawRegion( aWin->VisibleRegion() ); |
|
725 } |
|
726 if ( aIncludeChildren ) |
|
727 { |
|
728 aWin->WalkWindowTree( walkerRedraw, EWalkChildren ); |
|
729 } |
|
730 } |
|
731 } |
|
732 ScheduleRegionUpdate(NULL); |
|
733 } |