windowing/windowserver/nga/SERVER/renderorientationtracker.cpp
changeset 188 1b081cb0800b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/renderorientationtracker.cpp	Fri Sep 24 16:44:34 2010 +0300
@@ -0,0 +1,567 @@
+// 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 <hal.h>
+#include <e32std.h>
+#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::TDigitiserOrientation>
+			(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<TRenderOrientationTrackingType>(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<TInt>(&aWinGroup));
+                }            
+            break;
+
+        default:
+            error = KErrNotSupported;
+            if (wsDebugLog)
+                {
+                _LIT(logText,"Orientation Tracker: winGroup %08x has undefined orientation, Error %d");                
+                TBuf<LogTBufSize> 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)
+        {
+        _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<LogTBufSize> 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<LogTBufSize> 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<TInt>(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<TRenderOrientation>(themeOrientation);
+                break;
+            
+            default:
+                error = KErrNotSupported;
+                if (wsDebugLog)
+                    {
+                    _LIT(logText,"Orientation Tracker: Unsupported orientation %d from theme orientation property, Error %d");
+                    TBuf<LogTBufSize> 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<LogTBufSize> 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;
+    }
+