tactilefeedback/tactilefeedbackclient/src/touchfeedbackimpl.cpp
changeset 0 d54f32e146dd
child 3 1b74118366fe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tactilefeedback/tactilefeedbackclient/src/touchfeedbackimpl.cpp	Thu Dec 17 08:53:38 2009 +0200
@@ -0,0 +1,1774 @@
+/*
+* Copyright (c) 2007-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:  This is the actual Client API implementation.
+* Part of:      Tactile Feedback.
+*
+*/
+
+#include <eikenv.h>
+#include <coecntrl.h>
+#include <featmgr.h>
+#include <aknutils.h> 
+#include <tactilefeedbacktrace.h>
+#include <touchfeedbackspec.h>
+
+#include "touchfeedbackimpl.h"
+#include "touchfeedbackclient.h"
+#include "touchfeedbackregistry.h"
+#include "touchfeedbackclientpanic.h"
+
+/**
+ * This is the maximum number that can be used as feedback area identifier.
+ * after this the values starting from 1 are taken into use again when
+ * new areas are added. This also defines the maximum number of feedback
+ * areas that one application can have.
+ */
+const TInt KTouchMaxFeedbackAreaIdentifier = 5000;
+
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Cleanup items for removing latest item from the given array. These are used
+// for cleanup in case something leaves when we are adding new area
+// to the registry.
+// ---------------------------------------------------------------------------
+//
+void CleanupCacheArray( TAny* aPtr )
+    {
+    RArray<TControlCacheEntry>* array = 
+        static_cast<RArray<TControlCacheEntry>*> ( aPtr );
+        
+    TInt index = array->Count() - 1;
+    
+    // If we are removing control from cache, then we have to clean the
+    // associated area array also, or otherwise there will be a memory leak.
+    (*array)[index].iAreaArray.Reset();
+    (*array)[index].iAreaArray.Close();
+    
+    array->Remove( array->Count()-1 );        
+    }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CleanupAreaArray( TAny* aPtr )
+    {
+    RArray<TAreaIndexEntry>* array = 
+        static_cast<RArray<TAreaIndexEntry>*> ( aPtr );
+        
+    array->Remove( array->Count()-1 );    
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+CTouchFeedbackImpl::CTouchFeedbackImpl() :
+    iAudioEnabledForThisApp( ETrue ), 
+    iVibraEnabledForThisApp( ETrue )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// We check first if Tactile Feedback feature is supported in this device
+// and only construct the iClient -member in case needed. We thus use 
+// the existence of iClient as feature check in other API functions.
+//
+// This also means that iClient member needs to be checked in all the API
+// functions, so that we won't cause a KERN-EXEC 3 by trying to access
+// a NULL pointer in case the feature is disabled.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::ConstructL()
+    { 
+    TRACE("CTouchFeedbackImpl::ConstructL - Begin");
+
+    // Check if the whole Tactile Feedback feature is supported or not
+    
+    // Initialize feature manager, just in case we happen to be the first
+    // one using it in this thread.
+    FeatureManager::InitializeLibL();
+    
+    TBool featureSupported =
+        FeatureManager::FeatureSupported( KFeatureIdTactileFeedback );
+
+    // We don't need feature manager anymore, as it is not possible
+    // to change this feature on/off at run-time
+    FeatureManager::UnInitializeLib();
+    
+    // Only create client in case feature is supported
+    if ( featureSupported )
+        {
+        iClient = CTouchFeedbackClient::NewL( *this );
+        }
+    else
+        {
+        TRACE("Tactile Feedback feature is not supported");
+        }
+    
+    // Check if pen usage is enabled. We use this information later for
+    // disabling area registry -based feedback in case pen usage is not
+    // enabled.    
+    iPenEnabled = AknLayoutUtils::PenEnabled();
+    
+    TRACE3("CTouchFeedbackImpl::ConstructL - End, feature supported = %d, pen Enabled: %d", featureSupported, iPenEnabled);
+    }
+
+// ---------------------------------------------------------------------------
+// We cannot afford to leave here (at least for the moment), because
+// in that case the whole system won't boot up. Constructing of the
+// client (in ConstructL) will fail if click plugin is not configured in
+// WSINI.INI file, and that can happen very easily at least in the beginning
+// when this is a new feature. Thus we TRAP any leaves here.
+//
+// This also means that iClient member needs to be checked in all the API
+// functions. We will also use this for recognizing the situation when
+// touch feedback is not supported (in that case we won't even try to
+// instantiate the client).
+// ---------------------------------------------------------------------------
+//
+CTouchFeedbackImpl* CTouchFeedbackImpl::New()
+    {
+    CTouchFeedbackImpl* self = new CTouchFeedbackImpl;
+    if ( self )
+        {
+        TRAP_IGNORE( self->ConstructL() );    
+        }    
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CTouchFeedbackImpl::~CTouchFeedbackImpl()
+    {
+    TRACE("CTouchFeedbackImpl::~CTouchFeedbackImpl");
+
+    delete iClient;
+    
+    TInt i = 0;
+    
+    for ( i=0; i < iRegistryArray.Count(); i++ )
+        {
+        delete iRegistryArray[i];
+        }
+        
+    for ( i=iControlCache.Count()-1; i >= 0; i-- )
+        {
+        RemoveControlFromCache( i );
+        }
+        
+    iRegistryArray.Close();
+    iControlCache.Close();
+    }
+
+// ---------------------------------------------------------------------------
+// We return ETrue if iClient exist, because instantiation of the client is
+// not done in case the feature is not enabled. And on the other hand if 
+// instantiation of client fails, then using of feedback is not possible
+// anyway.
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::TouchFeedbackSupported()
+    {
+    if ( iClient )
+        {
+        return ETrue;        
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// Store the current status of feedback for this application, and
+// notify server of the change.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::SetFeedbackEnabledForThisApp( TBool aEnabled )
+    {
+    TRACE2( "CTouchFeedbackImpl::SetFeedbackEnabledForThisApp %d", aEnabled );
+    
+    // Only notify server when enabled value really changes.
+    if ( iClient && 
+       (( aEnabled != iAudioEnabledForThisApp ) || 
+         (aEnabled != iVibraEnabledForThisApp ) ))
+        {
+        iClient->RegistryChanged();        
+        }
+        
+    iAudioEnabledForThisApp = aEnabled;      
+    iVibraEnabledForThisApp = aEnabled;      
+    }
+
+// ---------------------------------------------------------------------------
+// Here we just return the current status.
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::FeedbackEnabledForThisApp() 
+    {
+    return iAudioEnabledForThisApp || iVibraEnabledForThisApp;
+    }
+        
+// ---------------------------------------------------------------------------
+// This functions main purpose is to do all possible parameter checks to
+// the arguments before actually setting the area.
+// 
+// #1 Check that feedback is enabled
+// #2 Check that we weren't given a NULL pointer as control.
+// #3 Check that feedback type and pointer event are supported
+// #4 Check that we can generate a client handle from the control
+//    (if not, then there is something wrong with given control)
+// #5 Call overridden method SetFeedbackArea for actually setting the 
+//    feedback area.
+// ---------------------------------------------------------------------------
+//
+TInt CTouchFeedbackImpl::SetFeedbackArea( 
+    const CCoeControl* aControl, 
+    TUint32 aIndex, 
+    TRect aRect, 
+    TTouchLogicalFeedback aFeedbackType, 
+    TTouchEventType aEventType )
+    {
+    TRACE("CTouchFeedbackImpl::SetFeedbackArea - Begin");
+    
+    // #1
+    if ( !iClient )
+        {
+        return KErrNone;
+        }
+    
+    // #2
+    if ( !aControl )
+        {
+        TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: NULL Control");
+        return KErrArgument;
+        }
+        
+    // #3    
+    if ( aFeedbackType > ETouchFeedbackSensitive || 
+        ( aEventType!= ETouchEventStylusDown ) )
+        {
+        TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: Unsupported params");
+        return KErrNotSupported;
+        }
+      
+    // #4        
+    TUint32 clientHandle = ClientHandle( aControl );
+    
+    if ( !clientHandle )
+        {
+        TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: Invalid Control");        
+        return KErrArgument;
+        }
+    
+    // #5    
+    TInt err(KErrGeneral);
+    CFeedbackSpec* spec = CFeedbackSpec::New();
+    if (spec)
+        {
+        spec->AddFeedback(aEventType, aFeedbackType);
+        err = SetFeedbackArea(aControl, aIndex, aRect, spec);
+        delete spec;
+        spec = NULL;
+        }
+        
+    TRACE2("CTouchFeedbackImpl::SetFeedbackArea - End, err = %d", err );
+    return err;    
+    }
+      
+// ---------------------------------------------------------------------------
+// Here we remove the given area from registry. 
+//
+// We still keep the control in the registry even if would have no areas,
+// because otherwise we'll lose feedback disabled/enabled information.
+//
+// #1 First check that given area is actually found
+// #2 Find corresponsing registry entry
+// #3 Remove feedback area entry from control cache
+// #4 Finally remove the actual area from registry, and notify server
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::RemoveFeedbackArea( 
+    const CCoeControl* aControl, 
+    TUint32 aIndex )
+    {
+    TRACE3( "CTouchFeedbackImpl::RemoveFeedbackArea: 0x%x, %d", aControl, aIndex );
+
+    if ( iClient )
+        {
+        TInt cacheIndex = KErrNotFound;
+        TInt areaIndex = KErrNotFound;
+        
+        FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+        
+        // #1 Only do something in case the area was found
+        if ( cacheIndex >=0 && areaIndex >= 0 )
+            {
+            // #2
+            TInt registryIndex = FindWindowFromRegistry ( 
+                iControlCache[cacheIndex].iClientHandle );
+
+            TInt areaId = 
+                iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
+            
+            // #3 Remove this feedback area entry
+            iControlCache[cacheIndex].iAreaArray.Remove( areaIndex );
+            
+            iNbOfFeedbackAreas--;
+            
+            // #4 Remove the area from registry
+            if ( registryIndex != KErrNotFound )
+                {
+                iRegistryArray[registryIndex]->RemoveFeedbackArea( areaId );
+                
+                iClient->RegistryChanged();
+                }        
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Here we return all areas related to given control.
+//
+// #1 Only do something in case the control is found from cache
+// #2 Find corresponding registry index.
+// #3 Remove all feedback areas from the registry.
+// #4 Remove the control from cache
+// #5 Notify server, if some areas were really removed.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::RemoveFeedbackForControl( 
+    const CCoeControl* aControl )
+    {
+    TRACE2("CTouchFeedbackImpl::RemoveFeedbackForControl: 0x%x", aControl);
+    
+    if ( iClient )
+        {
+        TInt controlIndex = FindControlFromCache( aControl );
+        
+        // #1
+        if ( controlIndex >= 0 ) // If control was found
+            {
+            TBool changesMade = EFalse;
+
+            TControlCacheEntry& entry( iControlCache[controlIndex] );
+            
+            // #2
+            TInt registryIndex = 
+                FindWindowFromRegistry( entry.iClientHandle );
+            
+            // #3 If registry entry was found, then remove all feedback
+            // areas.
+            if ( registryIndex >= 0) 
+                {
+                for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
+                    {
+                    iRegistryArray[registryIndex]->
+                            RemoveFeedbackArea( 
+                            entry.iAreaArray[i].iAreaId );
+                            
+                    changesMade = ETrue;   
+                    
+                    iNbOfFeedbackAreas--;     
+                    }
+                }
+            
+            // #4 Anyway remove controls feedback areas from cache
+            RemoveControlFromCache( controlIndex );
+           
+            // #5 Notify server of changes
+            if ( changesMade )
+                {
+                iClient->RegistryChanged();
+                }
+            }        
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// Here we change the rectangle of existing feedback area.
+//
+// #1 Only do something in case the area is really found.
+// #2 Find corresponding registry entry
+// #3 If the entry was found, then change the feedback area
+// #4 Only notify the server when the area really changed
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::ChangeFeedbackArea( const CCoeControl* aControl,
+                                             TUint32 aIndex, 
+                                             TRect aNewRect )
+    {
+    TRACE( "CTouchFeedbackImpl::ChangeFeedbackArea: 0x%x" );
+
+    if ( iClient )
+        {
+        TInt cacheIndex = KErrNotFound;
+        TInt areaIndex  = KErrNotFound;
+
+        FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+        
+        // #1
+        if ( cacheIndex >= 0 && areaIndex >= 0 )
+            {
+            TInt id = 
+                iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
+            
+            // #2 
+            TInt registryIndex = 
+                FindWindowFromRegistry ( 
+                    iControlCache[cacheIndex].iClientHandle );
+
+            // #3
+            if ( registryIndex != KErrNotFound )
+                {
+                TBool changed = 
+                    iRegistryArray[registryIndex]->ChangeFeedbackArea( 
+                        id, 
+                        aNewRect );
+
+                // #4 Only send upates to server when something 
+                //    really changed.
+                if ( changed )
+                    {
+                    iClient->RegistryChanged();                
+                    }
+                }           
+            }        
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Here we change the feedback type of existing feedback area.
+//
+// #1 Only do something in case the area is really found.
+// #2 Find corresponding registry entry
+// #3 If the entry was found, then change the feedback area
+// #4 Only notify the server when the feedback type really changed
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::ChangeFeedbackType( const CCoeControl* aControl,
+                                             TUint32 aIndex, 
+                                             TTouchLogicalFeedback aNewType )
+    {
+    TRACE4("CTouchFeedbackImpl::ChangeFeedbackType: 0x%x, %d, %d", aControl, aIndex, aNewType);
+
+    if ( iClient )
+        {
+        TInt cacheIndex = KErrNotFound;
+        TInt areaIndex  = KErrNotFound;
+
+        FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+        
+        // #1
+        if ( cacheIndex >= 0 && areaIndex >= 0 )
+            {
+            TInt id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
+            
+            // #2
+            TInt registryIndex = 
+                FindWindowFromRegistry ( 
+                    iControlCache[cacheIndex].iClientHandle );
+
+            // #3
+            if ( registryIndex != KErrNotFound )
+                {
+                TBool changed = 
+                    iRegistryArray[registryIndex]->ChangeFeedbackType( 
+                        id, 
+                        aNewType,
+                        // Feedback type change for up event is not supported 
+                        // by this function.
+                        static_cast<TTouchLogicalFeedback>( 0xFFFFFFFF ) );
+
+                // #4 Only send upates to server when something 
+                //    really changed.
+                if ( changed )
+                    {
+                    iClient->RegistryChanged();                
+                    }
+                }           
+            }        
+        }
+    }    
+   
+// ---------------------------------------------------------------------------
+// Here we change move the given feedback area to first priority, so that
+// it will be the topmost in its window.
+//
+// #1 Only do something in case the area is really found.
+// #2 Find corresponding registry entry
+// #3 If the entry was found, then change the feedback area
+// #4 Only notify the server when the move was successfull
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::MoveFeedbackAreaToFirstPriority( 
+    const CCoeControl* aControl, 
+    TUint32 aIndex )
+    {
+    if ( iClient )
+        {
+        TInt cacheIndex = KErrNotFound;
+        TInt areaIndex  = KErrNotFound;
+
+        FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+        
+        // #1
+        if ( cacheIndex >= 0 && areaIndex >= 0 )
+            {
+            TInt id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
+            
+            // #2
+            TInt registryIndex = 
+                FindWindowFromRegistry ( 
+                    iControlCache[cacheIndex].iClientHandle );
+
+            // #3
+            if ( registryIndex != KErrNotFound )
+                {
+                TInt err = 
+                    iRegistryArray[registryIndex]->
+                        MoveFeedbackAreaToFirstPriority( id );
+
+                // #4
+                if ( err == KErrNone )
+                    {
+                    TRACE3("CTouchFeedbackImpl::MoveFeedbackAreaToFirstPriority 0x%x, %d", aControl, aIndex);
+                    iClient->RegistryChanged();
+                    }
+                }  
+            }
+        }
+    }   
+
+// ---------------------------------------------------------------------------
+// Pass request to server in case feedback is enabled for this 
+// application.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::InstantFeedback( TTouchLogicalFeedback aType )
+    {
+    if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
+        {
+        TRACE2("CTouchFeedbackImpl::InstantFeedback %d", aType);
+        iClient->ImmediateFeedback( 
+            aType, 
+            iVibraEnabledForThisApp, 
+            iAudioEnabledForThisApp );        
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// In this overload we only play direct feedback if the feedback has
+// not been disabled for this control.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::InstantFeedback( 
+    const CCoeControl* aControl,
+    TTouchLogicalFeedback aType )
+    {
+    if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
+        {
+        
+        // First take application level vibra and audio enablers
+        // as default
+        TBool vibraEnabled = iVibraEnabledForThisApp;
+        TBool audioEnabled = iAudioEnabledForThisApp;
+
+        TInt cacheIndex = FindControlFromCache( aControl );
+        
+        
+        // Check control level disablers for vibra and audio.
+        // (These can only prevent vibra or audio effect playback,
+        //  but not to force it on)
+        if ( cacheIndex >=0 && vibraEnabled ) 
+            {
+            vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
+            }
+            
+        if ( cacheIndex >=0 && audioEnabled ) 
+            {
+            audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
+            }
+            
+        TRACE3("CTouchFeedbackImpl::InstantFeedback 0x%x, %d", aControl, aType);
+        iClient->ImmediateFeedback( aType, vibraEnabled, audioEnabled );   
+        }
+    }    
+
+// ---------------------------------------------------------------------------
+// It is not enough to check that the control exists in the cache, we
+// also need to check that it actually has some areas registered.
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::ControlHasFeedback( const CCoeControl* aControl )
+    {
+    TBool hasFeedback = EFalse;
+    
+    if ( iClient )
+        {
+        for ( TInt i=0; i < iControlCache.Count(); i++ )
+            {
+            if ( iControlCache[i].iControl == aControl )
+                {
+                if ( iControlCache[i].iAreaArray.Count() > 0 )
+                    {
+                    hasFeedback =  ETrue;                    
+                    }
+                    
+                // Break out from loop anyway, since we found the
+                // control
+                break;
+                }
+            }        
+        }
+        
+    return hasFeedback;
+    }
+
+// ---------------------------------------------------------------------------
+// Control has feedback if it has a feedback identifier with given index
+// number.
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::ControlHasFeedback( 
+    const CCoeControl* aControl, 
+    TUint32 aIndex )
+    {
+    TBool hasArea = EFalse;
+    
+    if ( iClient )
+        {
+        TInt cacheIndex = KErrNotFound;
+        TInt areaIndex  = KErrNotFound;
+        
+        FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+        
+        if ( cacheIndex >= 0 && areaIndex >= 0 )
+            {
+            hasArea = ETrue;
+            }
+        }
+
+    return hasArea;
+    }  
+  
+// ---------------------------------------------------------------------------
+// This overload is only wrapper to the real function
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::EnableFeedbackForControl( 
+    const CCoeControl* aControl, 
+    TBool aEnable )
+    {
+    EnableFeedbackForControl( aControl, aEnable, aEnable );
+    }    
+
+// ---------------------------------------------------------------------------
+// #1 Find control from the cache
+// #2 In case control was found, disable/enable it's registry entries, and
+//    also take into accound it's dimming status
+// #3 If control was not found, then add it to cache
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::EnableFeedbackForControl( 
+    const CCoeControl* aControl,
+    TBool aEnableVibra,
+    TBool aEnableAudio )
+    {
+    TRACE4( "CTouchFeedbackImpl::EnableFeedbackForControl - 0x%x Vibra:%d Audio:=%d", 
+           aControl, aEnableVibra, aEnableAudio );
+
+    if ( aControl )
+        {
+        // #1
+        TInt cacheIndex = FindControlFromCache( aControl );
+
+        if ( cacheIndex >= 0 )
+            {
+            // #2
+            TControlCacheEntry& entry ( iControlCache[cacheIndex] );
+            
+            entry.iVibraDisabled = !aEnableVibra;
+            entry.iAudioDisabled = !aEnableAudio;
+            
+            // Let's update visibility and dimming information also now
+            // that we have the pointer to control (due to broken object
+            // provider chain we might not have the correct information on 
+            // the moment).
+            entry.iDimmed  = aControl->IsDimmed();
+            entry.iVisible = aControl->IsVisible();
+            
+            if ( ControlsAreasActive( cacheIndex ) )
+                {
+                // If control is active (undimmed and visible), then we 
+                // set the areas according to parameters.
+                DoEnableControlsAreasInRegistry( cacheIndex, 
+                                                 aEnableVibra, 
+                                                 aEnableAudio,
+                                                 aControl->IsVisible() );
+                }
+            else
+                {
+                // If control is not active, then we disable all feedback.
+                DoEnableControlsAreasInRegistry( cacheIndex, 
+                                                 EFalse, 
+                                                 EFalse, 
+                                                 aControl->IsVisible() );
+                }
+            }
+        else if ( !aEnableVibra || !aEnableAudio  )
+            {
+            // #3 We have to add control to the cache in case
+            // it is not there yet (and disabling is wanted), because
+            // otherwise it will be impossible to block feedback
+            TUint32 clientHandle = ClientHandle( aControl );
+            
+            // We need to rely elsewhere that client handle exist if control
+            // is found in the cache --> Only make new entry if client
+            // handle can be aquired.
+            if ( clientHandle > 0 )
+                {
+                TControlCacheEntry newCacheEntry;
+                
+                newCacheEntry.iControl        = aControl;
+                newCacheEntry.iClientHandle   = clientHandle;
+                newCacheEntry.iVibraDisabled  = !aEnableVibra;
+                newCacheEntry.iAudioDisabled  = !aEnableAudio;
+                newCacheEntry.iVisible        = aControl->IsVisible();
+                newCacheEntry.iDimmed         = aControl->IsDimmed();
+                        
+                iControlCache.Append( newCacheEntry );                        
+                }
+            }        
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Store the current status of audio and vibra feedbacks for this 
+// application, and notify server of the change.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::SetFeedbackEnabledForThisApp( 
+    TBool aVibraEnabled, 
+    TBool aAudioEnabled )
+    {
+    TRACE3( "CTouchFeedbackImpl::SetFeedbackEnabledForThisApp %d %d", aVibraEnabled, aAudioEnabled );
+    
+    // Only notify server when enabled value really changes.
+    if ( iClient && 
+       (( aAudioEnabled != iAudioEnabledForThisApp ) || 
+         (aVibraEnabled != iVibraEnabledForThisApp ) ))
+        {
+        iClient->RegistryChanged();        
+        }
+        
+    iAudioEnabledForThisApp = aAudioEnabled;      
+    iVibraEnabledForThisApp = aVibraEnabled;      
+    }
+
+// ---------------------------------------------------------------------------
+// Simple utility for CTouchFeedbackClient
+// ---------------------------------------------------------------------------
+//
+RPointerArray<CTouchFeedbackRegistry>* CTouchFeedbackImpl::RegistryArray()
+    {
+    return &iRegistryArray;
+    }
+        
+// ---------------------------------------------------------------------------
+// Simple utility for CTouchFeedbackClient
+//
+// We return zero in case pen is not supported in current layout. This way
+// area registry is disabled in non-touch powered layouts, but feedback areas
+// are still kept in memory so that feedback can be enabled again in case 
+// layout changes.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::GetAreaCount( TInt& aAreaCount, TInt& aWindowCount )
+    {
+    aWindowCount = 0;
+    aAreaCount = 0;
+    
+    if ( iPenEnabled )
+        {
+        aWindowCount = iRegistryArray.Count();
+        aAreaCount =  iNbOfFeedbackAreas;            
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// This function is called by the application framework when any control's
+// visibility or dimming status has changed.
+//
+// We need to determine here whether the given control has any feedback,
+// and whether its current state requires a change in feedback
+// areas (for e.g. feedback areas will be disabled for any dimmed control).
+//
+// #1 Find control from cache (we don't need to do anything in case it
+//    is not found.
+// #2 Check if control's feedback areas are now active (based on dimming,
+//    visibility and feedback disabling). Also check control's current 
+//    visibility status as itself, as this determines whether the area will
+//    be put to registry at all.
+// #3 Save control's current dimming and visibility status
+// #4 Check again if control's areas should  be active
+// #5 Disable/Enable areas in case needed
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::ControlVisibilityChanged( 
+    const CCoeControl* aControl )
+    {
+    if ( iClient && aControl )
+        {
+        // #1
+        TInt cacheIndex = FindControlFromCache( aControl );
+        
+        if ( cacheIndex >= 0 )
+            {
+            // #2
+            TBool oldStatus = ControlsAreasActive( cacheIndex );
+            TBool oldVisible = iControlCache[cacheIndex].iVisible;
+            
+            // #3
+            iControlCache[cacheIndex].iVisible = aControl->IsVisible();
+            iControlCache[cacheIndex].iDimmed  = aControl->IsDimmed();
+                
+            
+            // #4
+            TBool newStatus = ControlsAreasActive( cacheIndex );
+            
+            // #5
+            if ( ( oldStatus != newStatus ) || 
+                 ( oldVisible != aControl->IsVisible() ) )
+                {
+                if ( newStatus ) // If control is now active
+                    {
+                    DoEnableControlsAreasInRegistry( 
+                        cacheIndex, 
+                        !iControlCache[cacheIndex].iVibraDisabled,
+                        !iControlCache[cacheIndex].iAudioDisabled,
+                        aControl->IsVisible() );
+                    }
+                else
+                    {
+                    DoEnableControlsAreasInRegistry( cacheIndex, 
+                                                     EFalse, 
+                                                     EFalse,
+                                                     aControl->IsVisible() );
+                    }
+                }
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Here we check whether the pen support status has changed, and update
+// registry in case needed.
+//
+// Notice that this has not effect on direct feedback: It is completely on
+// UI control's responsibility to check if pen is supported with direct
+// feedback (direct feedback is not automatically disabled because that
+// would cause problems in compatibility mode).
+//
+// Also notice that we don't actually destroy any feedback areas when pen
+// usage is not supported: We just report zero areas to server side, but
+// still keep everything in memory (see GetAreaCount -function)
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::LayoutChanged()
+    {    
+    if ( iClient )
+        {
+        TBool penEnabledNow = AknLayoutUtils::PenEnabled();
+
+        TRACE2("CTouchFeedbackImpl::LayoutChanged, PenEnabled = %d", penEnabledNow);
+        
+        if ( penEnabledNow != iPenEnabled )
+            {
+            iPenEnabled = penEnabledNow;
+            
+            iClient->RegistryChanged();                    
+            }        
+        }
+    }
+
+// new functions from MTouchFeedback that came in 5.2
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::FeedbackEnabledForThisApp( TTouchFeedbackType aFeedbackType )
+    {
+    TBool feedbackEnabled( ETrue );
+    
+    if ( (aFeedbackType & ETouchFeedbackAudio) && !iAudioEnabledForThisApp )
+        {
+        feedbackEnabled = EFalse;
+        }
+
+    if ( (aFeedbackType & ETouchFeedbackVibra) && !iVibraEnabledForThisApp )
+        {
+        feedbackEnabled = EFalse;
+        }        
+        
+    if ( !aFeedbackType )        
+        {
+        feedbackEnabled = EFalse;
+        }
+   
+    return feedbackEnabled;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::StartFeedback( const CCoeControl* aControl,
+                                        TTouchContinuousFeedback aType,
+                                        const TPointerEvent* /*aPointerEvent*/,
+                                        TInt aIntensity,
+                                        TTimeIntervalMicroSeconds32 aTimeout )
+    {
+    if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
+        {
+        // First take application level vibra and audio enablers
+        // as default
+        TBool vibraEnabled = iVibraEnabledForThisApp;
+        TBool audioEnabled = iAudioEnabledForThisApp;
+
+        TInt cacheIndex = FindControlFromCache( aControl );
+        
+        
+        // Check control level disablers for vibra and audio.
+        // (These can only prevent vibra or audio effect playback,
+        //  but not to force it on)
+        if ( cacheIndex >=0 && vibraEnabled ) 
+            {
+            vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
+            }
+            
+        if ( cacheIndex >=0 && audioEnabled ) 
+            {
+            audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
+            }
+            
+        if ( vibraEnabled || audioEnabled )
+            {
+            TRACE4("CTouchFeedbackImpl::StartFeedback, type:=%d intensity:%d, timeout:%d", aType, aIntensity, aTimeout);
+            TUint32 clientHandle = ClientHandle( aControl );
+            iClient->StartFeedback( clientHandle, 
+                                    aType, 
+                                    aIntensity, 
+                                    aTimeout );    
+            }
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::ModifyFeedback( const CCoeControl* aControl,
+                                         TInt aIntensity )
+    {
+    if ( iClient )
+        {
+        TRACE2("CTouchFeedbackImpl::ModifyFeedbac, intensity:%d, timeout:%d", aIntensity);
+        TUint32 clientHandle = ClientHandle( aControl );
+        iClient->ModifyFeedback( clientHandle, aIntensity );
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//                             
+void CTouchFeedbackImpl::StopFeedback( const CCoeControl* aControl )
+    {
+    if ( iClient )
+        {
+        TUint32 clientHandle = ClientHandle( aControl );
+        iClient->StopFeedback( clientHandle );
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CTouchFeedbackImpl::SetFeedbackEnabledForDevice( TTouchFeedbackType aFeedbackType )
+    {
+    TInt ret( KErrGeneral );
+    if ( iClient )
+        {
+        ret = iClient->SetFeedbackEnabledForDevice( aFeedbackType );
+        }
+    return ret;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TTouchFeedbackType CTouchFeedbackImpl::FeedbackEnabledForDevice()
+    {
+    TTouchFeedbackType enabled( static_cast<TTouchFeedbackType>(0) );
+    if ( iClient )
+        {
+        enabled = iClient->FeedbackEnabledForDevice();
+        }
+    return enabled;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::InstantFeedback( const CCoeControl* aControl,
+                                          TTouchLogicalFeedback aType,
+                                          const TPointerEvent& /*aPointerEvent*/ )
+    {
+    InstantFeedback(aControl, aType);
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CTouchFeedbackImpl::SetFeedbackArea( const CCoeControl* aControl, 
+                                          TUint32 aIndex,
+                                          TRect aRect, 
+                                          CFeedbackSpec* aFeedbackSpec )
+    {
+    // #1
+    if ( !iClient )
+        {
+        return KErrNone;
+        }
+    
+    // #2
+    if ( !aControl )
+        {
+        TRACE("CTouchFeedbackImpl::SetFeedbackArea(spec) - Err: NULL Control");
+        return KErrArgument;
+        }
+        
+    // #4        
+    TUint32 clientHandle = ClientHandle( aControl );
+    
+    if ( !clientHandle )
+        {
+        TRACE("CTouchFeedbackImpl::SetFeedbackArea(spec) - Err: Invalid Control");        
+        return KErrArgument;
+        }
+    
+    // #5    
+    TRAPD( err, 
+        DoSetFeedbackAreaL( 
+            aControl, 
+            aIndex, 
+            aRect, 
+            aFeedbackSpec, 
+            clientHandle ) );
+
+    if (err)
+        {
+        TRACE2("CTouchFeedbackImpl::SetFeedbackArea(spec) err = %d", err );
+        }
+    
+    return err;    
+    }
+    
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//    
+void CTouchFeedbackImpl::InstantFeedback( const CCoeControl* aControl,
+                                          TTouchLogicalFeedback aType,
+                                          TTouchFeedbackType aFeedbackType,
+                                          const TPointerEvent& /*aPointerEvent*/ )
+    {
+    if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
+        {
+        // Initialize vibra and audio enablers as given in param.
+        TBool vibraEnabled = aFeedbackType & ETouchFeedbackVibra;
+        TBool audioEnabled = aFeedbackType & ETouchFeedbackAudio;
+
+        // Check application level vibra and audio enablers
+        if ( !iVibraEnabledForThisApp )
+            {
+            vibraEnabled = EFalse;
+            }
+        if ( !iAudioEnabledForThisApp )
+            {
+            audioEnabled = EFalse;
+            }            
+
+        TInt cacheIndex = FindControlFromCache( aControl );
+        
+        
+        // Check control level disablers for vibra and audio.
+        // (These can only prevent vibra or audio effect playback,
+        //  but not to force it on)
+        if ( cacheIndex >=0 && vibraEnabled ) 
+            {
+            vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
+            }
+            
+        if ( cacheIndex >=0 && audioEnabled ) 
+            {
+            audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
+            }
+            
+        TRACE5("CTouchFeedbackImpl::InstantFeedback, 0x%x, type:=%d Vibra:%d Audio:%d", 
+               aControl, aType, vibraEnabled, audioEnabled);
+        iClient->ImmediateFeedback( aType, vibraEnabled, audioEnabled );   
+        }
+    }
+        
+// ---------------------------------------------------------------------------
+// Here we do the actual work for adding new area to the registry
+// (or updating an existing one).
+//
+// #1 Check that control exist in the cache
+//    #2a If it does not exist, then add it
+//    #2b If control exists, but area not, then add new area
+//    #2c If control and area both exist, then use existing id
+// #3 Find corresponding registry entry
+// #4 Create new entry if this was the first area for this window
+// #5 Determine if new area should actually be active, and then
+//    add it to registry
+// #6 Inform server if we added an active area
+//
+// We use specific cleanup items for removing the added area and/or control
+// from the control cache in caes adding of the area to the actual 
+// registry fails. This way actual registry and control cache will remain
+// in sync no matter what happens.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::DoSetFeedbackAreaL( 
+                                const CCoeControl* aControl, 
+                                TUint32 aIndex,
+                                TRect aRect, 
+                                CFeedbackSpec* aFeedbackSpec, 
+                                TUint32 aClientHandle )
+    {
+    TInt id = KErrNotFound;
+    TInt nbOfCleanupItems = 0;
+    TBool newArea = EFalse;
+    
+    // #1
+    TInt cacheIndex = KErrNotFound;
+    TInt areaIndex  = KErrNotFound;
+    FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
+
+    // #2a
+    if ( cacheIndex < 0 )
+        {
+        id = GenerateUniqueIdL();
+        
+        TControlCacheEntry newCacheEntry;
+        
+        newCacheEntry.iControl            = aControl;
+        newCacheEntry.iClientHandle       = aClientHandle;
+        newCacheEntry.iVibraDisabled      = EFalse;
+        newCacheEntry.iAudioDisabled      = EFalse;
+        newCacheEntry.iVisible         = aControl->IsVisible();
+        newCacheEntry.iDimmed          = aControl->IsDimmed();
+        
+        // New entry will be added at the end of array
+        // This assignment will also make it possible to use
+        // "cacheIndex" -variable in the rest of the function
+        // in all cases.
+        cacheIndex = iControlCache.Count();
+        
+        iControlCache.AppendL( newCacheEntry );  
+        
+        // Use cleanup item to remove the control in case something
+        // fails later in this function.
+        CleanupStack::PushL(
+            TCleanupItem( CleanupCacheArray, &iControlCache ) );  
+        nbOfCleanupItems++;    
+        
+        TAreaIndexEntry newAreaEntry;
+        
+        newAreaEntry.iIndex  = aIndex;
+        newAreaEntry.iAreaId = id;
+        
+        iControlCache[cacheIndex].iAreaArray.AppendL( newAreaEntry );
+        
+        // Use cleanup item to remove the area id in case something
+        // fails later in this function.
+        CleanupStack::PushL( 
+            TCleanupItem( CleanupAreaArray, 
+                          &iControlCache[cacheIndex].iAreaArray) );  
+        nbOfCleanupItems++;    
+                 
+        newArea = ETrue;   
+        
+        // Enable control state change reports on the new control
+        CCoeControl* tmp =  const_cast<CCoeControl*>( aControl );
+        tmp->EnableReportControlStateChange( ETrue );
+        }
+    // #2b   
+    else if ( areaIndex < 0 )
+        {
+        id = GenerateUniqueIdL();
+        
+        TAreaIndexEntry newAreaEntry;
+    
+        newAreaEntry.iIndex  = aIndex;
+        newAreaEntry.iAreaId = id;
+
+        iControlCache[cacheIndex].iAreaArray.AppendL( newAreaEntry );
+        
+        CleanupStack::PushL( 
+            TCleanupItem( CleanupAreaArray, 
+                          &iControlCache[cacheIndex].iAreaArray) );  
+        nbOfCleanupItems++;    
+
+        newArea = ETrue;   
+        }
+    // #2c
+    else
+        {
+        id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
+        }
+               
+    // #3              
+    TInt registryIndex = FindWindowFromRegistry ( aClientHandle );
+    
+    // #4   
+    if (  registryIndex == KErrNotFound )
+        {
+        // There isn't yet a registry entry for this window
+        // --> Create it
+        CTouchFeedbackRegistry* newRegistry = 
+            CTouchFeedbackRegistry::NewL( aClientHandle );
+            
+        CleanupStack::PushL( newRegistry );
+        
+        registryIndex = iRegistryArray.Count();
+                
+        iRegistryArray.AppendL( newRegistry );
+        
+        CleanupStack::Pop( newRegistry );
+        }
+
+    // #5 Determine what is the vibra and audio status for the new area
+    //    (if control is invisible or dimmed then both will be disabled)    
+    TBool vibraEnabled = EFalse;
+    TBool audioEnabled = EFalse;
+    
+    TBool areaActive = ControlsAreasActive( cacheIndex );
+    
+    if ( areaActive )
+        {
+        vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
+        audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
+        }
+        
+    
+    RArray<TTactileFbItem> feedbackEntries;
+    CleanupClosePushL( feedbackEntries );
+    TTouchEventType eventType(ETouchEventStylusDown);
+    TTouchLogicalFeedback feedbackTypeDown = ETouchFeedbackNone;
+    TTouchLogicalFeedback feedbackTypeUp   = ETouchFeedbackNone;
+    TTouchFeedbackType feedbackDown = ETouchFeedbackVibra;
+    TTouchFeedbackType feedbackUp   = ETouchFeedbackVibra;
+    aFeedbackSpec->GetFeedbackSpec(feedbackEntries);
+    TInt feedbackItems = feedbackEntries.Count();
+    for (TInt i=0;i<feedbackItems;i++)
+        {
+        TTactileFbItem item = feedbackEntries[i];
+        eventType = item.iEventType;
+        
+        if ( item.iEventType == ETouchEventStylusDown )
+            {
+            feedbackTypeDown = item.iFeedback;
+            feedbackDown = item.iFeedbackType;
+            }
+        else if ( item.iEventType == ETouchEventStylusUp )
+            {
+            feedbackTypeUp = item.iFeedback;
+            feedbackUp = item.iFeedbackType;
+            }
+        }
+    if ( feedbackItems > 0 )
+        {
+        iRegistryArray[registryIndex]->AddFeedbackAreaL( 
+            aRect, feedbackTypeDown, feedbackDown, feedbackTypeUp, feedbackUp, 
+            eventType, id, vibraEnabled, audioEnabled, aControl->IsVisible() );
+        }
+    CleanupStack::PopAndDestroy( &feedbackEntries );
+        
+    // We can now remove the cleanup items, because nothing can fail 
+    // anymore.    
+    CleanupStack::Pop( nbOfCleanupItems );    
+    
+    // We can also update the counter now, when we know that the area
+    // was actually added
+    if ( newArea )
+        {
+        iNbOfFeedbackAreas++;
+        }
+
+    // #6 We only need to inform server in case we added an active area
+    // to the registry.
+    if ( areaActive ) 
+        {
+        iClient->RegistryChanged();        
+        }
+    }
+        
+// ---------------------------------------------------------------------------
+// A simple for -loop should be enough here, as we are not likely to have
+// that many windows in one application process.
+// ---------------------------------------------------------------------------
+//
+TInt CTouchFeedbackImpl::FindWindowFromRegistry( TUint aWindowHandle )
+    {
+    TInt index = KErrNotFound;
+    
+    for ( TInt i=0; i < iRegistryArray.Count(); i++ )
+        {
+        if ( iRegistryArray[i]->WindowHandle() == aWindowHandle )
+            {
+            index = i;
+            break;
+            }
+        }
+        
+    return index;
+    }
+    
+// ---------------------------------------------------------------------------
+// Just ask client to do updates immediately
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::FlushRegistryUpdates( )
+    {
+    if ( iClient )
+        {
+        TRACE("CTouchFeedbackImpl::FlushRegistryUpdates" ); 
+        iClient->FlushUpdates();
+        }
+    }    
+    
+// ---------------------------------------------------------------------------
+// We use integer numers starting from 1 as area identifiers. 
+//
+// There is a bookkeeping of last used identifier, and we'll start from one
+// again after reaching the maximum value. 
+//
+// There is also a separate bookkeeping to know if our id values have been
+// rotated at least once or not. From that we know if we have to check that
+// the id is not in use already (if we are on the first round, then there 
+// cannot be any area with the new id).
+//
+// Notice that it should be checked already _before_ calling this function,
+// whether it is actually possible to find an unused identifier anymore.
+// ---------------------------------------------------------------------------
+//
+TUint CTouchFeedbackImpl::GenerateUniqueIdL()
+    {
+    // First check that there actually is an identifier that we can find
+    // (i.e. check that maximum number of areas has not been reached)
+    if ( iNbOfFeedbackAreas >= KTouchMaxFeedbackAreaIdentifier )
+        {
+        User::Leave( KErrNoMemory );
+        }
+    
+    iCurrentId++;
+    
+    if ( iCurrentId > KTouchMaxFeedbackAreaIdentifier )
+        {
+        iCurrentId = 1;
+        
+        iCurrentIdCounterRotated = ETrue;
+        }
+        
+    if ( iCurrentIdCounterRotated )
+        {
+        while ( FeedbackAreaExists( iCurrentId ) )
+            {
+            iCurrentId++;
+            
+            if ( iCurrentId > KTouchMaxFeedbackAreaIdentifier )
+                {
+                iCurrentId = 1;
+                }
+            }
+        
+        }
+    
+    return iCurrentId;
+    }
+    
+// ---------------------------------------------------------------------------
+// Scan through local registry in order to know whether the area with
+// given identifier exists.
+//
+// This function is only used when creating a new unique identifier.
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::FeedbackAreaExists( TUint aAreaId )
+    {
+    TBool areaExists = EFalse;
+    
+    for ( TInt i=0; i < iRegistryArray.Count() && !areaExists; i++ )
+        {
+        RArray<TFeedbackEntry>* entryArray = 
+            iRegistryArray[i]->WindowRegistry(); 
+        
+        for ( TInt j=0; j < entryArray->Count() && !areaExists; j++ )
+            {
+            if ( (*entryArray)[j].iId == aAreaId )
+                {
+                areaExists = ETrue;
+                }
+            }
+        }   
+    
+    return areaExists;
+    }
+        
+// ---------------------------------------------------------------------------
+// Because we use the so called "client handle" for identifying windows on
+// client- and server sides, we must be able to generate a client handle
+// from CCoeControl -pointer.
+//
+// The algorithm:
+//
+// #1 Loop as long as we haven't reached the top-level control, and we still
+//    haven't found the first window-owning control.
+// 
+// #2 If this is a window-owning control, then it's address is the
+//    client-side handle
+//
+// #3 Otherwise move up to next parent
+//
+// #4 If this control doesn't have paren't pointer, then try to get
+//    a pointer to this control's window.
+//
+// #5 If we got the window, then use the ClientHandle -function for 
+//    retrieving the pointer from server side
+//
+// #6 If we don't have parent- or window pointers, then give up.
+// ---------------------------------------------------------------------------
+//
+TUint32 CTouchFeedbackImpl::ClientHandle( const CCoeControl* aControl )
+    {
+    TUint32 clientHandle = 0;
+    
+    const CCoeControl* parent = aControl;
+    
+    // #1
+    while ( clientHandle == 0 && parent )
+        {
+        if ( parent->OwnsWindow() )
+            {
+            // #2
+            clientHandle = reinterpret_cast<TUint32>( parent );            
+            }
+        else
+            {
+            // #3
+            parent = parent->Parent();
+            
+            if ( !parent )
+                {      
+                // #4          
+                RDrawableWindow* window = aControl->DrawableWindow();
+                
+                if ( window )
+                    {
+                    // #5
+                    TRACE("CTouchFeedbackImpl::ClientHandle - Ask handle from wserv - begin" );
+                    clientHandle = window->ClientHandle();
+                    TRACE("CTouchFeedbackImpl::ClientHandle - Ask handle from wserv - end" );
+                    }
+                else
+                    {
+                    // #6
+                    TRACE("CTouchFeedbackImpl::ClientHandle - Error: No window defined, not possible to get handle!!");
+                    }
+                
+                }
+            }        
+        }
+        
+    return clientHandle;
+    }
+    
+// ---------------------------------------------------------------------------
+// We could optimize this search in case we get very many controls to the
+// array, but so far it hasn't been necessary.
+// ---------------------------------------------------------------------------
+//
+TInt CTouchFeedbackImpl::FindControlFromCache( 
+    const CCoeControl* aControl )
+    {
+    TInt position = KErrNotFound;
+    
+    for ( TInt i=0; i < iControlCache.Count(); i++ )
+        {
+        if ( iControlCache[i].iControl == aControl )
+            {
+            position = i;
+            break;
+            }
+        }
+        
+    return position;    
+    }
+        
+// ---------------------------------------------------------------------------
+// If this search is starting to take too long time, then the best 
+// optimization would be to optimize the FindControlFromCache -function,
+// as there can potentially be very many controls, but not likely very many
+// ares per each control.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::FindAreaFromCache( 
+    const CCoeControl* aControl, 
+    TUint32 aIndex, 
+    TInt& aCacheIndex, 
+    TInt& aAreaIndex )
+    {
+    aAreaIndex  = KErrNotFound;
+
+    aCacheIndex = FindControlFromCache( aControl );
+        
+    if ( aCacheIndex >= 0 )
+        {
+        TControlCacheEntry& entry (iControlCache[aCacheIndex]);
+        
+        for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
+            {
+            if ( entry.iAreaArray[i].iIndex == aIndex )
+                {
+                aAreaIndex = i;
+                break;
+                }
+            } 
+        }
+    }   
+   
+// ---------------------------------------------------------------------------
+// Here we remove the control from the cache. It is assumed that
+// corresponding feedback areas have been removed from registry
+// already.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::RemoveControlFromCache( TInt aControlIndex )
+    {
+    __ASSERT_ALWAYS(  
+        aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
+        Panic( ETouchClientPanicArrayAccess ) );
+        
+    iControlCache[aControlIndex].iAreaArray.Reset();
+    iControlCache[aControlIndex].iAreaArray.Close();
+    
+    iControlCache.Remove( aControlIndex );
+    }
+         
+// ---------------------------------------------------------------------------
+// We have a separate function for knowing if control's feedback areas
+// should be active or not, because determining this is not so simple, and
+// because this part can still change.
+// 
+// Control's areas are NOT active in case
+//
+//  #1 Its feedback has been explicitely disabled for audio and vibra
+//
+// OR
+//
+//  #2 It is not visible 
+//
+// OR 
+//
+//  #3 It is dimmed.
+//
+// ---------------------------------------------------------------------------
+//
+TBool CTouchFeedbackImpl::ControlsAreasActive( TInt aControlIndex )
+    {
+    __ASSERT_ALWAYS(  
+        aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
+        Panic( ETouchClientPanicArrayAccess ) );
+
+    TBool ret = ETrue;
+    
+    if ( ( iControlCache[aControlIndex].iVibraDisabled &&     // #1
+           iControlCache[aControlIndex].iAudioDisabled ) ||   
+          !iControlCache[aControlIndex].iVisible || // #2
+          iControlCache[aControlIndex].iDimmed )    // #3
+        {
+        ret = EFalse;
+        }
+        
+    return ret;
+    }   
+   
+// ---------------------------------------------------------------------------
+// This function can be used for disabling or enabling all control's 
+// feedback areas in the registry.
+//
+// #1 Find out the registry index.
+// #2 In a loop, disable / enable each feedback area for this control
+// #3 Maintain bookkeeping, so that we will know in the end if anything 
+//    changed or not (so that we won't make unnecessary updates to server)
+// #4 Make a pending update request if registry really changed.
+// ---------------------------------------------------------------------------
+//
+void CTouchFeedbackImpl::DoEnableControlsAreasInRegistry( 
+    TInt aControlIndex,
+    TBool aEnableVibra,
+    TBool aEnableAudio,
+    TBool aVisible )
+    {
+    __ASSERT_ALWAYS(  
+        aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
+        Panic( ETouchClientPanicArrayAccess ) );
+
+    TBool registryChanged = EFalse;
+    
+    TControlCacheEntry& entry ( iControlCache[aControlIndex] );
+    
+    // #1
+    TInt registryIndex = FindWindowFromRegistry ( entry.iClientHandle );
+
+    if ( registryIndex != KErrNotFound )
+        {
+        for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
+            {
+            TInt id = entry.iAreaArray[i].iAreaId;
+            
+            // #2
+            TBool changedNow = 
+                iRegistryArray[registryIndex]->SetFeedbackEnabled( 
+                    id, aEnableVibra, aEnableAudio, aVisible );
+                    
+            // #3       
+            registryChanged = registryChanged || changedNow;
+            }
+        }
+    
+    // #4
+    if ( registryChanged )
+        {
+        iClient->RegistryChanged();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//    
+EXPORT_C CFeedbackSpec* CFeedbackSpec::New()
+    {
+    return new CFeedbackSpec;
+    }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CFeedbackSpec::~CFeedbackSpec()
+    {
+    iFbArray.Close();
+    }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CFeedbackSpec::AddFeedback( TTouchEventType aEventType, 
+                                          TTouchLogicalFeedback aFeedback )
+    {
+    // Vibra feedback is enabled by default for every event type.
+    TInt fbType( ETouchFeedbackVibra | ETouchFeedbackAudio );
+    
+    return AddFeedback( aEventType, 
+                        aFeedback, 
+                        static_cast<TTouchFeedbackType>( fbType ) );
+    }
+    
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CFeedbackSpec::AddFeedback( TTouchEventType aEventType, 
+                                          TTouchLogicalFeedback aFeedback,
+                                          TTouchFeedbackType aFeedbackType )
+    {
+    TTactileFbItem item;
+    if ( !(aEventType >= ETouchEventStylusDown && aEventType <= ETouchEventStylusPressUp ) )
+        {
+        return KErrArgument;
+        }
+    item.iEventType = aEventType;        
+    
+	// range check. update when logical feedback types are changed.
+    if (! ( aFeedback >= ETouchFeedbackNone || aFeedback <= ETouchFeedbackSensitive) 
+     || ! ( aFeedback >= ETouchFeedbackBasicButton || 
+            aFeedback <= ETouchFeedbackMultiTouchRecognized ) )
+        {
+        return KErrArgument;
+        }
+    item.iFeedback = aFeedback;        
+    item.iFeedbackType = aFeedbackType;
+        
+    iFbArray.Append(item);
+    return KErrNone;
+    }    
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CFeedbackSpec::GetFeedbackSpec( RArray<TTactileFbItem>& aArray )
+    {
+    // copy values from one array to another
+    TInt count = iFbArray.Count();
+    aArray.Reset(); // remove records from array if any
+    
+    for ( TInt i=0 ; i < count ; i++ )
+        {
+        TTactileFbItem item;
+        item.iFeedback  = iFbArray[i].iFeedback;
+        item.iEventType = iFbArray[i].iEventType;
+        item.iFeedbackType = iFbArray[i].iFeedbackType;
+        aArray.Append(item);
+        }
+    }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CFeedbackSpec::CFeedbackSpec()
+    {
+    }
+
+// End of File