menucontentsrv/src/menu.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 07 Jan 2010 12:55:39 +0200
changeset 1 844b978f8d5e
parent 0 79c6a41cd166
permissions -rw-r--r--
Revision: 200951 Kit: 201001

/*
* Copyright (c) 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:
*
*/
#include "mcsdef.h"

#include "mcsmenu.h"
#include "menusrvdef.h"
#include "menumsg.h"
#include "menubuf.h"
#include "menuutil.h"
#include "menuclientoperation.h"
#include "menuhandlereng.h"
#include "mcsmenufilter.h"

#include <s32strm.h>
#include <e32debug.h>

// ================= LOCAL FUNCTIONS =======================

/**
* Start the server executable.
* @return Error code.
*/
LOCAL_C TInt StartServer()
    {
    TInt err( KErrNone );
    RProcess server;
    err = server.Create( KMenuSrvExe, KNullDesC, EOwnerThread );
    if ( !err )
        {
        TRequestStatus status;
        server.Rendezvous( status );
        if ( status != KRequestPending )
            {
            server.Kill( 0 ); // Abort startup.
            }
        else
            {
            server.Resume(); // Logon OK - start the server.
            }
        User::WaitForRequest( status ); // Wait for start or death.
        // We can't use the 'exit reason' if the server panicked as this
        // is the panic 'reason' and may be '0' which cannot be distinguished
        // from KErrNone.
        err = (server.ExitType() == EExitPanic) ? KErrGeneral : status.Int();
        server.Close();
        }
    return err;
    }

// ================= MEMBER FUNCTIONS =======================

NONSHARABLE_CLASS( RMenu::TData )
    {
public:
    // Transfer buffer. Size must be big enough to accomodate any object that
    // will go through it: attribute, TMenuItem
    TUint16 iBuf[KMenuMaxAttrValueLen];
    // Handler engine.
    CMenuHandlerEng* iHandler;
    };

// ================= MEMBER FUNCTIONS =======================

// ---------------------------------------------------------
// RMenu::Close
// ---------------------------------------------------------
//
EXPORT_C void RMenu::Close()
    {
    RSessionBase::Close();
    if ( iData )
        {
        delete iData->iHandler; iData->iHandler = NULL;
        delete iData; iData = NULL;
        }
    }

// ---------------------------------------------------------
// RMenu::OpenL
// ---------------------------------------------------------
//
EXPORT_C void RMenu::OpenL( const TDesC& aName )
    {
    __ASSERT_DEBUG( !iData, User::Invariant() );
    User::LeaveIfError( ConnectSession() );
    CleanupClosePushL( *this ); // Atomcic connect + local data + construct.
    iData = new (ELeave) RMenu::TData();
    iData->iHandler = NULL;
    // We have a connected blank session, now construct it.
    // It would be good to have a CreateSession which leaves us at least one
    // IpcArg, so the name could be sent to session creation directly.
    // Since having a fully constructed session needs this extra IPC, the
    // server side session had to be cluttered with ASSERTS. (Almost all
    // messages need to check that the session is fully constructed.)
    //
    // The reason for this is a design issue (we use the session as an object,
    // and not just as a communication channel. But normally there is only one
    // object used, so why complicate things for the client?
    User::LeaveIfError
        ( SendReceive( EMenuConstructSession, TIpcArgs( &aName ) ) );
    CleanupStack::Pop( this );
    }

// ---------------------------------------------------------
// RMenu::RootFolderL
// ---------------------------------------------------------
//
EXPORT_C TInt RMenu::RootFolderL()
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    TPckgBuf<TInt> pckg;
    User::LeaveIfError( SendReceive( EMenuRootFolder, TIpcArgs( &pckg ) ) );
    return pckg();
    }

