diff -r 2717213c588a -r 171fae344dd4 windowing/windowserver/nga/SERVER/renderorientationtracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nga/SERVER/renderorientationtracker.cpp Fri Jul 16 11:45:55 2010 +0300 @@ -0,0 +1,570 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This material, including documentation and any related +// computer programs, is protected by copyright controlled by +// Nokia. All rights are reserved. Copying, including +// reproducing, storing, adapting or translating, any +// or all of this material requires the prior written consent of +// Nokia. This material also contains confidential +// information which may not be disclosed to others without the +// prior written consent of Nokia. +// +// Description: +// Render Orientation Tracking and Publication +// + +#include +#include +#include "renderorientationtracker.h" +#include "rootwin.h" +#include "windowgroup.h" +#include "wstop.h" +#include "..\debuglog\DEBUGLOG.H" + +extern CDebugLogBase* wsDebugLog; + +/** Convert a TRenderOrientation value into a TDigitiserOrientation. +Note: The algorithm used makes use of the ordering of the values of the respective enums, +thus this is checked for (at compile time) at the start of the function. +@param aWservOrientation A value from the TRenderOrientation enums. +@return The equivalent value from the TDigitiserOrientation enums. +*/ +inline HALData::TDigitiserOrientation WservToDigitiser(TRenderOrientation aWservOrientation) + { + __ASSERT_COMPILE(EDisplayOrientationNormal+1 == EDisplayOrientation90CW); + __ASSERT_COMPILE(EDisplayOrientationNormal+2 == EDisplayOrientation180); + __ASSERT_COMPILE(EDisplayOrientationNormal+3 == EDisplayOrientation270CW); + __ASSERT_COMPILE(HALData::EDigitiserOrientation_000+1 == HALData::EDigitiserOrientation_090); + __ASSERT_COMPILE(HALData::EDigitiserOrientation_000+2 == HALData::EDigitiserOrientation_180); + __ASSERT_COMPILE(HALData::EDigitiserOrientation_000+3 == HALData::EDigitiserOrientation_270); + HALData::TDigitiserOrientation ret=static_cast + (HALData::EDigitiserOrientation_000 + (aWservOrientation - EDisplayOrientationNormal)); + return ret; + } + +// Todo remove/undefine this for release +#define TECHVIEW_TESTMODE + +CWsRenderOrienationTracker* CWsRenderOrienationTracker::NewL() + { + CWsRenderOrienationTracker* self = new(ELeave)CWsRenderOrienationTracker(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CWsRenderOrienationTracker::CWsRenderOrienationTracker() + : CActive(CActive::EPriorityStandard), + iRenderOrientationTrackingType(EDisplayOrientationNormal), + iPublishedRenderOrientation(EDisplayOrientationNormal) + { + CActiveScheduler::Add(this); + } + +void CWsRenderOrienationTracker::ConstructL() + { + const TSecurityPolicy KRenderOrientationReadSecurityPolicy(ECapability_None); + const TSecurityPolicy KRenderOrientationWriteSecurityPolicy(ECapabilityWriteDeviceData); + + // Define P&S Property to publish to + TInt error = RProperty::Define( KRenderOrientationCategory, + KRenderOrientationKey, + RProperty::EInt, + KRenderOrientationReadSecurityPolicy, + KRenderOrientationWriteSecurityPolicy); + + // Attach the publisher for real-time publishing + if(KErrNone == error) + error = iRenderOrientationPublisher.Attach( KRenderOrientationCategory, + KRenderOrientationKey); + + // Publish the initial value + if(KErrNone == error) + error = DoPublishOrientation(EDisplayOrientationNormal); + + //Set the initial value to HAL + if(KErrNone == error) + SetHALOrientation(EDisplayOrientationNormal); + + if (wsDebugLog && KErrNone!=error) + { + _LIT(logText,"Orientation Tracker: failed to initialise with error %d"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,logText,error); + } + User::LeaveIfError(error); + } + +CWsRenderOrienationTracker::~CWsRenderOrienationTracker() + { + Cancel(); + iRenderOrientationPublisher.Delete(KRenderOrientationCategory, KRenderOrientationKey); + iRenderOrientationPublisher.Close(); + } + +/** +If the orientation of the given window group is useable updates aOrientationTrackingType with the orientation + +@param Input: the window group to check +@param Output: the window group's orientation if usable ( otherwise unchanged ) +@return KErrNone if the orienation is usable, KErrNotFound if the orientation is not useable, KErrNotSupported if the orientation is unknown +*/ +TInt CWsRenderOrienationTracker::CheckWindowGroupOrientation(const CWsWindowGroup& aWinGroup, TRenderOrientationTrackingType& aOrientationTrackingType) + { + TInt error = KErrNone; + TRenderOrientationTrackingType tempOrientationTrackingType = static_cast(aWinGroup.WsOwner()->GetIndicatedAppOrientation()); + switch(tempOrientationTrackingType) + { + case EDisplayOrientationNormal: + case EDisplayOrientation90CW: + case EDisplayOrientation180: + case EDisplayOrientation270CW: + case EDisplayOrientationAuto: + aOrientationTrackingType = tempOrientationTrackingType; + break; + + case EDisplayOrientationIgnore: + error = KErrNotFound; + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: winGroup %08x orientation is set to be ignored"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText,reinterpret_cast(&aWinGroup)); + } + break; + + default: + error = KErrNotSupported; + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: winGroup %08x has undefined orientation, Error %d"); + TBuf buf; + buf.Format(logText, &aWinGroup, error); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,buf); + } + break; + } + + return error; + } + +/** +Checks that the given group window is appropriate for dictating the render orientation + +@param Input: The group window to check +@return ETrue is the group window is usable, else EFalse +*/ +TBool CWsRenderOrienationTracker::UseableGroupWindow(const CWsWindowGroup& aWinGroup) const + { +#ifdef TECHVIEW_TESTMODE + // for some reason IsFocusable seems to return 0 and 2, not 0 and 1 + return NULL!=aWinGroup.Child() && + (aWinGroup.IsFocusable() ? ETrue : EFalse); +#else + return (NULL!=aWinGroup.Child()); +#endif + } + +/** +Finds the topmost usable windowgroup which has a usable orientation, and outputs that orientation + +@param Output: The current render orientation +@return KErrNone if successful, KErrNotFound if the focus window group is not usable, KErrNotSupported if an invalid orientation is found +*/ +TInt CWsRenderOrienationTracker::GetFocusWindowOrientation(TRenderOrientationTrackingType& aOrientationTrackingType) + { + TInt error = KErrNone; + CWsWindowGroup* focusWinGroup = CWsTop::FocusWindowGroup(); + if(!focusWinGroup) + { + if(wsDebugLog) + { + _LIT(logText,"Orientation Tracker: focusWinGroup not found"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText); + } + error = KErrNotFound; + } + else + { + error = CheckWindowGroupOrientation(*focusWinGroup, aOrientationTrackingType); + } + return error; + } + +/** +Finds the topmost usable windowgroup which has a usable orientation, and outputs that orientation + +@param Output: The current render orientation +@return KErrNone if successful, KErrNotSupported if an invalid orientation is found +*/ +TInt CWsRenderOrienationTracker::FindOrientationFromWindowTree(TRenderOrientationTrackingType& aOrientationTrackingType) + { + TInt error = KErrNone; + TRenderOrientationTrackingType tempOrientationTrackingType = iRenderOrientationTrackingType; + CWsRootWindow* rootWin = CWsTop::CurrentFocusScreen()->RootWindow(); + TBool finished = EFalse; + for(CWsWindowGroup* winGroup = rootWin->Child(); !finished && NULL != winGroup; winGroup = winGroup->NextSibling()) + { + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: winGroup %08x has priority %d, Orientation %d, Focusable %d, Child %08x"); + TBuf buf; + buf.Format(logText, winGroup, winGroup->OrdinalPriority(), winGroup->WsOwner()->GetIndicatedAppOrientation(), + winGroup->IsFocusable()?ETrue:EFalse, winGroup->Child()); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,buf); + } + // winGroup is a higher priority ordinal, so see if it has an orientation that can be used + // although we're only interested in window groups with child windows otherwise nothing is visible anyway + if(UseableGroupWindow(*winGroup)) + { + error = CheckWindowGroupOrientation(*winGroup, tempOrientationTrackingType); + switch(error) + { + case KErrNone: + { + // List is in order, so just find the first one + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Found winGroup %08x with Orientation %d"); + TBuf buf; + buf.Format(logText, winGroup, winGroup->WsOwner()->GetIndicatedAppOrientation()); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,buf); + } + finished = ETrue; + break; + } + + case KErrNotFound: + // so keep searching + break; + + case KErrNotSupported: + default: + finished = ETrue; + break; + + } + + } + } + // Safe even in error code as won't have been changed by CheckWindowGroupOrientation + aOrientationTrackingType = tempOrientationTrackingType; + + return error; + } + +/** +First checks to see if the focus window group has a usable orientation, if so that is output. +Otherwise, finds the topmost usable windowgroup which has a usable orientation, and outputs that + +@param Output: The current render orientation +@return KErrNone if successful, KErrNotSupported if an invalid orientation is found + */ +TInt CWsRenderOrienationTracker::GetIndicatedOrientation(TRenderOrientationTrackingType& aOrientationTrackingType) + { + // First check the focus window group + TInt error = GetFocusWindowOrientation(aOrientationTrackingType); + + // Don't look for another window if the focus window is usable + // or if an error has occured, then don't change current orientation + switch(error) + { + case KErrNone: + { + if(wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Using focus window %08x for orientation"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText,reinterpret_cast(CWsTop::FocusWindowGroup())); + } + break; + } + + case KErrNotFound: + { + // Can't use focus window group, so find the topmost windowgroup with a valid orientation + error = FindOrientationFromWindowTree(aOrientationTrackingType); + break; + } + + default: + // Unrecoverable error, abort and leave published orientation unchanged + break; + } + + return error; + } + +/** +Checks to see if the render orientation has changed, and publishes any new orientaion +via publish and subscribe + +@see KRenderOrientationCategory +@see KRenderOrientationKey +*/ +void CWsRenderOrienationTracker::CheckRenderOrientation() + { + TRenderOrientationTrackingType newOrientationTrackingType = iRenderOrientationTrackingType; + TInt error = GetIndicatedOrientation(newOrientationTrackingType); + + // if the tracking type has changed... + if(KErrNone == error && iRenderOrientationTrackingType != newOrientationTrackingType) + { + if(EDisplayOrientationAuto == iRenderOrientationTrackingType) + { + // change from auto type, so we need to cancel request for updates from the theme server + Cancel(); + } + iRenderOrientationTrackingType = newOrientationTrackingType; + if(EDisplayOrientationAuto == iRenderOrientationTrackingType) + { + // Change to auto type, so we need to request updates from the theme server + // Attach to the Theme server to get orientation change updates + error = iThemeOrientationProperty.Attach( KThemeOrientationCategory, KThemeOrientationKey ); + if (wsDebugLog) + { + if(KErrNone == error) + { + // Information Log + _LIT(logText,"Orientation Tracker: Attached to theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText); + } + else + { + // Error Log + _LIT(logText,"Orientation Tracker: Error %d attaching to theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,logText, error); + } + } + + RequestDeviceOrientationNotification(); + } + // See if the has changed, and publish if it has + error = DoOrientationTracking(); + } + + if (wsDebugLog && KErrNone != error) + { + _LIT(logText,"Orientation Tracker: Error %d Checking Render Orientation"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,logText, error); + } + } + +/** +Requests notification of change of the theme server orientation + +@Pre iThemeOrientationProperty has had Attach called on it +*/ +void CWsRenderOrienationTracker::RequestDeviceOrientationNotification() + { + if(!IsActive()) + { + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Subscribing to theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText); + } + // Request for Theme Server Orientation P&S + iThemeOrientationProperty.Subscribe(iStatus); + SetActive(); + } + } + +/** +Cancels and closes (detaches) from the theme orientation publish and subscribe +*/ +void CWsRenderOrienationTracker::CancelDeviceOrientationNotification() + { + // Cancel Request for Theme Server Orientation P&S + iThemeOrientationProperty.Cancel(); + iThemeOrientationProperty.Close(); + + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Cancelled/closed theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,logText); + } + } + +/** +Called when the theme servers orientation has changed. +Re-requests unless cancelled +*/ +void CWsRenderOrienationTracker::RunL() + { + TInt error = iStatus.Int(); + if(KErrNone == error) + { + // Re-request + RequestDeviceOrientationNotification(); + + TInt error = DoOrientationTracking(); + if (wsDebugLog && KErrNone != error) + { + _LIT(logText,"Orientation Tracker: Error %d processing theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,logText, error); + } + } + else if (wsDebugLog && KErrCancel != error) + { + _LIT(logText,"Orientation Tracker: Error %d from theme orientation property, not resubscribed"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,logText, error); + } + } + +/** +Cancels the request for notification for changes to theme orientation +*/ +void CWsRenderOrienationTracker::DoCancel() + { + CancelDeviceOrientationNotification(); + } + +/** +Gets the orientation published from theme server + +@param Output: the theme server orientation +@return KErrNone if successful, KErrNotSupported if the theme server returns an unknown orientation, else any of the system wide error codes +*/ +TInt CWsRenderOrienationTracker::GetThemeOrientation(TRenderOrientation& aThemeOrientation) + { + TInt themeOrientation=EDisplayOrientationNormal; + TInt error = iThemeOrientationProperty.Get(themeOrientation); + if(wsDebugLog && KErrNone != error) + { + _LIT(logText,"Orientation Tracker: Error %d getting theme orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,logText, error); + } + + if(KErrNone == error) + { + // Translate the received orientation + switch(themeOrientation) + { + case EDisplayOrientationNormal: + case EDisplayOrientation90CW: + case EDisplayOrientation180: + case EDisplayOrientation270CW: + // only update if orientation is supported + aThemeOrientation = static_cast(themeOrientation); + break; + + default: + error = KErrNotSupported; + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Unsupported orientation %d from theme orientation property, Error %d"); + TBuf buf; + buf.Format(logText, themeOrientation, error); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,buf); + } + break; + } + } + return error; + } + +/** +Processes the indicated orientation into an actual orientation + +@return KErrNone for success, KErrNotSupported if the orientation is unknown, else any of the system wide error codes +*/ +TInt CWsRenderOrienationTracker::DoOrientationTracking() + { + TInt error = KErrNone; + TRenderOrientation newDeviceOrientation; + switch(iRenderOrientationTrackingType) + { + case EDisplayOrientationNormal: + case EDisplayOrientation90CW: + case EDisplayOrientation180: + case EDisplayOrientation270CW: + newDeviceOrientation = iRenderOrientationTrackingType; + break; + + case EDisplayOrientationAuto: + error = GetThemeOrientation(newDeviceOrientation); + break; + + default: + error = KErrNotSupported; + if (wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Unsupported orientation tracking type %d, error %d"); + TBuf buf; + buf.Format(logText, iRenderOrientationTrackingType, error); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,buf); + } + break; + } + + if(KErrNone == error) + { + error = PublishOrientation(newDeviceOrientation); + } + + return error; + } + +/** +Publishes the given value + +@param The render orientation to publish +@return KErrNone for success, else any of the system wide erro codes +*/ +TInt CWsRenderOrienationTracker::DoPublishOrientation(const TRenderOrientation aRenderOrientation) + { + TInt error = iRenderOrientationPublisher.Set(aRenderOrientation); + + // if it's published OK, then remember the newly published value + if(KErrNone == error) + { + iPublishedRenderOrientation = aRenderOrientation; + if(wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Published render orientation %d"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, logText, aRenderOrientation); + } + } + else if(wsDebugLog) + { + _LIT(logText,"Orientation Tracker: Error %d setting render orientation property"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate, logText, error); + } + return error; + } + +void CWsRenderOrienationTracker::SetHALOrientation(const TRenderOrientation aRenderOrientation) + { + // If the render orientation is EDisplayOrientationAuto then don't update HAL + // The application and HAL should always have the same state for the orientation. + if(EDisplayOrientationAuto != aRenderOrientation) + { + TInt error = HAL::Set(CWsTop::CurrentFocusScreen()->ScreenNumber(), HALData::EDigitiserOrientation, WservToDigitiser(iPublishedRenderOrientation)); + //Just log the error if there is one. + if(wsDebugLog && error != KErrNone) + { + _LIT(logText,"Orientation Tracker: Error %d setting digitiser orientation"); + wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate, logText, error); + } + } + } + +/** +If the current orientation differs from the previously published value then publishes the current value + +@param The render orientation to check and publish +@return KErrNone for success, else any of the system wide erro codes +*/ +TInt CWsRenderOrienationTracker::PublishOrientation(const TRenderOrientation aRenderOrientation) + { + TInt error = KErrNone; + + if(aRenderOrientation != iPublishedRenderOrientation) + { + // If the device Orientation has changed, publish it + error = DoPublishOrientation(aRenderOrientation); + if(KErrNone == error) + SetHALOrientation(aRenderOrientation); + } + return error; + } +