--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/menucontentsrv/src/menu.cpp Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,416 @@
+/*
+* 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.
+ }