// ---------------------------------------------------------
// RMenu::GetItemsL
// ---------------------------------------------------------
//
EXPORT_C void RMenu::GetItemsL(
        RArray<TMenuItem>& aItemArray,
        TInt aFolder,
        const CMenuFilter* aFilter /*=NULL*/,
        TBool aRecursive /*=EFalse*/ )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    if ( aFilter )
        {
        // Filtered query, 2+ more IPC.
        // The buffer is opened empty, used to send the filter
        // then the result is received into it.
        RMenuBuf buf;
        User::LeaveIfError( buf.Open( *this ) );
        CleanupClosePushL( buf );
        RWriteStream stream( &buf );
        aFilter->ExternalizeL( stream );
        stream.CommitL();
        TIpcArgs args( aFolder, aRecursive, buf.SubSessionHandle() );
        User::LeaveIfError( SendReceive( EMenuGetItemsFiltered, args ) );
        RReadStream rs( &buf );
        MenuUtil::InternalizeL( aItemArray, rs );
        CleanupStack::PopAndDestroy( &buf );
        }
    else
        {
        // Unfiltered query.
        // The buffer already contains the query result when Open() returns.
        RMenuBuf buf;
        TIpcArgs args( aFolder, aRecursive );
        User::LeaveIfError( buf.Open( *this, EMenuGetItems, args ) );
        CleanupClosePushL( buf );
        RReadStream stream( &buf );
        MenuUtil::InternalizeL( aItemArray, stream );
        CleanupStack::PopAndDestroy( &buf );
        }
    }

// ---------------------------------------------------------
// RMenu::GetRunningAppsL
// ---------------------------------------------------------
//
EXPORT_C  void RMenu::GetRunningAppsL( RArray<TUid>& aArray )
	{
    RMenuBuf buf;
    TIpcArgs args( 0 );
    User::LeaveIfError( buf.Open( *this, EMenuGetRunningApps, args ) );
    CleanupClosePushL( buf );
    RReadStream stream( &buf );
    MenuUtil::InternalizeL( aArray, stream );
    CleanupStack::PopAndDestroy( &buf );
	}
    

// ---------------------------------------------------------
// RMenu::RemoveL
// ---------------------------------------------------------
//
EXPORT_C CMenuOperation* RMenu::RemoveL( TInt aId, TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
        ( *this, CActive::EPriorityStandard, aStatus );
    CleanupStack::PushL( op );
    op->RemoveL( aId );
    CleanupStack::Pop( op );
    return op;
    }

// ---------------------------------------------------------
// RMenu::MoveToFolderL
// ---------------------------------------------------------
//
EXPORT_C CMenuOperation* RMenu::MoveToFolderL(
        const RArray<TInt>& aItems,
        TInt aFolder,
        TInt aMoveBefore,
        TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    RMenuBuf buf;
    User::LeaveIfError( buf.Open( *this ) );
    CleanupClosePushL( buf );
    RWriteStream stream( &buf );
    MenuUtil::ExternalizeL( aItems, stream );
    stream.CommitL();
    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
        ( *this, CActive::EPriorityStandard, aStatus );
    CleanupStack::PushL( op );
    op->MoveToFolderL( buf, aFolder, aMoveBefore );
    CleanupStack::Pop( op );
    CleanupStack::PopAndDestroy( &buf );
    return op;
    }

// ---------------------------------------------------------
// RMenu::ReorderL
// ---------------------------------------------------------
//
EXPORT_C CMenuOperation* RMenu::ReorderL
( TInt aId, TInt aMoveBefore, TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
        ( *this, CActive::EPriorityStandard, aStatus );
    CleanupStack::PushL( op );
    op->ReorderL( aId, aMoveBefore );
    CleanupStack::Pop( op );
    return op;
    }

// ---------------------------------------------------------
// RMenu::ResourceMark
// ---------------------------------------------------------
//
EXPORT_C void RMenu::ResourceMark()
    {
    SendReceive( EMenuResourceMarkStart );
    }

// ---------------------------------------------------------
// RMenu::ResourceCheck
// ---------------------------------------------------------
//
EXPORT_C void RMenu::ResourceCheck()
    {
    SendReceive( EMenuResourceMarkEnd );
    }

// ---------------------------------------------------------
// RMenu::ResourceCount
// ---------------------------------------------------------
//
EXPORT_C TInt RMenu::ResourceCount()
    {
    return SendReceive( EMenuResourceCount );
    }

#ifdef _DEBUG

