author | Gareth Stockwell <gareth.stockwell@accenture.com> |
Fri, 22 Oct 2010 11:38:29 +0100 | |
branch | bug235_bringup_0 |
changeset 206 | c170e304623f |
parent 0 | 5d03bc08d59c |
permissions | -rw-r--r-- |
// Copyright (c) 1995-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: // Group window sub-class of CWsWindow // // #include <e32std.h> #include "W32STD.H" #include "W32CLICK.H" #include "server.h" #include "rootwin.h" #include "windowgroup.h" #include "walkwindowtree.h" #include "wstop.h" #include "EVENT.H" #include "KEYCLICK.H" #include "PRIKEY.H" #include "panics.h" GLREF_D TPtr nullDescriptor; GLREF_D CDebugLogBase* wsDebugLog; #if defined(_DEBUG) TInt CWsWindowGroup::iSkipCount=0; #endif TInt CWsWindowGroup::iIdentifierCount=1; TBool CWsWindowGroup::iFocusGainPreProcess=EFalse; //'REMOVEFADINGONFOCUSGAIN' flag in INI file RPointerArray< TDblQue<CWsWindowGroup> > CWsWindowGroup::iChains(3); static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_SwEvent,ECapabilitySwEvent); static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_WriteDeviceData,ECapabilityWriteDeviceData); const TInt KArrayMaxGranularity=0x10000000; CWsWindowGroup* CWsWindowGroup::NewL(CWsClient* aOwner, CScreen* aScreen, const TWsClCmdCreateWindowGroup& aCmd) { CWsWindowGroup* self = new(ELeave) CWsWindowGroup(aOwner, aScreen); CleanupStack::PushL(self); self->ConstructL(aCmd); CleanupStack::Pop(self); return self; } CWsWindowGroup::CWsWindowGroup(CWsClient* aOwner, CScreen* aScreen) : CWsWindowBase(aOwner,WS_HANDLE_GROUP_WINDOW,aScreen) { __DECLARE_NAME(_S("CWsWindowGroup")); iWinType=EWinTypeGroup; } void CWsWindowGroup::PurgeCapturedKeys() { CWsObjectIx& objix=*WsOwner()->ObjectIndex(); const TWsObject* ptr=objix.FirstObject(); const TWsObject* end=ptr+objix.Length(); while(++ptr<end) //Fisrt one should always have a NULL object { const CWsObject* obj=ptr->iObject; if (obj && ((obj->Type()==WS_HANDLE_CAPTURE_KEY && STATIC_CAST(const CWsCaptureKey*,obj)->WindowGroup()==this) || (obj->Type()==WS_HANDLE_CAPTURE_KEY_UPDOWNS && STATIC_CAST(const CWsCaptureKeyUpsAndDowns*,obj)->WindowGroup()==this) || (obj->Type()==WS_HANDLE_CAPTURE_LONG_KEY && STATIC_CAST(const CWsCaptureLongKey*,obj)->WindowGroup()==this))) { objix.Remove(ptr); delete obj; } } objix.Tidy(); CKeyboardRepeat::CancelRepeat(this); } void CWsWindowGroup::SwitchToOwningWindow(CWsWindowGroup *aClosingWindow) { if (this==CWsTop::FocusWindowGroup()) { CWsWindowGroup *winGroup=NULL; // // First try for an 'owning' window // if (iOwningWindowGroup) { for(winGroup=RootWindow()->Child();winGroup;winGroup=winGroup->NextSibling()) if (winGroup->Identifier()==iOwningWindowGroup && winGroup->iOrdinalPriority==iOrdinalPriority) goto gotIt; } // // If that failed look for the frontmost window belonging to the owner of dying window // for(winGroup=RootWindow()->Child();winGroup;winGroup=winGroup->NextSibling()) if (winGroup!=this && winGroup->WsOwner()==WsOwner() && winGroup->iOrdinalPriority==iOrdinalPriority) goto gotIt; // // Next try for the nominated default owning window group // winGroup=iScreen->DefaultOwningWindowGroup(); if (winGroup && winGroup->iOrdinalPriority==iOrdinalPriority) { gotIt: winGroup->SetOrdinalPosition(0,this); return; } } ResetFocus(aClosingWindow); } CWsWindowGroup::~CWsWindowGroup() { if (wsDebugLog) { TLogMessageText buf; _LIT(KWSERVDebugLogGroupWindowId,"Destroying: RWindowGroup[0x%x,%d],Id=%d"); buf.Format(KWSERVDebugLogGroupWindowId,iClientHandle,LogHandle(),iIdentifier); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, buf); } if (CClick::IsHandler()) { CClick::OtherEvent(EEventGroupWindowClose,reinterpret_cast<TAny*>(iIdentifier)); } if (iQueue) { if (iQueue->Last()!=this) { //Unlink all the children of the window that is being deleted TDblQueIter<CWsWindowGroup> iter(*iQueue); CWsWindowGroup* groupWin; iter.SetToLast(); while ((groupWin=iter--)!=this) { WS_ASSERT_DEBUG(groupWin!=NULL && groupWin->iQueue==iQueue,EWsPanicGroupWindowChainError); groupWin->iChainLink.Deque(); groupWin->iQueue=NULL; } } WS_ASSERT_DEBUG(iQueue->Last()==this,EWsPanicGroupWindowChainError); TDblQueLinkBase* parentLink=iChainLink.iPrev; iChainLink.Deque(); if (parentLink->iNext==parentLink->iPrev) //Check to see chain no longer required { if (!iQueue->IsEmpty()) { //Only the parent is left in queue CWsWindowGroup* parent=iQueue->First(); static_cast<TDblQueLink*>(parentLink)->Deque(); WS_ASSERT_DEBUG(parent->iQueue==iQueue,EWsPanicGroupWindowChainError); parent->iQueue=NULL; } DeleteQueue(iQueue); } iQueue=NULL; } RemoveAllPriorityKeys(); PurgeCapturedKeys(); iTextCursor.Close(); SetPointerCursor(NULL); for(CWsClientWindow *win=Child();win;win=win->NextSibling()) win->SetInactive(); if (iScreen) { iScreen->RemoveFromDefaultOwningList(this); } CWsWindowBase::Shutdown(); TWindowServerEvent::SendGroupChangedEvents(); iClientHandle=0; // To block focus lost events being sent // Decide which window to give focus to if WServ isn't shutting down if (iScreen && !CWsTop::ShuttingDown()) SwitchToOwningWindow(this); delete iGroupName; delete iMessageArray; } void CWsWindowGroup::DeleteQueue(TDblQue<CWsWindowGroup>* aQueue) { iChains.Remove(iChains.Find(aQueue)); delete aQueue; if (iChains.Count()==0) { iChains.Compress(); } } void CWsWindowGroup::AdvanceIdentifierCount() { if (++iIdentifierCount>EMaxIdentifierCount) iIdentifierCount=1; // so limit it to low value } void CWsWindowGroup::ConstructL(const TWsClCmdCreateWindowGroup &aCmd) { #if defined(_DEBUG) if (IsClientHandleInUse(aCmd.clientHandle)) { OwnerPanic(EWservPanicDuplicateHandle); } #endif NewObjL(); iFlags=EGroupFlagAutoForeground|EGroupFlagMsgQueueNew; if (aCmd.focus) { iFlags|=EGroupFlagReceivesFocus; } iTextCursor.ConstructL(this); iClientHandle=aCmd.clientHandle; if(aCmd.screenDeviceHandle <= 0) { //Use primary screen. Client should make sure PrimaryScreenDevice is correct set up immediately after establishing session. iScreenDevice=iWsOwner->PrimaryScreenDevice(); } else { //Use the specified screen iScreenDevice=STATIC_CAST(DWsScreenDevice*,iWsOwner->HandleToObj(aCmd.screenDeviceHandle,WS_HANDLE_SCREEN_DEVICE)); } iScreen = (iScreenDevice) ? iScreenDevice->Screen() : CWsTop::Screen(); //if no screen device use screen 0 CWsWindowGroup* parent=NULL; if (aCmd.parentId>0) { parent=CWsWindowGroup::WindowGroupFromIdentifier(aCmd.parentId); if (!parent) { OwnerPanic(EWservPanicWindow); } if(parent->Screen() != iScreen) { OwnerPanic(EWservPanicWrongScreen); } if (parent->iOrdinalPriorityAdjust>0) { WS_ASSERT_DEBUG(parent->iQueue==NULL,EWsPanicGroupWindowChainError); parent->iOrdinalPriorityAdjust=0; parent->UpdateOrdinalPriority(ETrue); } iOrdinalPriorityBase=parent->iOrdinalPriorityBase; iOrdinalPriority=iOrdinalPriorityBase; } CWsWindowBase::ConstructL(RootWindow()); if (parent) { TDblQue<CWsWindowGroup>* queue=parent->iQueue; if (queue && queue->Last()!=parent) User::Leave(KErrInUse); if (parent->iWsOwner!=iWsOwner) { _LIT_SECURITY_POLICY_S0(securityPolicy,parent->iChildSID); if (!securityPolicy().CheckPolicy(iWsOwner->ClientMessage())) User::Leave(KErrPermissionDenied); } if (!queue) { queue=new(ELeave) TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink)); CleanupStack::PushL(queue); User::LeaveIfError(iChains.Append(queue)); CleanupStack::Pop(queue); queue->AddFirst(*parent); parent->iQueue=queue; } iQueue=queue; //Shouldn't set the queue until after it can leave iChainLink.Enque(&parent->iChainLink); } do { AdvanceIdentifierCount(); // Always advance by at least one to stop re-using last id } while (WindowGroupFromIdentifier(iIdentifierCount)); // If current count is in use try again iIdentifier=iIdentifierCount; iMessageArray=new(ELeave) CArrayVarSeg<TWsMessage>(1); if (CClick::IsHandler()) { TGroupWindowOpenData params; params.iIdentifier=iIdentifier; params.iClient=iWsOwner->ConnectionHandle(); params.iNumClientWindowGroups=NumClientWindowGroups()-1; //Don't include this one CClick::OtherEvent(EEventGroupWindowOpen,¶ms); } if (wsDebugLog) { TLogMessageText buf; _LIT(KWSERVDebugLogGroupWindowId,"Creating: RWindowGroup[0x%x,%d],Id=%d"); buf.Format(KWSERVDebugLogGroupWindowId,iClientHandle,LogHandle(),iIdentifier); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, buf); } } void CWsWindowGroup::UpdateOrdinalPriority(TBool aDoAdjust) { TInt newPri; newPri=iOrdinalPriorityBase; if (iWsOwner==CWsTop::FocusWindowGroupOwner()) newPri+=iOrdinalPriorityAdjust; CheckCapability(newPri); if (newPri!=iOrdinalPriority) { iOrdinalPriority=newPri; if (aDoAdjust) SetOrdinalPosition(0); } } void CWsWindowGroup::SetOrdinalPriority(TInt aPos,TInt aPriority) { if (!iQueue) { iOrdinalPriorityBase=aPriority; UpdateOrdinalPriority(EFalse); } else { TDblQueIter<CWsWindowGroup> iter(*iQueue); CWsWindowGroup* group; while ((group=iter++)!=NULL) { group->iOrdinalPriorityBase=aPriority; group->iOrdinalPriority=aPriority; } } SetOrdinalPosition(aPos); } void CWsWindowGroup::CommandL(TInt aOpcode, const TAny *aCmdData) { #ifdef _DEBUG // Save root window for performing CheckTree at the end of this func. // When aOpcode is EWsWinOpFree, this object would've been destroyed // and a call to RootWindow() in that case would be impossible CWsRootWindow* rootWindow=RootWindow(); // For certain opcodes, check for the 'screen device deleted' condition. If it // has occured for the screen device associated with this group window then // those op-codes are not valid, and the client is panicked. switch (aOpcode) { case EWsWinOpEnableScreenChangeEvents: case EWsWinOpAllowChildWindowGroup: case EWsWinOpReceiveFocus: case EWsWinOpAutoForeground: case EWsWinOpSetOrdinalPositionPri: case EWsWinOpSetOrdinalPriorityAdjust: case EWsWinOpCaptureKey: case EWsWinOpCaptureKeyUpsAndDowns: case EWsWinOpCaptureLongKey: case EWsWinOpAddPriorityKey: case EWsWinOpSetTextCursor: case EWsWinOpSetTextCursorClipped: case EWsWinOpSetOwningWindowGroup: case EWsWinOpDefaultOwningWindow: case EWsWinOpSetName: case EWsWinOpDisableKeyClick: case EWsWinOpSendPointerEvent: { if (ScreenDeviceDeleted()) OwnerPanic(EWservPanicGroupWinScreenDeviceDeleted); break; }; } #endif TWsWinCmdUnion pData; pData.any=aCmdData; if (CWsWindowBase::CommandL(aOpcode,pData)==EFalse) { switch(aOpcode) { case EWsWinOpAllowChildWindowGroup: iChildSID=*pData.UInt; break; case EWsWinOpEnableScreenChangeEvents: SetScreenChangeEventStateL(ETrue); break; case EWsWinOpDisableScreenChangeEvents: SetScreenChangeEventStateL(EFalse); break; case EWsWinOpReceiveFocus: iFlags&=~EGroupFlagReceivesFocus; if (*pData.Bool) iFlags|=EGroupFlagReceivesFocus; iScreen->ResetFocus(NULL); break; case EWsWinOpAutoForeground: iFlags&=~EGroupFlagAutoForeground; if (*pData.Bool) iFlags|=EGroupFlagAutoForeground; break; case EWsWinOpSetOrdinalPositionPri: case EWsWinOpSetOrdinalPositionErr: { TInt priority=pData.OrdinalPos->ordinalPriority; TBool hascap = CheckCapability(priority); SetOrdinalPriority(pData.OrdinalPos->pos, priority); if (aOpcode == EWsWinOpSetOrdinalPositionErr) { SetReply(hascap?KErrNone:KErrPermissionDenied); } } break; case EWsWinOpSetOrdinalPriorityAdjust: if (!iQueue) { iOrdinalPriorityAdjust=*pData.Int; UpdateOrdinalPriority(ETrue); } break; case EWsWinOpCaptureKey: { if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureKey API"))) { User::Leave(KErrPermissionDenied); } CWsCaptureKey *cKey=new(ELeave) CWsCaptureKey(this); CleanupStack::PushL(cKey); cKey->ConstructL(*pData.CaptureKey); CleanupStack::Pop(); } break; case EWsWinOpCaptureKeyUpsAndDowns: { if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureKeyUpsAndDowns API"))) { User::Leave(KErrPermissionDenied); } CWsCaptureKeyUpsAndDowns *cKey=new(ELeave) CWsCaptureKeyUpsAndDowns(this); CleanupStack::PushL(cKey); cKey->ConstructL(*pData.CaptureKey); CleanupStack::Pop(); } break; case EWsWinOpCaptureLongKey: { if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureLongKey API"))) { User::Leave(KErrPermissionDenied); } CWsCaptureLongKey *cKey=new(ELeave) CWsCaptureLongKey(this); CleanupStack::PushL(cKey); cKey->ConstructL(*pData.CaptureLongKey); CleanupStack::Pop(); } break; case EWsWinOpCancelCaptureKey: if (*pData.UInt!=0) // Ignore null handle { CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt,WS_HANDLE_CAPTURE_KEY); if (destroyObj) { //Cancel any repeat that is underway for this key const TWsWinCmdCaptureKey& capKey(*pData.CaptureKey); CKeyboardRepeat::CancelRepeat(this,capKey.key,EFalse,capKey.modifierMask); delete destroyObj; } else { #ifdef _DEBUG // Attempt to cancel key capture with an incorrect handle OwnerPanic(EWservPanicDestroy); #endif // _DEBUG } } break; case EWsWinOpCancelCaptureKeyUpsAndDowns: if (*pData.UInt!=0) // Ignore null handle { CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt,WS_HANDLE_CAPTURE_KEY_UPDOWNS); if (destroyObj) { //Cancel any repeat that is underway for this key const TWsWinCmdCaptureKey& capKey(*pData.CaptureKey); CKeyboardRepeat::CancelRepeat(this,capKey.key,EFalse,capKey.modifierMask); delete destroyObj; } else { #ifdef _DEBUG // Attempt to cancel ups and downs key capture with an incorrect handle OwnerPanic(EWservPanicDestroy); #endif // _DEBUG } } break; case EWsWinOpCancelCaptureLongKey: if (*pData.UInt!=0) // Ignore null handle { CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt,WS_HANDLE_CAPTURE_LONG_KEY); if (destroyObj) { //Cancel any repeat that is underway for this key const TWsWinCmdCaptureLongKey& capKey(*pData.CaptureLongKey); CKeyboardRepeat::CancelRepeat(this,capKey.inputKey,ETrue,capKey.modifierMask); delete destroyObj; } else { #ifdef _DEBUG // Attempt to cancel long key capture with an incorrect handle OwnerPanic(EWservPanicDestroy); #endif // _DEBUG } } break; case EWsWinOpAddPriorityKey: AddPriorityKeyL(pData.PriorityKey->keycode, pData.PriorityKey->modifierMask, pData.PriorityKey->modifiers); break; case EWsWinOpRemovePriorityKey: RemovePriorityKey(pData.PriorityKey->keycode, pData.PriorityKey->modifierMask, pData.PriorityKey->modifiers); break; case EWsWinOpSetTextCursor: iTextCursor.SetL(*pData.SetTextCursor, EFalse); break; case EWsWinOpSetTextCursorClipped: iTextCursor.SetL(*pData.SetTextCursor, ETrue); break; case EWsWinOpCancelTextCursor: iTextCursor.Cancel(); break; case EWsWinOpSetOwningWindowGroup: iOwningWindowGroup=*pData.Int; break; case EWsWinOpDefaultOwningWindow: { if(KSecurityPolicy_WriteDeviceData().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::DefaultOwningWindow API"))) { iScreen->SetDefaultOwningWindow(this); } } break; case EWsWinOpName: iWsOwner->ReplyGroupName(iGroupName,*pData.Int); break; case EWsWinOpSetName: { HBufC *newName=NULL; const TInt size=*pData.Int; if (size>0) { newName=HBufC::NewLC(size); TPtr ptr(newName->Des()); iWsOwner->RemoteReadL(ptr,0); CleanupStack::Pop(newName); } //Window Group Name is unchanged if (iGroupName && newName && *iGroupName == *newName) { delete newName; } else //Window Group Name is changed { delete iGroupName; iGroupName=newName; TWindowServerEvent::SendGroupChangedEvents(); } } break; case EWsWinOpIdentifier: SetReply(Identifier()); break; case EWsWinOpDisableKeyClick: if (*pData.Bool) iFlags|=EGroupFlagDisableKeyClick; else iFlags&=~EGroupFlagDisableKeyClick; if (this==CWsTop::FocusWindowGroup()) UpdateKeyClickState(); break; case EWsWinOpSendPointerEvent: if (!TWindowServerEvent::MousePress(*pData.RawEvent,this)) OwnerPanic(EWservPanicEventType); break; case EWsWinOpClearChildGroup: if(iQueue) { TBool fBefore=EFalse; TBool fAfter=EFalse; // If there is nothing to clear, return KErrArgument if(iQueue->Last()==this) { SetReply(KErrArgument); break; } // fBefore is True if there is AT LEAST one window group queued before the current one else if(iQueue->First()!=this) { fBefore=ETrue; } // fAfter is True if there is MORE THAN one window group queued after the current one TDblQueIter<CWsWindowGroup> iter(*iQueue); iter.SetToLast(); if(iter--!=this && iter!=this) { fAfter=ETrue; } TDblQue<CWsWindowGroup>* queue=NULL; // if fBefore and fAfter are True, create a new queue and copy all window groups after the current one into that queue if(fBefore && fAfter) { TInt ret=KErrNoMemory; queue=new TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink)); if(queue) { ret=iChains.Append(queue); if(ret!=KErrNone) { delete queue; queue = NULL; } } // Check that the queue creation and appending worked (we deque all the child groups even if it didn't) if(ret!=KErrNone) { SetReply(ret); } } // If we've got zero or one window groups after, don't need to queue them if(!fAfter || fBefore) { iter.SetToLast(); CWsWindowGroup* groupWin; while((groupWin=iter--)!=this) { groupWin->iChainLink.Deque(); groupWin->iQueue=queue; if(queue) queue->AddFirst(*groupWin); } } // if we've got no window groups before, don't need to have a queue for this anymore if(!fBefore) { iChainLink.Deque(); if (!fAfter) { DeleteQueue(iQueue); } iQueue=NULL; } } else // if this window group isn't queued, we can't clear any children { SetReply(KErrArgument); } break; case EWsWinOpSetChildGroup: { CWsWindowGroup* childWinGroup = CWsWindowGroup::WindowGroupFromIdentifier(*pData.Int); if(!childWinGroup //(no child to append) || (iQueue && (!iQueue->IsLast(this) || (childWinGroup->iQueue==iQueue))) //(GpWin has a child) || (GpWin and childGpWin in the same queue) || (childWinGroup->iQueue && !childWinGroup->iQueue->IsFirst(childWinGroup)) //(childGpWin has a parent) || (childWinGroup == this)) //(childGpWin == GpWin) { SetReply(KErrArgument); break; } if(iQueue) // If we have a chain, we're prepending ourselves to the child window group // So we take the childs chain and prepend each of the window groups in our own chain // beginning with the current window group and working backward { TDblQueIter<CWsWindowGroup> iter(*iQueue); iter.SetToLast(); CWsWindowGroup* groupWin; if(childWinGroup->iQueue) { TDblQue<CWsWindowGroup>* oldQueue=iQueue; while((groupWin=iter--)!=NULL) { groupWin->iChainLink.Deque(); childWinGroup->iQueue->AddFirst(*groupWin); groupWin->iQueue=childWinGroup->iQueue; } DeleteQueue(oldQueue); } else { iQueue->AddLast(*childWinGroup); childWinGroup->iQueue=iQueue; } } else // 1. If we don't have a chain, and if the child has a chain, we can simply prepend this wg to the child // wg chain // 2. If we don't have a chain, and if the child does not have a chain, need to create a chain with the child // as the owning member, and prepend our window group { if(childWinGroup->iQueue) { childWinGroup->iQueue->AddFirst(*this); iQueue=childWinGroup->iQueue; } else { TDblQue<CWsWindowGroup>* queue=new TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink)); TInt ret=KErrNoMemory; if (queue) { ret=iChains.Append(queue); if(ret!=KErrNone) { delete queue; } } if(ret!=KErrNone) { SetReply(ret); break; } queue->AddFirst(*childWinGroup); childWinGroup->iQueue=queue; queue->AddFirst(*this); iQueue=queue; } } } break; default: // All other window commands disallowed OwnerPanic(EWservPanicOpcode); } } #if defined(_DEBUG) rootWindow->CheckTree(); #endif } TPoint CWsWindowGroup::Origin() const { return TPoint(0,0); } TRect CWsWindowGroup::AbsRect() const { return (TRect(RootWindow()->Abs().iTl,RootWindow()->Size())); } TSize CWsWindowGroup::Size() const { return RootWindow()->Size(); } void CWsWindowGroup::UpdateKeyClickState() { CClick::SetKeyClickOveride(iFlags&EGroupFlagDisableKeyClick); } void CWsWindowGroup::SetOrdinalPosition(TInt aPos) { if (aPos==(TInt)KOrdinalPositionSwitchToOwningWindow) SwitchToOwningWindow(NULL); else SetOrdinalPosition(aPos,NULL); } TBool CWsWindowGroup::SetOrdinalPosition(TInt aPos,CWsWindowGroup* aClosingWindow) { TBool ret=ETrue; if (!iQueue) ret=DoSetOrdinalPosition1(aPos,aClosingWindow); else { TDblQueIter<CWsWindowGroup> iter(*iQueue); CWsWindowGroup* group; iter.SetToLast(); TInt after=0; TInt before=0; TInt* inc=&before; while ((group=iter--)!=NULL) { if (group==this) inc=&after; ++(*inc); } TInt lastWinGpPos=NumWindowGroupsOnMyScreen(OrdinalPriority())-after; if (aPos<0) aPos=lastWinGpPos; else aPos=Min(aPos,lastWinGpPos); aPos-=before; aPos=Max(aPos,0); iter.SetToLast(); CWsWindowGroup* firstForward=iter--; while (firstForward && firstForward->OrdinalPosition(EFalse)<aPos) { firstForward=iter--; ++aPos; } if (!firstForward) iter.SetToFirst(); else { iter.Set(*firstForward); MoveChainedWindows(iter,ETrue,aPos,aClosingWindow); iter.Set(*firstForward); iter++; } MoveChainedWindows(iter,EFalse,--aPos,aClosingWindow); #if defined(_DEBUG) iter.SetToLast(); TInt pos1=-1; TInt pos2; TBool ok=ETrue; while ((group=iter--)!=this) { pos2=group->OrdinalPosition(EFalse); if (pos2<=pos1) ok=EFalse; pos1=pos2; } WS_ASSERT_DEBUG(ok, EWsPanicGroupWindowChainError); #endif } return ret; } void CWsWindowGroup::MoveChainedWindows(TDblQueIter<CWsWindowGroup>& aIter,TBool aForward,TInt aPos,CWsWindowGroup* aClosingWindow) { CWsWindowGroup* groupWindow; while ((groupWindow=(aForward ? aIter-- : aIter++))!=NULL) { groupWindow->DoSetOrdinalPosition1(aPos,aClosingWindow); (aForward ? ++aPos : --aPos); } } TBool CWsWindowGroup::DoSetOrdinalPosition1(TInt aPos,CWsWindowGroup* aClosingWindow) { TBool ret=EFalse; if (CheckOrdinalPositionChange(aPos)) { if (Child()) // A group window with no children can not affect shadows { ret=ETrue; } DoSetOrdinalPosition2(aPos,aClosingWindow); } else iScreen->ResetFocus(aClosingWindow); return ret; } void CWsWindowGroup::DoSetOrdinalPosition2(TInt aPos, CWsWindowGroup *aClosingWindow) { ChangeWindowPosition(aPos,iParent); ResetFocus(aClosingWindow); } void CWsWindowGroup::LostFocus() { iTextCursor.LostFocus(); iWsOwner->UpdateWindowOrdinalPrioritys(); if (iClientHandle!=0) QueueEvent(EEventFocusLost); TWalkWindowTreeFocusChanged wwt(EFalse); WalkWindowTree(wwt,EWalkChildren); iWsOwner->SetClientPriority(); } void CWsWindowGroup::ReceivedFocus() { iWsOwner->UpdateWindowOrdinalPrioritys(); iTextCursor.ReceivedFocus(); // Used for event queue testing // Calling MoveToFront sets the queue of the focused window to first place, // not doing so puts the queues in unusual situation thus stress testing the queue code. // One such situation is where the focus queue is first but there is a gap before it (iEventPtr>iGlobalEventPtr)" #if defined(_DEBUG) if (++iSkipCount==5) { iSkipCount=0; } else { WsOwner()->EventQueue()->MoveToFront(); } #else WsOwner()->EventQueue()->MoveToFront(); #endif QueueEvent(EEventFocusGained); TWalkWindowTreeFocusChanged wwt(ETrue); WalkWindowTree(wwt,EWalkChildren); iWsOwner->SetClientPriority(); UpdateKeyClickState(); } TInt CWsWindowGroup::NumWindowGroups(TBool aAllPriorities, TInt aPriority) { TInt count=0; TInt screenNo; for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo) { count+=CWsWindowGroup::NumWindowGroupsOnScreen(CWsTop::Screen(screenNo)->RootWindow()->Child(),aAllPriorities,aPriority); } return(count); } TInt CWsWindowGroup::NumWindowGroupsOnScreen(const CWsWindowGroup* aGroupWin,TBool aAllPriorities,TInt aPriority) { TInt count=0; while (aGroupWin) { if (aAllPriorities || aGroupWin->iOrdinalPriority==aPriority) ++count; aGroupWin=aGroupWin->NextSibling(); } return count; } inline TInt CWsWindowGroup::NumWindowGroupsOnMyScreen(TInt aPriority) { return(CWsWindowGroup::NumWindowGroupsOnScreen(Parent()->Child(),EFalse,aPriority)); } void CWsWindowGroup::GetFocusWindowGroupL(TInt aScreenNumber) { CWsWindowGroup *groupWin=(aScreenNumber==KDummyScreenNumber)?CWsTop::FocusWindowGroup():CWsTop::Screen(aScreenNumber)->FocusWindowGroup(); if (!groupWin) User::Leave(KErrGeneral); CWsClient::SetReply(groupWin->Identifier()); } TInt CWsWindowGroup::GetWindowGroupListL(TInt aScreenNo,TBool aAllPriorities,TInt aPriority,TInt aCount,CArrayFixFlat<TInt>* aList) { TInt count=aList->Count(); CWsWindowGroup* groupWin=CWsTop::Screen(aScreenNo)->RootWindow()->Child(); while(!aAllPriorities && groupWin && groupWin->iOrdinalPriority!=aPriority) groupWin=groupWin->NextSibling(); while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==aPriority) && count<aCount) { aList->AppendL(groupWin->Identifier()); ++count; groupWin=groupWin->NextSibling(); } return count; } TInt CWsWindowGroup::SendWindowGroupListL(TInt aScreenNumber, TBool aAllPriorities, TInt aPriority, TInt aCount) { if ((aCount<1) || (aCount>(KArrayMaxGranularity/sizeof(TInt)))) User::Leave(KErrArgument); CArrayFixFlat<TInt>* list=new(ELeave) CArrayFixFlat<TInt>(aCount); CleanupStack::PushL(list); TInt count(0); TInt requestedScreen=aScreenNumber; if(requestedScreen==KDummyScreenNumber) { // get list from current focus screen first TInt focusScreenNo=CWsTop::CurrentFocusScreen()->ScreenNumber(); count=GetWindowGroupListL(focusScreenNo, aAllPriorities, aPriority, aCount, list); if(count<aCount) { // now get from the remaining screen TInt screenNo; for(screenNo=0;screenNo<CWsTop::NumberOfScreens() && count<aCount;++screenNo) { // skip focus screen if (screenNo==focusScreenNo) continue; // count hold total number of window groups collected so far count=GetWindowGroupListL(screenNo, aAllPriorities, aPriority, aCount, list); } } } else { count=GetWindowGroupListL(requestedScreen, aAllPriorities, aPriority, aCount, list); } if (list->Count() > 0) CWsClient::ReplyBuf(&list->At(0),count*sizeof(TInt)); CleanupStack::PopAndDestroy(list); return(count); // How many actually returned, may be less than asked for, but not more } void CWsWindowGroup::GetWindowGroupListAndChainL(TInt aScreen,TBool aAllPriorities,TInt aPriority ,RArray<RWsSession::TWindowGroupChainInfo>& list,TInt& aCountLeft) { CWsWindowGroup *groupWin=CWsTop::Screen(aScreen)->RootWindow()->Child(); while(!aAllPriorities && groupWin && groupWin->iOrdinalPriority!=aPriority) groupWin=groupWin->NextSibling(); while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==aPriority) && aCountLeft>0) { RWsSession::TWindowGroupChainInfo windowId; windowId.iId=groupWin->Identifier(); if(!groupWin->IsChained(windowId.iParentId)) windowId.iParentId=-1; //Unchained window group list.AppendL(windowId); --aCountLeft; groupWin=groupWin->NextSibling(); } } TInt CWsWindowGroup::SendWindowGroupListAndChainL(TBool aAllPriorities, TInt aPriority, TInt aCount) { if ((aCount<1) || (aCount>(KArrayMaxGranularity/sizeof(RWsSession::TWindowGroupChainInfo)))) User::Leave(KErrArgument); RArray<RWsSession::TWindowGroupChainInfo> list(aCount); CleanupClosePushL(list); TInt count=aCount; TInt focusScreenNo=CWsTop::CurrentFocusScreen()->ScreenNumber(); GetWindowGroupListAndChainL(focusScreenNo,aAllPriorities,aPriority,list,count); TInt screenNo; for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo) { if (screenNo!=focusScreenNo) GetWindowGroupListAndChainL(screenNo,aAllPriorities,aPriority,list,count); } if (list.Count() > 0) CWsClient::ReplyBuf(&list[0],aCount*sizeof(RWsSession::TWindowGroupChainInfo)); CleanupStack::PopAndDestroy(&list); return(aCount-count); // How many actually returned, may be less than asked for, but not more } TBool CWsWindowGroup::SendEventToAllGroups(TBool aAllPriorities,TBool aOnePerClient,const TWsClCmdSendEventToWindowGroup& aData) { TWsEvent event=aData.event; if (event.Type()==EEventKey && event.Key()->iRepeats!=0) CKeyboardRepeat::CancelRepeat(NULL); //Otherwise we will trip an invarient TInt priority=aData.parameter; TBool sentToAll=ETrue; TInt screenNo; for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo) { CWsWindowGroup *groupWin=CWsTop::Screen(screenNo)->RootWindow()->Child(); if (!aAllPriorities) { while(groupWin && groupWin->iOrdinalPriority!=priority) groupWin=groupWin->NextSibling(); } CWsWindowGroup* firstGroupWin=groupWin; CWsClient* lastOwner=NULL; CWsWindowGroup* groupWin2; while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==priority)) { if (aOnePerClient) { if (lastOwner==groupWin->iWsOwner) goto ContinueLoop; lastOwner=groupWin->iWsOwner; for(groupWin2=firstGroupWin;groupWin2!=groupWin;groupWin2=groupWin2->NextSibling()) { if (groupWin2->iWsOwner==groupWin->iWsOwner) break; } if (groupWin2->iWsOwner==groupWin->iWsOwner && groupWin2!=groupWin) goto ContinueLoop; } event.SetHandle(groupWin->ClientHandle()); if (!groupWin->EventQueue()->QueueEvent(event)) sentToAll=EFalse; ContinueLoop: groupWin=groupWin->NextSibling(); } } return sentToAll; } void CWsWindowGroup::SendMessageToAllGroupsL(CWsClient& aSender,TBool aAllPriorities,const TWsClCmdSendMessageToWindowGroup& aData) { TInt screenNo; for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo) { CWsWindowGroup* groupWin=CWsTop::Screen(screenNo)->RootWindow()->Child(); if (!aAllPriorities) { while(groupWin && groupWin->iOrdinalPriority!=aData.identifierOrPriority) groupWin=groupWin->NextSibling(); } while(groupWin && (aAllPriorities || (groupWin->iOrdinalPriority==aData.identifierOrPriority))) { groupWin->QueueMessageL(aData.uid, aData.dataLength, aSender); groupWin=groupWin->NextSibling(); } } } CWsWindowGroup *CWsWindowGroup::WindowGroupFromIdentifier(TInt aIdentifier) { // apply to all screens TInt screenNo; for (screenNo=0; screenNo<CWsTop::NumberOfScreens(); ++screenNo) { CWsWindowGroup* group; for(group=CWsTop::Screen(screenNo)->RootWindow()->Child(); group; group=group->NextSibling()) { if (group->Identifier() == aIdentifier) return group; } } return NULL; } CWsWindowGroup *CWsWindowGroup::WindowGroupFromIdentifierL(TInt aIdentifier) { CWsWindowGroup *group=WindowGroupFromIdentifier(aIdentifier); if (!group) User::Leave(KErrNotFound); return(group); } CWsWindowGroup *CWsWindowGroup::FindWindowGroupL(CWsClient* aClient, TInt aIdentifier,TInt aOffset,const TPtrC *aMatch,const TThreadId *aThreadId) { CWsWindowGroup *group; if (aIdentifier) { group=WindowGroupFromIdentifier(aIdentifier); if (group) // NULL group will cause KErrNotFound to be returned group=group->NextSibling(); } else { // get window group for this session // group = aClient->Screen()->RootWindow()->Child(); } for(;group;group=group->NextSibling()) { if (aThreadId) { if (group->WsOwner()->Client().Id()==*aThreadId) break; // Found one } else { const TDesC *groupName=&nullDescriptor; if (group->GroupName()) groupName=group->GroupName(); if (groupName->Length()>=aOffset && groupName->Mid(aOffset).MatchF(*aMatch)>=0) break; // Found one } } if (!group) User::Leave(KErrNotFound); return(group); } void CWsWindowGroup::AddPriorityKeyL(TUint aKeycode, TUint aModifierMask, TUint aModifiers) { iPriorityKeys=new(ELeave) TPriorityKey(aKeycode,aModifierMask,aModifiers,iPriorityKeys); } void CWsWindowGroup::RemovePriorityKey(TUint aKeycode, TUint aModifierMask, TUint aModifiers) { for(TPriorityKey **ppk=&iPriorityKeys;*ppk;ppk=&((*ppk)->iNext)) if ((*ppk)->Equals(aKeycode, aModifierMask, aModifiers)) { TPriorityKey *next=(*ppk)->iNext; delete *ppk; *ppk=next; break; } } void CWsWindowGroup::RemoveAllPriorityKeys() { TPriorityKey *pk=iPriorityKeys; while(pk) { TPriorityKey *next=pk->iNext; delete pk; pk=next; } } TBool CWsWindowGroup::CheckForPriorityKey(const TKeyData &aKey, TInt aScanCode) { for(TPriorityKey *pk=iPriorityKeys;pk;pk=pk->iNext) { if (pk->KeyMatches(aKey)) { WsOwner()->PriorityKeyPressed(ClientHandle(),aKey, aScanCode); return(ETrue); } } return(EFalse); } void CWsWindowGroup::StatusDump(TDes &aBuf) { _LIT(KWSERVStatusDumpWindowGroupInfo,"CWsWindowGroup[0x%x]RWindowGroup[0x%x,%d],Pri=%d,Id=%d,SizeMode=%d"); aBuf.AppendFormat(KWSERVStatusDumpWindowGroupInfo,this,iClientHandle,LogHandle(),iOrdinalPriority,iIdentifier,iScreenDevice?iScreenDevice->AppMode():0); } void CWsWindowGroup::SignalMessageReady() { TWsEvent event; event.SetType(EEventMessageReady); event.SetHandle(ClientHandle()); event.SetTimeNow(); SEventMessageReady& eventMessageReady=*(SEventMessageReady*)event.EventData(); eventMessageReady.iWindowGroupIdentifier=Identifier(); eventMessageReady.iMessageUid=(*iMessageArray)[0].iUid; eventMessageReady.iMessageParametersSize=iMessageArray->Length(0)-sizeof(TUid); if(WsOwner()->EventQueue()->QueueEvent(event,EEventPriorityHigh)) { iFlags|=EGroupFlagMessageSignalled; } } void CWsWindowGroup::QueueMessageL(TUid aUid, TInt aDataLength, CWsClient& aSender) { WS_ASSERT_DEBUG(iFlags&(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew) || iMessageArray->Count()>=1,EWsPanicMsgQueueError); if (!(iFlags&(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew)) && iMessageArray->Count()>=KMaxNumberOfMsgsInInactiveQueue) { WS_ASSERT_DEBUG(iMessageArray->Count()<=KMaxNumberOfMsgsInInactiveQueue,EWsPanicMsgQueueError); iMessageArray->Delete(1,iMessageArray->Count()-1); } TWsMessage* message=NULL; TRAPD(err,message=&iMessageArray->ExtendL(aDataLength+sizeof(aUid))); if ((err || (iFlags&EGroupFlagMsgQueueNew)) && iMessageArray->Count()>KMaxNumberOfMsgsInQueue) { iFlags&=~(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew); iMessageArray->Delete(1,iMessageArray->Count()-(err?1:2)); iMessageArray->Compress(); } User::LeaveIfError(err); if (message) { message->iUid=aUid; TPtr8 ptr(&message->iTheRest[0],aDataLength); TRAP(err,aSender.RemoteReadL(ptr,0)); if (err) { iMessageArray->Delete(iMessageArray->Count()-1); User::Leave(err); } if (!(iFlags&EGroupFlagMessageSignalled)) { WS_ASSERT_DEBUG(iMessageArray->Count()==1,EWsPanicMsgQueueError); SignalMessageReady(); } } } void CWsWindowGroup::FetchMessageL() { if (!(iFlags&EGroupFlagMessageSignalled)) { OwnerPanic(EWservPanicFetchMessage); } CWsClient::ReplyBuf(&((*iMessageArray)[0].iTheRest[0]),(TInt)iMessageArray->Length(0)-sizeof(TUid)); iMessageArray->Delete(0); iFlags|=EGroupFlagMsgQueueActive; iFlags&=~(EGroupFlagMessageSignalled|EGroupFlagMsgQueueNew); if (iMessageArray->Count()>0) { SignalMessageReady(); } } TBool CWsWindowGroup::ScreenDeviceValid() const { return(iScreenDevice?iScreenDevice->ScreenDeviceValidState():(iScreen->ScreenSizeMode()==0)); } TBool CWsWindowGroup::CanReceiveFocus() const { return(ReceivesFocus() && iWsOwner->NotClosing() && (ScreenDeviceValid() || iFlags&EGroupFlagHandlesDeviceChange)); } void CWsWindowGroup::SetScreenChangeEventStateL(TBool aEnabled) { iFlags&=~EGroupFlagHandlesDeviceChange; if (aEnabled) { iFlags|=EGroupFlagHandlesDeviceChange; TWindowServerEvent::AddToScreenDeviceChangeEventListL(*this); if (iScreen->ScreenSizeMode()!=0) TWindowServerEvent::SendScreenDeviceChangedEvent(this); } else TWindowServerEvent::RemoveFromScreenDeviceChangeEventList(*this); iScreen->ResetFocus(NULL); } void CWsWindowGroup::SetScreenDeviceValidState(const DWsScreenDevice *aDevice) { if (iScreenDevice==aDevice) { TBool state=ScreenDeviceValid(); for(CWsClientWindow *win=Child();win;win=win->NextSibling()) { win->SetScreenDeviceValidState(state); } } } void CWsWindowGroup::SetScreenDeviceValidStates(const DWsScreenDevice *aDevice) { for(CWsWindowGroup *groupWin=aDevice->RootWindow()->Child();groupWin;groupWin=groupWin->NextSibling()) groupWin->SetScreenDeviceValidState(aDevice); } TBool CWsWindowGroup::SetScreenDeviceValidStates(const TBool aScreenSizeChanged,const TBool aSwapWidthAndHeight, CScreen* aScreen) { TBool ret=EFalse; CWsRootWindow* rootWindow = aScreen->RootWindow(); CWsWindowGroup* groupWin; CWsClientWindow* win; for(groupWin=rootWindow->Child();groupWin;groupWin=groupWin->NextSibling()) { TBool state=groupWin->ScreenDeviceValid(); for(win=groupWin->Child();win;win=win->NextSibling()) { win->SetScreenDeviceValidStateFlag(state); win->ResetHiddenFlagsInParentAndChildren(); } } if (aScreenSizeChanged) { rootWindow->ScreenSizeChanged(aSwapWidthAndHeight); } aScreen->AddRedrawRegion(rootWindow->WindowArea()); return ret; } void CWsWindowGroup::SetScreenDevice(DWsScreenDevice *aDevice) { iScreenDevice=aDevice; } void CWsWindowGroup::NewOrientation(TInt aMode,CFbsBitGc::TGraphicsOrientation aRotation, CWsRootWindow* aRootWindow) { for(CWsWindowGroup *groupWin=aRootWindow->Child();groupWin;groupWin=groupWin->NextSibling()) { DWsScreenDevice *device=groupWin->Device(); if (device) device->NewOrientation(aMode,aRotation); } } void CWsWindowGroup::ResetFocus(CWsWindowGroup *aClosingWindow) { if (iScreen) { iScreen->ResetFocus(aClosingWindow); } } TBool CWsWindowGroup::IsChained(TInt& aParentId) { if (!iQueue) return EFalse; if (iQueue->First()==this) aParentId=0; else aParentId=BeforeInChain()->Identifier(); return ETrue; } inline CWsWindowGroup* CWsWindowGroup::BeforeInChain() { //You should only call this function if you know the window has a parent return reinterpret_cast<CWsWindowGroup*>(PtrSub(iChainLink.iPrev,_FOFF(CWsWindowGroup,iChainLink))); } TBool CWsWindowGroup::CheckCapability(TInt& aOrdinalPriority) { if(aOrdinalPriority>=KPasswordWindowGroupPriority) { if(!KSecurityPolicy_SwEvent().CheckPolicy(WsOwner()->Client(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed"))) { aOrdinalPriority=KPasswordWindowGroupPriority-1; return EFalse; } } return ETrue; } TBool CWsWindowGroup::HasVisibleTranslucentChild() { CWsWindowBase * child = iChild; while (child) { if (child->WinType() == EWinTypeClient) { CWsClientWindow * cliwin = static_cast<CWsClientWindow *>(child); if (cliwin->IsTranslucent() && cliwin->IsVisible()) return ETrue; } else if (static_cast<CWsWindowGroup*>(child)->HasVisibleTranslucentChild()) { return ETrue; } child = child->NextSibling(); } return EFalse; } TInt CWsWindowGroup::NumClientWindowGroups() { CWsObjectIx& objix=*WsOwner()->ObjectIndex(); const TWsObject* ptr=objix.FirstObject(); const TWsObject* end=ptr+objix.Length(); TInt count=0; while(++ptr<end) //First one should always have a NULL object { const CWsObject* obj=ptr->iObject; if (obj && obj->Type()==WS_HANDLE_GROUP_WINDOW) ++count; } return count; }