|
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 // Window functions |
|
15 // |
|
16 // |
|
17 |
|
18 #include "server.h" |
|
19 #include "rootwin.h" |
|
20 #include "window.h" |
|
21 #include "walkwindowtree.h" |
|
22 #include "wstop.h" |
|
23 #include "ScrDev.H" |
|
24 #include "EVENT.H" |
|
25 #include "ANIM.H" |
|
26 #include "Direct.H" |
|
27 #include "panics.h" |
|
28 #include "backedupwindow.h" |
|
29 #include "wstypes.h" |
|
30 #include "offscreenbitmap.h" |
|
31 |
|
32 CWsWindow* CWsWindow::iAccessListRecentEnd = 0; |
|
33 CWsWindow* CWsWindow::iAccessListOldestEnd = 0; |
|
34 |
|
35 CWsWindow::CWsWindow(CWsClient* aOwner,WH_HANDLES aType, CScreen* aScreen) : CWsWindowBase(aOwner,aType,aScreen), |
|
36 iFlags(EFlagHidden), |
|
37 iDSAs(_FOFF(CWsDirectScreenAccess,iMultipleDSALink)) |
|
38 { |
|
39 } |
|
40 |
|
41 CWsWindow::~CWsWindow() |
|
42 { |
|
43 iFadableRegion.Close(); |
|
44 } |
|
45 |
|
46 void CWsWindow::Construct() |
|
47 { |
|
48 InsertIntoAccessListOldestEnd(); |
|
49 } |
|
50 |
|
51 void CWsWindow::Shutdown() |
|
52 { |
|
53 TWindowServerEvent::NotifyDrawer(TWservCrEvent(TWservCrEvent::EWindowClosing, 0, 0, this)); |
|
54 RemoveFromAccessList(); |
|
55 CWsAnim::WindowClosing(iAnimList); // Destroy any animated objects attached to this window |
|
56 iVisibleRegion.Close(); |
|
57 iScheduledRegion.Close(); |
|
58 AbortAllDSAs(); |
|
59 CWsWindowBase::Shutdown(); |
|
60 SetPointerCursor(NULL); |
|
61 delete iRedraw; |
|
62 } |
|
63 |
|
64 // |
|
65 // Region and invalid area functions // |
|
66 // |
|
67 |
|
68 TRect CWsWindow::FullRect() const |
|
69 { |
|
70 return(TRect(iOrigin,iRel.Size())); |
|
71 } |
|
72 |
|
73 // |
|
74 // Normal regions // |
|
75 // |
|
76 |
|
77 void CWsWindow::SetNonFading(TBool aNonFade) |
|
78 { |
|
79 if (aNonFade) |
|
80 iFlags|=EFlagNonFadingWindow; |
|
81 else |
|
82 iFlags&=(~EFlagNonFadingWindow); |
|
83 } |
|
84 |
|
85 TPoint CWsWindow::InquireOffset(TUint32 aHandle) const |
|
86 { |
|
87 CWsWindowBase *win2; |
|
88 iWsOwner->HandleToWindow(aHandle,&win2); |
|
89 return(iOrigin-win2->Origin()); |
|
90 } |
|
91 |
|
92 TDisplayMode CWsWindow::DisplayMode() const |
|
93 { |
|
94 return iScreen->DisplayMode(); |
|
95 } |
|
96 |
|
97 void CWsWindow::StatusDump(TDes &aBuf) |
|
98 { |
|
99 _LIT(KStatusString1,"CWsWindow[0x%x]RWindow[0x%x,%d],Pos(%d,%d),Size(%d,%d)"); |
|
100 _LIT(KStatusString3,",Mode=%d"); |
|
101 _LIT(KStatusInvisible,",Inv"); |
|
102 aBuf.AppendFormat(KStatusString1,this,iClientHandle,LogHandle(),iRel.iTl.iX,iRel.iTl.iY,Size().iWidth,Size().iHeight); |
|
103 aBuf.AppendFormat(KStatusString3,(TInt)iScreen->DisplayMode()); |
|
104 if (!IsVisible()) |
|
105 aBuf.Append(KStatusInvisible); |
|
106 } |
|
107 |
|
108 TDblQue<TPointerKeyList> *CWsWindow::PointerKeyList() const |
|
109 { |
|
110 return(NULL); |
|
111 } |
|
112 |
|
113 void CWsWindow::AbortAllDSAs() |
|
114 { |
|
115 iScreen->AbortDSAs(RDirectScreenAccess::ETerminateRegion,iDSAs); |
|
116 } |
|
117 |
|
118 void CWsWindow::PossibleVisibilityChangedEvent(TBool aForceSend) |
|
119 { |
|
120 // notify plugin |
|
121 // |
|
122 TWservCrEvent crEvent(TWservCrEvent::EWindowVisibilityChanged, HasBeenDrawnToScreen(), IsVisible()? &iVisibleRegion : NULL, this); |
|
123 TWindowServerEvent::NotifyDrawer(crEvent); |
|
124 |
|
125 if (!(iFlags & EFlagGeneratesVisibilityEvents)) |
|
126 return; |
|
127 |
|
128 if (!IsVisible()) |
|
129 { |
|
130 goto notvisible; |
|
131 } |
|
132 |
|
133 if (iVisibleRegion.Count() == 0) |
|
134 { |
|
135 goto notvisible; |
|
136 } |
|
137 |
|
138 {// braces here to avoid gccxml error |
|
139 TInt visibleArea = 0; |
|
140 TInt count = iVisibleRegion.Count(); |
|
141 TInt ii; |
|
142 for (ii = 0; ii < count; ii++) |
|
143 { |
|
144 visibleArea+= iVisibleRegion[ii].Width() * iVisibleRegion[ii].Height(); |
|
145 } |
|
146 |
|
147 const TRegion* baseRegion = (static_cast<CWsClientWindow*>(this))->BaseArea(); |
|
148 TInt baseArea = 0; |
|
149 count = baseRegion->Count(); |
|
150 for (ii = 0; ii < count; ii++) |
|
151 { |
|
152 const TRect& rect = (*baseRegion)[ii]; |
|
153 baseArea+= rect.Width() * rect.Height(); |
|
154 } |
|
155 |
|
156 if (visibleArea == baseArea) |
|
157 { |
|
158 goto fullyvisible; |
|
159 } |
|
160 else |
|
161 { |
|
162 goto partiallyvisible; |
|
163 } |
|
164 } |
|
165 |
|
166 fullyvisible: |
|
167 if (aForceSend || !(iFlags & EFlagNotCantBeSeen) || !(iFlags & EFlagCanBeSeen)) |
|
168 { |
|
169 iFlags |= (EFlagCanBeSeen | EFlagNotCantBeSeen); |
|
170 TWindowServerEvent::SendVisibilityChangedEvents(this, TWsVisibilityChangedEvent::EPartiallyVisible | TWsVisibilityChangedEvent::EFullyVisible); |
|
171 // we have to set EPartiallyVisible too for compatibility reasons |
|
172 } |
|
173 return; |
|
174 |
|
175 partiallyvisible: |
|
176 if (aForceSend || !(iFlags & EFlagCanBeSeen) || (iFlags & EFlagNotCantBeSeen)) |
|
177 { |
|
178 iFlags |= EFlagCanBeSeen; |
|
179 iFlags &= ~EFlagNotCantBeSeen; |
|
180 TWindowServerEvent::SendVisibilityChangedEvents(this, TWsVisibilityChangedEvent::EPartiallyVisible); |
|
181 } |
|
182 return; |
|
183 |
|
184 notvisible: |
|
185 if (aForceSend || (iFlags & EFlagCanBeSeen) || (iFlags & EFlagNotCantBeSeen)) |
|
186 { |
|
187 iFlags &= ~(EFlagCanBeSeen | EFlagNotCantBeSeen); |
|
188 TWindowServerEvent::SendVisibilityChangedEvents(this, TWsVisibilityChangedEvent::ENotVisible); |
|
189 } |
|
190 return; |
|
191 } |
|
192 |
|
193 TPoint CWsWindow::Origin() const |
|
194 { |
|
195 return iOrigin; |
|
196 } |
|
197 |
|
198 TRect CWsWindow::AbsRect() const |
|
199 { |
|
200 return iAbs; |
|
201 } |
|
202 |
|
203 TSize CWsWindow::Size() const |
|
204 { |
|
205 return iRel.Size(); |
|
206 } |
|
207 |
|
208 TBool CWsWindow::SetScheduledRegion(const RWsRegion& aRegion) |
|
209 { |
|
210 iScheduledRegion.Copy(aRegion); |
|
211 return !iScheduledRegion.CheckError(); |
|
212 } |
|
213 |
|
214 void CWsWindow::ClearScheduledRegion() |
|
215 { |
|
216 iScheduledRegion.Clear(); |
|
217 } |
|
218 |
|
219 void CWsWindow::SetFadeBehind(TBool aFade) |
|
220 { |
|
221 if (aFade != ((iFlags & EFlagFadeBehind) != 0)) |
|
222 { |
|
223 iFlags ^= EFlagFadeBehind; |
|
224 } |
|
225 } |
|
226 |
|
227 void CWsWindow::FocusChanged(TBool aNewFocusState) |
|
228 { |
|
229 TRAPD(err,FocusChangedL(aNewFocusState)); |
|
230 if (err!=KErrNone) |
|
231 OwnerPanic(EWservPanicAnimLeave); |
|
232 } |
|
233 |
|
234 void CWsWindow::FocusChangedL(TBool aNewFocusState) |
|
235 { |
|
236 for (CWsAnim * anim = iAnimList; anim; anim = anim->Next()) |
|
237 { |
|
238 anim->FocusChanged(aNewFocusState); |
|
239 } |
|
240 } |
|
241 |
|
242 // Moves a window to the recent end of the accessed list |
|
243 void CWsWindow::Accessed() |
|
244 { |
|
245 WS_ASSERT_DEBUG(iAccessListRecentEnd && iAccessListOldestEnd, EWsPanicAccessList); |
|
246 |
|
247 RemoveFromAccessList(); |
|
248 InsertIntoAccessListRecentEnd(); |
|
249 } |
|
250 |
|
251 void CWsWindow::InsertIntoAccessListOldestEnd() |
|
252 { |
|
253 iAccessListPrev = 0; |
|
254 iAccessListNext = iAccessListOldestEnd; |
|
255 if (iAccessListNext) |
|
256 iAccessListNext->iAccessListPrev = this; |
|
257 iAccessListOldestEnd = this; |
|
258 if (!iAccessListRecentEnd) |
|
259 iAccessListRecentEnd = this; |
|
260 } |
|
261 |
|
262 void CWsWindow::InsertIntoAccessListRecentEnd() |
|
263 { |
|
264 iAccessListNext = 0; |
|
265 iAccessListPrev = iAccessListRecentEnd; |
|
266 if (iAccessListPrev) |
|
267 iAccessListPrev->iAccessListNext = this; |
|
268 iAccessListRecentEnd = this; |
|
269 if (!iAccessListOldestEnd) |
|
270 iAccessListOldestEnd = this; |
|
271 } |
|
272 |
|
273 void CWsWindow::RemoveFromAccessList() |
|
274 { |
|
275 if (iAccessListOldestEnd == this) |
|
276 iAccessListOldestEnd = iAccessListNext; |
|
277 if (iAccessListRecentEnd == this) |
|
278 iAccessListRecentEnd = iAccessListPrev; |
|
279 if (iAccessListPrev) |
|
280 iAccessListPrev->iAccessListNext = iAccessListNext; |
|
281 if (iAccessListNext) |
|
282 iAccessListNext->iAccessListPrev = iAccessListPrev; |
|
283 } |
|
284 |
|
285 TBool CWsWindow::ReleaseMemory(MWsMemoryRelease::TMemoryReleaseLevel aLevel) |
|
286 { |
|
287 for (CWsWindow * access = iAccessListOldestEnd; access; access = access->iAccessListNext) |
|
288 { |
|
289 if(access->Redraw()) |
|
290 { |
|
291 if (access->Redraw()->ReleaseMemory(aLevel)) |
|
292 return ETrue; |
|
293 } |
|
294 } |
|
295 return EFalse; |
|
296 } |
|
297 |
|
298 const TRegion& CWsWindow::VisibleRegion() const |
|
299 { |
|
300 return(iVisibleRegion); |
|
301 } |
|
302 |
|
303 TBool CWsWindow::IsDSAHost() const |
|
304 { |
|
305 TBool res = EFalse; |
|
306 if ( !iDSAs.IsEmpty() ) |
|
307 { |
|
308 TSglQueIter<CWsDirectScreenAccess> iter( (TSglQueBase&)iDSAs ); |
|
309 iter.SetToFirst(); |
|
310 CWsDirectScreenAccess* dsa; |
|
311 while ( (dsa = iter++) != NULL && !res ) |
|
312 { |
|
313 res = dsa->IsVisible() || dsa->IsSyncTimeoutPending(); |
|
314 } |
|
315 } |
|
316 return res; |
|
317 } |
|
318 |
|
319 void CWsWindow::ResetVisibleRegion() |
|
320 { |
|
321 if (!iVisibleRegion.IsEmpty()) |
|
322 { |
|
323 iVisibleRegion.Clear(); |
|
324 } |
|
325 iFadableRegion.Clear(); |
|
326 } |
|
327 |
|
328 void CWsWindow::SetVisibleRegion(const TRegion& aNewRegion, const TRegion* aTop, TRegion& aNewFadableRegion) |
|
329 { |
|
330 STACK_REGION difference; |
|
331 TBool diffs = EFalse; |
|
332 |
|
333 difference.Copy(iVisibleRegion); |
|
334 difference.SubRegion(aNewRegion); |
|
335 if (!difference.IsEmpty()) |
|
336 { |
|
337 diffs = ETrue; |
|
338 if (IsTranslucent()) |
|
339 { |
|
340 // Andy - If this is a client window (what else could it be) we can also subtract the |
|
341 // user defined opaque region before doing this: |
|
342 iScreen->AddRedrawRegion(difference, EFalse); |
|
343 } |
|
344 } |
|
345 |
|
346 difference.Copy(aNewRegion); |
|
347 if (HasBeenDrawnToScreen()) |
|
348 { |
|
349 difference.SubRegion(iVisibleRegion); |
|
350 } |
|
351 if (!difference.IsEmpty()) |
|
352 { |
|
353 diffs = ETrue; |
|
354 STACK_REGION topDiff; |
|
355 topDiff.Copy(difference); |
|
356 WS_ASSERT_DEBUG(aTop,EWsPanicRegion); |
|
357 topDiff.Intersect(*aTop); |
|
358 difference.SubRegion(topDiff); |
|
359 iScreen->AddRedrawRegion(topDiff, EFalse, ERedrawTopOnly); |
|
360 iScreen->AddRedrawRegion(difference, EFalse, ERedrawAll); |
|
361 topDiff.Close(); |
|
362 } |
|
363 |
|
364 difference.Close(); |
|
365 |
|
366 AbortDsaIfRequired(aNewRegion, aTop); |
|
367 |
|
368 if (diffs) |
|
369 { |
|
370 ResetVisibleRegion(); |
|
371 iVisibleRegion.Copy(aNewRegion); |
|
372 PossibleVisibilityChangedEvent(EFalse); |
|
373 } |
|
374 |
|
375 iFadableRegion.Copy( aNewFadableRegion ); |
|
376 |
|
377 // Just because the visible region (screen coordinates) didn't change doesn't |
|
378 // mean the invalid region (window coordinates) didn't change, so we always call this. |
|
379 iRedraw->VisibleRegionChange(); |
|
380 } |
|
381 |
|
382 void CWsWindow::ClearVisibleRegion() |
|
383 { |
|
384 AbortAllDSAs(); |
|
385 iScreen->AddRedrawRegion(VisibleRegion(), EFalse); |
|
386 ResetVisibleRegion(); |
|
387 PossibleVisibilityChangedEvent(EFalse); |
|
388 iFlags &= ~EFlagDrawnToScreen; |
|
389 } |
|
390 |
|
391 void CWsWindow::AbortDsaIfRequired(const TRegion& aNewRegion, const TRegion* aTop) |
|
392 { |
|
393 if (!iDSAs.IsEmpty()) |
|
394 { |
|
395 // If the top visible region of this window has changed, DSA clients may need |
|
396 // to be sent a DSA abort, as they may be drawing to a different region |
|
397 STACK_REGION newTopVisible; |
|
398 newTopVisible.Copy(aNewRegion); // new visible region |
|
399 if (aTop!=NULL) |
|
400 { |
|
401 newTopVisible.Intersect(*aTop); // area of new visible region not obscured by any other opaque or translucent windows |
|
402 } |
|
403 // Build a list of DSA clients that need to be sent a DSA abort |
|
404 TSglQue<CWsDirectScreenAccess> dsaList(_FOFF(CWsDirectScreenAccess,iAbortLink)); |
|
405 TSglQueIter<CWsDirectScreenAccess> iter(iDSAs); |
|
406 CWsDirectScreenAccess* dsa; |
|
407 while ((dsa=iter++)!=NULL) |
|
408 { |
|
409 if (dsa->IsAbortRequired(newTopVisible)) |
|
410 { |
|
411 dsaList.AddLast(*dsa); |
|
412 } |
|
413 } |
|
414 if (!dsaList.IsEmpty()) |
|
415 { |
|
416 iScreen->AbortDSAs(RDirectScreenAccess::ETerminateRegion, dsaList); |
|
417 } |
|
418 newTopVisible.Close(); |
|
419 } |
|
420 } |
|
421 |
|
422 const TRegion* CWsWindow::VisibleRegionIfValid() const |
|
423 { |
|
424 return iVisibleRegion.CheckError() ? NULL : &iVisibleRegion; |
|
425 } |
|
426 |
|
427 TBool CWsWindow::ReadyToDraw() const |
|
428 { |
|
429 return iRedraw->ReadyToDraw(); |
|
430 } |
|
431 |
|
432 /** |
|
433 This function draws the region specified |
|
434 Andy - I would be happier if no region was specified here - the GC should incorporate that information |
|
435 */ |
|
436 void CWsWindow::Render(CFbsBitGc * aGc, const TRegion& aRegion) |
|
437 { |
|
438 WS_ASSERT_DEBUG(IsVisible() || (WinType() == EWinTypeRoot), EWsPanicScheduledRedraw); |
|
439 |
|
440 Accessed(); |
|
441 iFlags |= EFlagDrawnToScreen; |
|
442 |
|
443 iRedraw->PreDrawWindow(aGc, aRegion); |
|
444 iRedraw->DrawWindow(); |
|
445 iRedraw->PostDrawWindow(aGc); |
|
446 } |
|
447 |
|
448 void CWsWindow::SetNextScheduled(CWsWindow * aWin) |
|
449 { |
|
450 iNextScheduled = aWin; |
|
451 } |
|
452 |
|
453 CWsWindow * CWsWindow::NextScheduled() const |
|
454 { |
|
455 return iNextScheduled; |
|
456 } |
|
457 |
|
458 void CWsWindow::AddSprite(CWsSpriteBase * aSprite) |
|
459 { |
|
460 aSprite->SetNext(iSpriteList); |
|
461 iSpriteList = aSprite; |
|
462 } |
|
463 |
|
464 void CWsWindow::RemoveSprite(CWsSpriteBase * aSprite) |
|
465 { |
|
466 if (aSprite == iSpriteList) |
|
467 { |
|
468 iSpriteList = aSprite->Next(); |
|
469 } |
|
470 else |
|
471 { |
|
472 for (CWsSpriteBase * sprite = iSpriteList; sprite; sprite = sprite->Next()) |
|
473 { |
|
474 if (sprite->Next() == aSprite) |
|
475 { |
|
476 sprite->SetNext(aSprite->Next()); |
|
477 } |
|
478 } |
|
479 } |
|
480 aSprite->SetNext(0); |
|
481 } |
|
482 |
|
483 void CWsWindow::DeactivateAllSprites() |
|
484 { |
|
485 CWsSpriteBase * current = iSpriteList; |
|
486 while (current) |
|
487 { |
|
488 CWsSpriteBase * next = current->Next(); |
|
489 current->Deactivate(); |
|
490 current = next; |
|
491 } |
|
492 } |
|
493 |
|
494 void CWsWindow::ClipRectToViewport(TRect& aRect) const |
|
495 { |
|
496 const CWsWindowBase * win = this; |
|
497 while (win) |
|
498 { |
|
499 if (win->WinType() != EWinTypeGroup) |
|
500 { |
|
501 aRect.Intersection(win->AbsRect()); |
|
502 } |
|
503 win = win->BaseParent(); |
|
504 } |
|
505 } |
|
506 |
|
507 const TRegion& CWsWindow::FadableRegion() const |
|
508 { |
|
509 return iFadableRegion; |
|
510 } |
|
511 |
|
512 /** |
|
513 MWsWindow |
|
514 */ |
|
515 MWsWindow * CWsWindow::FindChildByHandle(TUint32 aHandle) |
|
516 { |
|
517 TWalkWindowTreeFindByHandle wwt(aHandle); |
|
518 WalkWindowTree(wwt, EWalkChildren); |
|
519 return wwt.Found(); |
|
520 } |
|
521 |
|
522 TUint32 CWsWindow::Handle() const |
|
523 { |
|
524 return ClientHandle(); |
|
525 } |
|
526 |
|
527 MWsScreen * CWsWindow::WsScreen() const |
|
528 { |
|
529 return iScreen; |
|
530 } |
|
531 |
|
532 TInt CWsWindow::OrdinalPriority() const |
|
533 { |
|
534 return iOrdinalPriority; |
|
535 } |