// ---------------------------------------------------------
// RMenu::__DbgSetAllocFail
// ---------------------------------------------------------
//
EXPORT_C void RMenu::__DbgSetAllocFail
( RAllocator::TAllocFail aType, TInt aRate )
    {
    TInt type = STATIC_CAST( TInt, aType );
    SendReceive( EMenuSetHeapFailure, TIpcArgs( type, aRate ) );
    }

#else /* not _DEBUG */

// ---------------------------------------------------------
// RMenu::__DbgSetAllocFail
// ---------------------------------------------------------
//
EXPORT_C void RMenu::__DbgSetAllocFail
( RAllocator::TAllocFail /*aType*/, TInt /*aRate*/ )
    {
    }

#endif /* def _DEBUG */

// ---------------------------------------------------------
// RMenu::HandleCommandL
// ---------------------------------------------------------
//
CMenuOperation* RMenu::HandleCommandL(
        CMenuItem& aItem,
        const TDesC8& aCommand,
        const TDesC8& aParams,
        TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    if ( !iData->iHandler )
        {
        // Create handler engine on demand - handlers not loaded unless needed.
        iData->iHandler = CMenuHandlerEng::NewL( *this );
        }
    return iData->iHandler->HandleCommandL
        ( aItem, aCommand, aParams, aStatus );
    }

// ---------------------------------------------------------
// RMenu::ConnectSession
// ---------------------------------------------------------
//
TInt RMenu::ConnectSession()
    {
    TVersion version( KMenuMajorVersion, KMenuMinorVersion, KMenuBuild );
    TInt err = CreateSession( KMenuSrvName, version );
    if ( KErrNotFound == err )
        {
        err = StartServer();
        if ( !err || KErrAlreadyExists == err ) // Deal with race conditions.
            {
            err = CreateSession( KMenuSrvName, version );
            }
        }
    return err;
    }

// ---------------------------------------------------------
// RMenu::GetAttributeL
// ---------------------------------------------------------
//
HBufC* RMenu::GetAttributeL( TInt aId, const TDesC& aAttrName )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= 2 * KMenuMaxAttrValueLen, \
        User::Invariant() ); // Must fit into the transfer buffer.
    
    RBuf ptr;
    ptr.CleanupClosePushL();
    ptr.CreateL(KMenuMaxAttrValueLen);
    TPckgBuf<TBool> attrExists( EFalse );
    TIpcArgs args( aId, &aAttrName, &attrExists, &ptr );
    User::LeaveIfError( SendReceive( EMenuItemGetAttribute, args ) );
    
    if( attrExists() )
    	{
    	HBufC* ret = ptr.AllocL();
    	CleanupStack::PopAndDestroy( &ptr );
    	return ret;
    	}
    else
    	{
    	CleanupStack::PopAndDestroy( &ptr );
    	return NULL;
    	}
    }
    


// ---------------------------------------------------------
// RMenu::GetAttributeL
// ---------------------------------------------------------
void RMenu::GetAttributeListL( TInt aId, RArray<TAttributeName>& aList )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= 2 * KMenuMaxAttrValueLen, \
        User::Invariant() ); // Must fit into the transfer buffer.

    RMenuBuf buf;
    TIpcArgs args( aId );
    User::LeaveIfError( buf.Open( *this, EMenuItemGetAttributeList, args ) );
    CleanupClosePushL( buf );
    RReadStream rs( &buf );
    
    TInt len;
    TAttributeName name;
    while ( ETrue )
        {

        len = rs.ReadInt32L();

        if ( len == 0 )
            {
            break;
            }

        rs.ReadL( name, len );
        aList.AppendL( name );
        }

    CleanupStack::PopAndDestroy( &buf );
    }

// ---------------------------------------------------------
// RMenu::GetHdrL
// ---------------------------------------------------------
//
const TMenuItem& RMenu::GetHdrL( TInt aId )
    {
    __ASSERT_DEBUG( iData, User::Invariant() );
    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= sizeof( TMenuItem ), \
        User::Invariant() ); // Header must fit into the transfer buffer.
    TPckg<TMenuItem> pckg( (TMenuItem&)iData->iBuf );
    TIpcArgs args( aId, &pckg );
    User::LeaveIfError( SendReceive( EMenuGetHdr, args ) );
    return pckg(); // Returned object is in the transfer buffer.
    }