screengrabber/src/SGModel.cpp
changeset 0 d6fe6244b863
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/screengrabber/src/SGModel.cpp	Tue Feb 02 00:17:27 2010 +0200
@@ -0,0 +1,1604 @@
+/*
+* 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 "SGModel.h"
+#include "SGApp.h"
+#include "SG.hrh"
+#include "SGGifAnimator.h"
+
+#include <w32std.h>
+#include <e32keys.h>
+#include <imageconversion.h>
+#include <pathinfo.h>
+#include <AknGlobalConfirmationQuery.h>
+#include <aknnotewrappers.h>
+#include <textresolver.h>
+#include <bautils.h>
+#include <coeutils.h>
+#include <s32file.h>
+#include <AknGlobalNote.h>
+
+
+_LIT(KSingleShotSaved, "Screen shot saved to Media Gallery");
+_LIT(KMultipleShotsSaved, "%u screen shots saved to Media Gallery");
+_LIT(KVideoSaved, "Video saved to Media Gallery");
+_LIT(KErrorOccured, "Grabber error: ");
+_LIT(KDefaultImageFileName, "Shot");
+_LIT(KDefaultVideoFileName, "Video");
+_LIT(KScreenShotsSubDirectory, "Screen Shots\\");
+_LIT(KSGTemporaryDirectory, "\\system\\temp\\screengrabber\\");
+
+#define HIGH_QUALITY_JPEG 97
+#define LOW_QUALITY_JPEG 60
+#define DEFAULT_SEQ_CAPTURE_DELAY_MS 5000   // 5.000 secs
+#define VIDEO_CAPTURE_DELAY 250             // 0.25 secs
+#define VIDEO_CAPTURE_MINIMUM_DELAY 200     // 0.20 secs
+#define KEY_CAPTURE_PRIORITY 100            // do not change, this is for window server
+
+const TInt KSettingsDrive = EDriveC;
+_LIT(KSettingsFileName, "screengrabber_settings.ini");
+
+// ---------------------------------------------------------------------------
+
+CScreenGrabberModel* CScreenGrabberModel::NewL()
+	{
+	CScreenGrabberModel* self = new(ELeave) CScreenGrabberModel;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+// ---------------------------------------------------------------------------
+
+CScreenGrabberModel::CScreenGrabberModel() : CActive(EPriorityStandard)
+	{
+	}
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::ConstructL()
+	{
+    User::LeaveIfError(iTimer.CreateLocal());
+
+    // init audio utility
+  	iMdaAudioToneUtility = CMdaAudioToneUtility::NewL(*this);
+
+    iSavedQuery = CSavedQuery::NewL();
+    iVideoFrameArray = new(ELeave) CVideoFrameArray(10000);
+
+	iPreviouslyCapturedBitmap = new(ELeave) CFbsBitmap;
+
+    iEnv = CEikonEnv::Static();
+  	iRootWin = iEnv->RootWin();
+  	iCapturingInProgress = EFalse;
+  	iStopCapturing = EFalse;
+  	iNumberOfTakenShots = 0;
+  	iCurrentFrameNumber = 0;
+  	iHashKeyCapturingActivated = EFalse;
+  	iHashKeyDown = EFalse;
+  	iGalleryUpdaterSupported = ETrue;
+  	iGalleryUpdaterInitialized = EFalse;
+
+	CActiveScheduler::Add(this);
+	}
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::ActivateModelL()
+	{
+    // clean temporary files
+    TRAP_IGNORE( CleanTemporaryFilesL() );
+            
+    // load settings
+    TRAP_IGNORE( LoadSettingsL() );
+
+    // start capturing
+    ActivateCaptureKeysL();
+	}
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::DeActivateModelL()
+	{
+    CancelCapturing();
+
+    // for a faster exit, send the application to background
+    TApaTask selfTask(iEnv->WsSession());
+    selfTask.SetWgId(iEnv->RootWin().Identifier());
+    selfTask.SendToBackground();
+	}
+	
+// ---------------------------------------------------------------------------
+
+CScreenGrabberModel::~CScreenGrabberModel()
+	{
+	Cancel();
+
+    // deactivate Media Gallery DLL
+    if (iGalleryUpdaterInitialized)
+        {
+        if (iMGXFileManager)
+            delete iMGXFileManager;
+            
+        iGalleryUpdaterDLL.Close();
+        }
+
+	TRAP_IGNORE( CleanTemporaryFilesL() );
+
+    iTimer.Close();
+
+    if (iFrameImageData)
+        delete iFrameImageData;
+
+    if (iPreviouslyCapturedBitmap)
+        delete iPreviouslyCapturedBitmap;
+
+    if (iImageEncoder)
+        delete iImageEncoder;
+        
+    delete iVideoFrameArray;
+
+    delete iSavedQuery;
+
+    delete iMdaAudioToneUtility;
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::LoadDFSValueL(CDictionaryFileStore* aDicFS, const TUid& aUid, TInt& aValue)
+    {
+    if (aDicFS->IsPresentL(aUid))
+        {
+        RDictionaryReadStream in;
+        in.OpenLC(*aDicFS, aUid);
+        aValue = in.ReadInt16L();
+        CleanupStack::PopAndDestroy(); // in        
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::LoadDFSValueL(CDictionaryFileStore* aDicFS, const TUid& aUid, TDes& aValue)
+    {
+    if (aDicFS->IsPresentL(aUid))
+        {
+        RDictionaryReadStream in;
+        in.OpenLC(*aDicFS, aUid);
+        TInt bufLength = in.ReadInt16L();   // get length of descriptor
+        in.ReadL(aValue, bufLength);        // get the descriptor itself
+        CleanupStack::PopAndDestroy(); // in
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::SaveDFSValueL(CDictionaryFileStore* aDicFS, const TUid& aUid, const TInt& aValue)
+    {
+    RDictionaryWriteStream out;
+    out.AssignLC(*aDicFS, aUid);
+    out.WriteInt16L(aValue);
+    out.CommitL(); 	
+    CleanupStack::PopAndDestroy(1);// out
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::SaveDFSValueL(CDictionaryFileStore* aDicFS, const TUid& aUid, const TDes& aValue)
+    {
+    RDictionaryWriteStream out;
+    out.AssignLC(*aDicFS, aUid);
+    out.WriteInt16L(aValue.Length());       // write length of the descriptor
+    out.WriteL(aValue, aValue.Length());    // write the descriptor itself
+    out.CommitL(); 	
+    CleanupStack::PopAndDestroy(1);// out
+    }
+    
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::LoadSettingsL()
+    {
+    // set defaults
+    iGrabSettings.iCaptureMode = ECaptureModeSingleCapture;
+    
+    iGrabSettings.iSingleCaptureHotkey = EHotkeySendKey;
+    iGrabSettings.iSingleCaptureImageFormat = EImageFormatPNG;
+    iGrabSettings.iSingleCaptureMemoryInUse = CAknMemorySelectionSettingPage::EPhoneMemory; 
+    iGrabSettings.iSingleCaptureMemoryInUseMultiDrive = EDriveC;
+    iGrabSettings.iSingleCaptureFileName.Copy( KDefaultImageFileName );
+
+    iGrabSettings.iSequantialCaptureHotkey = EHotkeySendKey;
+    iGrabSettings.iSequantialCaptureImageFormat = EImageFormatPNG;
+    iGrabSettings.iSequantialCaptureDelay = DEFAULT_SEQ_CAPTURE_DELAY_MS;
+    iGrabSettings.iSequantialCaptureMemoryInUse = CAknMemorySelectionSettingPage::EPhoneMemory; 
+    iGrabSettings.iSequantialCaptureMemoryInUseMultiDrive = EDriveC;
+    iGrabSettings.iSequantialCaptureFileName.Copy( KDefaultImageFileName );
+
+    iGrabSettings.iVideoCaptureHotkey = EHotkeySendKey;
+    iGrabSettings.iVideoCaptureVideoFormat = EVideoFormatAnimatedGIF;
+    iGrabSettings.iVideoCaptureMemoryInUse = CAknMemorySelectionSettingPage::EPhoneMemory; 
+    iGrabSettings.iVideoCaptureMemoryInUseMultiDrive = EDriveC;
+    iGrabSettings.iVideoCaptureFileName.Copy( KDefaultVideoFileName );
+       
+        
+    // make sure that the private path of this app in c-drive exists
+    iEnv->FsSession().CreatePrivatePath( KSettingsDrive ); // c:\\private\\101fb751\\
+    
+    // handle settings always in the private directory 
+    if (iEnv->FsSession().SetSessionToPrivate( KSettingsDrive ) == KErrNone)
+        {
+        // open or create a dictionary file store
+        CDictionaryFileStore* settingsStore = CDictionaryFileStore::OpenLC(iEnv->FsSession(), KSettingsFileName, KUidScreenGrabber);
+
+        LoadDFSValueL(settingsStore, KSGSettingCaptureMode,                             iGrabSettings.iCaptureMode);
+        
+        LoadDFSValueL(settingsStore, KSGSettingSingleCaptureHotkey,                     iGrabSettings.iSingleCaptureHotkey);
+        LoadDFSValueL(settingsStore, KSGSettingSingleCaptureImageFormat,                iGrabSettings.iSingleCaptureImageFormat);
+        LoadDFSValueL(settingsStore, KSGSettingSingleCaptureMemoryInUse,                (TInt&)iGrabSettings.iSingleCaptureMemoryInUse);
+        LoadDFSValueL(settingsStore, KSGSettingSingleCaptureMemoryInUseMultiDrive,      (TInt&)iGrabSettings.iSingleCaptureMemoryInUseMultiDrive);
+        LoadDFSValueL(settingsStore, KSGSettingSingleCaptureFileName,                   iGrabSettings.iSingleCaptureFileName);
+        
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureHotkey,                 iGrabSettings.iSequantialCaptureHotkey);
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureImageFormat,            iGrabSettings.iSequantialCaptureImageFormat);
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureDelay,                  iGrabSettings.iSequantialCaptureDelay);
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureMemoryInUse,            (TInt&)iGrabSettings.iSequantialCaptureMemoryInUse);
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureMemoryInUseMultiDrive,  (TInt&)iGrabSettings.iSequantialCaptureMemoryInUseMultiDrive);
+        LoadDFSValueL(settingsStore, KSGSettingSequantialCaptureFileName,               iGrabSettings.iSequantialCaptureFileName);
+
+        LoadDFSValueL(settingsStore, KSGSettingVideoCaptureHotkey,                      iGrabSettings.iVideoCaptureHotkey);
+        LoadDFSValueL(settingsStore, KSGSettingVideoCaptureVideoFormat,                 iGrabSettings.iVideoCaptureVideoFormat);
+        LoadDFSValueL(settingsStore, KSGSettingVideoCaptureMemoryInUse,                 (TInt&)iGrabSettings.iVideoCaptureMemoryInUse);
+        LoadDFSValueL(settingsStore, KSGSettingVideoCaptureMemoryInUseMultiDrive,       (TInt&)iGrabSettings.iVideoCaptureMemoryInUseMultiDrive);
+        LoadDFSValueL(settingsStore, KSGSettingVideoCaptureFileName,                    iGrabSettings.iVideoCaptureFileName);
+
+        CleanupStack::PopAndDestroy(); // settingsStore         
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::SaveSettingsL(TGrabSettings aGrabSettings)
+    {
+    // set the new settings
+    iGrabSettings = aGrabSettings;
+
+    // handle settings always in c:\\private\\101fb751\\
+    if (iEnv->FsSession().SetSessionToPrivate( KSettingsDrive ) == KErrNone)
+        {
+        // delete existing store to make sure that it is clean and not eg corrupted
+        if (BaflUtils::FileExists(iEnv->FsSession(), KSettingsFileName))
+            {
+            iEnv->FsSession().Delete(KSettingsFileName);
+            }
+        
+        // create a dictionary file store
+        CDictionaryFileStore* settingsStore = CDictionaryFileStore::OpenLC(iEnv->FsSession(), KSettingsFileName, KUidScreenGrabber);
+
+        SaveDFSValueL(settingsStore, KSGSettingCaptureMode,                             iGrabSettings.iCaptureMode);
+        
+        SaveDFSValueL(settingsStore, KSGSettingSingleCaptureHotkey,                     iGrabSettings.iSingleCaptureHotkey);
+        SaveDFSValueL(settingsStore, KSGSettingSingleCaptureImageFormat,                iGrabSettings.iSingleCaptureImageFormat);
+        SaveDFSValueL(settingsStore, KSGSettingSingleCaptureMemoryInUse,                (TInt&)iGrabSettings.iSingleCaptureMemoryInUse);
+        SaveDFSValueL(settingsStore, KSGSettingSingleCaptureMemoryInUseMultiDrive,      (TInt&)iGrabSettings.iSingleCaptureMemoryInUseMultiDrive);
+        SaveDFSValueL(settingsStore, KSGSettingSingleCaptureFileName,                   iGrabSettings.iSingleCaptureFileName);
+        
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureHotkey,                 iGrabSettings.iSequantialCaptureHotkey);
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureImageFormat,            iGrabSettings.iSequantialCaptureImageFormat);
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureDelay,                  iGrabSettings.iSequantialCaptureDelay);
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureMemoryInUse,            (TInt&)iGrabSettings.iSequantialCaptureMemoryInUse);
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureMemoryInUseMultiDrive,  (TInt&)iGrabSettings.iSequantialCaptureMemoryInUseMultiDrive);
+        SaveDFSValueL(settingsStore, KSGSettingSequantialCaptureFileName,               iGrabSettings.iSequantialCaptureFileName);
+
+        SaveDFSValueL(settingsStore, KSGSettingVideoCaptureHotkey,                      iGrabSettings.iVideoCaptureHotkey);
+        SaveDFSValueL(settingsStore, KSGSettingVideoCaptureVideoFormat,                 iGrabSettings.iVideoCaptureVideoFormat);
+        SaveDFSValueL(settingsStore, KSGSettingVideoCaptureMemoryInUse,                 (TInt&)iGrabSettings.iVideoCaptureMemoryInUse);
+        SaveDFSValueL(settingsStore, KSGSettingVideoCaptureMemoryInUseMultiDrive,       (TInt&)iGrabSettings.iVideoCaptureMemoryInUseMultiDrive);
+        SaveDFSValueL(settingsStore, KSGSettingVideoCaptureFileName,                    iGrabSettings.iVideoCaptureFileName);
+        
+        settingsStore->CommitL();
+        CleanupStack::PopAndDestroy(); // settingsStore             
+        }
+    }
+    	
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::DoCancel()
+	{
+    iTimer.Cancel();
+	}
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::ActivateCaptureKeysL(TBool aChangeKey)
+    {
+    // if changing the capture key, capturing needs to be cancelled first
+    if (aChangeKey)
+        {
+        CancelCapturing();
+        }
+
+    // get hotkey of the capture
+    TInt captureHotkey(0);
+    if (iGrabSettings.iCaptureMode == ECaptureModeSingleCapture)
+        captureHotkey = iGrabSettings.iSingleCaptureHotkey;
+    else if (iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture)
+        captureHotkey = iGrabSettings.iSequantialCaptureHotkey;
+    else if (iGrabSettings.iCaptureMode == ECaptureModeVideoCapture)
+        captureHotkey = iGrabSettings.iVideoCaptureHotkey;
+    else
+        User::Panic(_L("Wrong mode"), 40);
+    
+    
+    // capture hash key if needed
+    if (captureHotkey == EHotkeyHashStar)
+        {
+        iCapturedKeyHash    = iRootWin.CaptureKey(EStdKeyHash, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+        iCapturedKeyHashUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyHash, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+        iHashKeyCapturingActivated = ETrue;
+        }
+    
+
+    // start capturing based on user selected key
+    switch (captureHotkey)
+        {
+        case EHotkeyShiftStar:
+            {
+            iCapturedKey    = iRootWin.CaptureKey('*', EModifierCtrl|EModifierShift|EModifierFunc, EModifierShift, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns('*', EModifierCtrl|EModifierShift|EModifierFunc, EModifierShift, KEY_CAPTURE_PRIORITY);
+            break;
+            }
+        case EHotkeyHashStar:
+            {
+            iCapturedKey    = iRootWin.CaptureKey('*', EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns('*', EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;
+            }
+        case EHotkeyShiftMenu:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyApplication0, EModifierCtrl|EModifierShift|EModifierFunc, EModifierShift, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyApplication0, EModifierCtrl|EModifierShift|EModifierFunc, EModifierShift, KEY_CAPTURE_PRIORITY);
+            break;
+            }
+        case EHotkeySendKey:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyYes, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyYes, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;
+            }
+        case EHotkeyPowerKey:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyDevice2, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyDevice2, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;
+            }
+        case EHotkeySideKey:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyDevice6, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyDevice6, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;            
+            }
+        case EHotkeyCameraKey1:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyDevice7, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyDevice7, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;            
+            }
+        case EHotkeyCameraKey2:
+            {
+            iCapturedKey    = iRootWin.CaptureKey(EStdKeyApplication1A, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyApplication1A, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            break;            
+            }
+       	case EHotkeyPOC:
+        	{
+        	iCapturedKey    = iRootWin.CaptureKey(EStdKeyApplication1, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+            iCapturedKeyUnD = iRootWin.CaptureKeyUpAndDowns(EStdKeyApplication1, EModifierCtrl|EModifierShift|EModifierFunc, 0, KEY_CAPTURE_PRIORITY);
+           	break;
+        	}  
+        default:
+            {
+            User::Panic(_L("Key not supported"), 100);
+            break;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::CancelCapturing()
+    {
+	// cancel all captures
+    iRootWin.CancelCaptureKey(iCapturedKey);
+    iRootWin.CancelCaptureKeyUpAndDowns(iCapturedKeyUnD);
+    
+    if (iHashKeyCapturingActivated)
+        {
+        iRootWin.CancelCaptureKey(iCapturedKeyHash);
+        iRootWin.CancelCaptureKeyUpAndDowns(iCapturedKeyHashUnD);
+        
+        iHashKeyCapturingActivated = EFalse;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+TBool CScreenGrabberModel::HandleCaptureCommandsL(const TWsEvent& aEvent)
+    {
+    TBool continueEventLoop(ETrue);
+    
+    // get hotkey of the capture
+    TInt captureHotkey(0);
+    if (iGrabSettings.iCaptureMode == ECaptureModeSingleCapture)
+        captureHotkey = iGrabSettings.iSingleCaptureHotkey;
+    else if (iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture)
+        captureHotkey = iGrabSettings.iSequantialCaptureHotkey;
+    else if (iGrabSettings.iCaptureMode == ECaptureModeVideoCapture)
+        captureHotkey = iGrabSettings.iVideoCaptureHotkey;
+    else
+        User::Panic(_L("Wrong mode"), 41);
+
+
+    // ignore any errors
+    if (aEvent.Type()==EEventErrorMessage)
+	    {
+	    // error
+	    }
+	
+	// check if hash key has been pushed down
+	else if (iHashKeyCapturingActivated && aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyHash)
+	    {
+        iHashKeyDown = ETrue;	    
+	    }
+
+	// check if hash key has been released
+	else if (iHashKeyCapturingActivated && aEvent.Type()==EEventKeyUp && aEvent.Key()->iScanCode==EStdKeyHash)
+	    {
+        iHashKeyDown = EFalse;	    
+	    }
+	    	
+    // handle captured keys, we are interested here only of the keydown events
+    else if (
+              ( captureHotkey == EHotkeyShiftStar &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode=='*' &&
+                aEvent.Key()->iModifiers & EModifierShift)
+            ||
+              ( captureHotkey == EHotkeyHashStar &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode=='*' &&
+                iHashKeyDown)
+            ||
+              ( captureHotkey == EHotkeyShiftMenu &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyApplication0 &&
+                aEvent.Key()->iModifiers & EModifierShift)
+            ||
+              ( captureHotkey == EHotkeySendKey &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyYes )
+            ||
+              ( captureHotkey == EHotkeyPowerKey &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyDevice2 )
+            ||
+              ( captureHotkey == EHotkeySideKey &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyDevice6 )
+            ||
+              ( captureHotkey == EHotkeyCameraKey1 &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyDevice7 )
+            ||
+              ( captureHotkey == EHotkeyCameraKey2 &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyDevice7 )
+            ||
+              ( captureHotkey == EHotkeyPOC &&
+                aEvent.Type()==EEventKeyDown && aEvent.Key()->iScanCode==EStdKeyApplication1A )
+            )
+		{
+		
+		// check if already capturing images in sequence
+		if ( iCapturingInProgress && !iStopCapturing && iNumberOfTakenShots!=0 && iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture )
+            {
+            // asking to stop capturing
+            iStopCapturing = ETrue;
+            
+            // cancel the active object, this will cancel any timer delays and ICL stuff
+            Cancel();
+            
+            // set status
+            iState = ECancelCapturing; 
+            
+            // jump smoothly to RunL()
+            iTimer.After(iStatus, 50);
+            SetActive(); 
+
+       		// do not continue the event loop in HandleWsEventL for these events
+           	continueEventLoop = EFalse;
+            }
+
+		// check if already capturing video
+		else if ( iCapturingInProgress && !iStopCapturing && iGrabSettings.iCaptureMode == ECaptureModeVideoCapture )
+            {
+            // asking to stop capturing
+            iStopCapturing = ETrue;
+            
+            // cancel the active object, this will cancel any timer delays and ICL stuff
+            Cancel();
+
+            // set status
+            iState = ECancelVideoCapturing;
+            
+            // jump smoothly to RunL()
+            iTimer.After(iStatus, 50);
+            SetActive(); 
+
+       		// do not continue the event loop in HandleWsEventL for these events
+           	continueEventLoop = EFalse;
+            }        
+        else if (!iCapturingInProgress && (iGrabSettings.iCaptureMode == ECaptureModeSingleCapture || iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture ))
+            {
+            // not capturing anything, so start doing that
+            iCapturingInProgress = ETrue;    
+
+			// take a screen shot and save it
+    	    TakeScreenShotAndSaveL();                
+
+       		// do not continue the event loop in HandleWsEventL for these events
+           	continueEventLoop = EFalse;
+            }
+        
+        else if (!iCapturingInProgress && iGrabSettings.iCaptureMode == ECaptureModeVideoCapture )
+            {
+            // not capturing anything, so start doing that
+            iCapturingInProgress = ETrue;
+            
+            // clean temporary files
+            TRAP_IGNORE( CleanTemporaryFilesL() );
+            
+            // get initial dimensions for the video
+            CWsScreenDevice* screenDevice = new(ELeave) CWsScreenDevice ( CEikonEnv::Static()->WsSession() );
+            CleanupStack::PushL(screenDevice);
+            User::LeaveIfError( screenDevice->Construct( iEnv->WsSession().GetFocusScreen() ) );
+            iVideoDimensions = screenDevice->SizeInPixels();
+            iPreviousFrameScreenDimension = screenDevice->SizeInPixels();
+            CleanupStack::PopAndDestroy(); // screenDevice
+
+			// capture the first frame
+			CaptureFrameForVideoL();              
+
+       		// do not continue the event loop in HandleWsEventL for these events
+           	continueEventLoop = EFalse;
+            }
+
+		}
+
+    // catch other event types as well so that we can ignore them
+    else if (
+              ( captureHotkey == EHotkeyShiftStar &&
+                aEvent.Key()->iScanCode=='*' &&
+                aEvent.Key()->iModifiers & EModifierShift)
+            ||
+              ( captureHotkey == EHotkeyHashStar &&
+                aEvent.Key()->iScanCode=='*' &&
+                iHashKeyDown)
+            ||
+              ( captureHotkey == EHotkeyShiftMenu &&
+                aEvent.Key()->iScanCode==EStdKeyApplication0 &&
+                aEvent.Key()->iModifiers & EModifierShift)
+            ||
+              ( captureHotkey == EHotkeySendKey &&
+                aEvent.Key()->iScanCode==EStdKeyYes )
+            ||
+              ( captureHotkey == EHotkeyPowerKey &&
+                aEvent.Key()->iScanCode==EStdKeyDevice2 )
+            ||
+              ( captureHotkey == EHotkeySideKey &&
+                aEvent.Key()->iScanCode==EStdKeyDevice6 )
+            ||
+              ( captureHotkey == EHotkeyCameraKey1 &&
+                aEvent.Key()->iScanCode==EStdKeyDevice7 )
+            ||
+              ( captureHotkey == EHotkeyCameraKey2 &&
+                aEvent.Key()->iScanCode==EStdKeyApplication1A )
+            ||
+    		  ( captureHotkey == EHotkeyPOC &&
+                aEvent.Key()->iScanCode==EStdKeyApplication1 )
+            )
+		{
+		// do not continue the event loop in HandleWsEventL for these events
+        continueEventLoop = EFalse;
+		}
+
+    return continueEventLoop;
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::TakeScreenShotAndSaveL()
+    {
+	// take a screen shot
+	CWsScreenDevice* screenDevice = new( ELeave ) CWsScreenDevice( CEikonEnv::Static()->WsSession() );
+	CleanupStack::PushL( screenDevice );
+	User::LeaveIfError( screenDevice->Construct( iEnv->WsSession().GetFocusScreen() ) );
+	User::LeaveIfError( iPreviouslyCapturedBitmap->Create(screenDevice->SizeInPixels(), screenDevice->DisplayMode()) );
+	User::LeaveIfError( screenDevice->CopyScreenToBitmap(iPreviouslyCapturedBitmap) );
+	CleanupStack::PopAndDestroy(); // screenDevice
+
+    // play a beep sound for each shot when capturing in sequantial mode
+    if (iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture)
+        PlayBeepSound();
+
+
+    // get memory in use & image format of the screen capture
+#ifdef SCREENGRABBER_MULTIDRIVE_SUPPORT            
+    TDriveNumber memoryInUse(EDriveC);
+#else
+    TInt memoryInUse(0);
+#endif
+    TInt imageFormat(0);
+    TFileName fileName;
+    
+    if (iGrabSettings.iCaptureMode == ECaptureModeSingleCapture)
+        {
+#ifdef SCREENGRABBER_MULTIDRIVE_SUPPORT            
+        memoryInUse = iGrabSettings.iSingleCaptureMemoryInUseMultiDrive;
+#else
+        memoryInUse = iGrabSettings.iSingleCaptureMemoryInUse;
+#endif
+        imageFormat = iGrabSettings.iSingleCaptureImageFormat;
+        fileName = iGrabSettings.iSingleCaptureFileName;
+        }
+    else if (iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture)
+        {
+#ifdef SCREENGRABBER_MULTIDRIVE_SUPPORT            
+        memoryInUse = iGrabSettings.iSequantialCaptureMemoryInUseMultiDrive;
+#else
+        memoryInUse = iGrabSettings.iSequantialCaptureMemoryInUse;
+#endif
+
+        imageFormat = iGrabSettings.iSequantialCaptureImageFormat;
+        fileName = iGrabSettings.iSequantialCaptureFileName;
+        }
+    else
+        User::Panic(_L("Wrong mode"), 30);  
+
+
+    // init the path for saving the file
+#ifdef SCREENGRABBER_MULTIDRIVE_SUPPORT
+    if (PathInfo::GetRootPath(iSaveFileName, memoryInUse) != KErrNone || !DriveOK(memoryInUse))
+        iSaveFileName.Copy( PathInfo::PhoneMemoryRootPath() );
+#else
+    if (memoryInUse == CAknMemorySelectionSettingPage::EPhoneMemory || !MemoryCardOK())
+        iSaveFileName.Copy( PathInfo::PhoneMemoryRootPath() );
+    else
+        iSaveFileName.Copy( PathInfo::MemoryCardRootPath() );
+#endif
+
+    iSaveFileName.Append( PathInfo::ImagesPath() );
+    iSaveFileName.Append( KScreenShotsSubDirectory );
+    
+    
+    // a quick check that filename is valid
+    if (fileName.Length() > 0 && fileName.Length() <= 255) 
+        iSaveFileName.Append( fileName );
+    else
+        iSaveFileName.Append( KDefaultImageFileName );
+
+    iSaveFileName.Append( _L(".") );
+
+
+    // reset the encoder
+    if (iImageEncoder)
+        {
+	    delete iImageEncoder;
+        iImageEncoder = NULL;
+        }
+        
+    
+    switch (imageFormat)
+        {
+        case EImageFormatPNG:
+            {
+            // set filename
+            iSaveFileName.Append(_L("png"));
+            CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+            // init & convert
+            iImageEncoder = CImageEncoder::FileNewL(iEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionAlwaysThread, KImageTypePNGUid);
+            iImageEncoder->Convert( &iStatus, *iPreviouslyCapturedBitmap );
+            }
+            break;
+        
+        case EImageFormatJPGHQ:
+        case EImageFormatJPGLQ:
+            {
+            // reset frameimagedata
+            if (iFrameImageData)
+                {
+                delete iFrameImageData;
+                iFrameImageData = NULL;
+                }
+            
+            // set filename
+            iSaveFileName.Append(_L("jpg"));
+            CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+            // init 
+            iImageEncoder = CImageEncoder::FileNewL(iEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionAlwaysThread, KImageTypeJPGUid);
+
+            // JPEG properties
+            TJpegImageData* imageData = new(ELeave) TJpegImageData;
+            imageData->iSampleScheme = TJpegImageData::EColor444;
+            imageData->iQualityFactor = (imageFormat==EImageFormatJPGHQ) ? HIGH_QUALITY_JPEG : LOW_QUALITY_JPEG;
+            iFrameImageData = CFrameImageData::NewL();
+            User::LeaveIfError(iFrameImageData->AppendImageData(imageData));  //ownership of imageData is transferred
+
+            // convert
+            iImageEncoder->Convert( &iStatus, *iPreviouslyCapturedBitmap, iFrameImageData );
+            }
+            break;
+        
+        case EImageFormatBMP:
+            {
+            // set filename
+            iSaveFileName.Append(_L("bmp"));
+            CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+            // init & convert
+            iImageEncoder = CImageEncoder::FileNewL(iEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionAlwaysThread, KImageTypeBMPUid);
+            iImageEncoder->Convert( &iStatus, *iPreviouslyCapturedBitmap );
+            }
+            break;
+
+        case EImageFormatGIF:
+            {
+            // set filename
+            iSaveFileName.Append(_L("gif"));
+            CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+            // init & convert
+            iImageEncoder = CImageEncoder::FileNewL(iEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionAlwaysThread, KImageTypeGIFUid);
+            iImageEncoder->Convert( &iStatus, *iPreviouslyCapturedBitmap );
+            }
+            break;
+            
+        case EImageFormatMBM:
+            {
+            // set filename
+            iSaveFileName.Append(_L("mbm"));
+            CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+            // init & convert
+            iImageEncoder = CImageEncoder::FileNewL(iEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionAlwaysThread, KImageTypeMBMUid);
+            iImageEncoder->Convert( &iStatus, *iPreviouslyCapturedBitmap );
+            }
+            break;
+            
+        default:
+            {
+            User::Panic(_L("Invalid Img Type"), 20);
+            }
+        }
+
+    // set the state of the active object
+	iState = EEncodingImage;
+
+    // indicate an outstanding request
+    SetActive();
+    }
+    
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::CaptureFrameForVideoL()
+    {
+    // record time
+    TTime timeNow;
+    timeNow.HomeTime();
+    
+    // take a screen shot	
+ 	CFbsBitmap* currentCapturedBitmap = new(ELeave) CFbsBitmap;
+ 	CleanupStack::PushL(currentCapturedBitmap);
+
+	CWsScreenDevice* screenDevice = new(ELeave) CWsScreenDevice( CEikonEnv::Static()->WsSession() );
+	CleanupStack::PushL( screenDevice );
+	User::LeaveIfError( screenDevice->Construct( iEnv->WsSession().GetFocusScreen() ) );
+	
+    TSize currentScreenSize = screenDevice->SizeInPixels();
+
+	User::LeaveIfError( currentCapturedBitmap->Create(currentScreenSize, EColor256) );
+	User::LeaveIfError( screenDevice->CopyScreenToBitmap(currentCapturedBitmap) );
+	CleanupStack::PopAndDestroy(); // screenDevice
+
+	// grow video's dimensions if the size has changed
+	if (currentScreenSize.iWidth > iVideoDimensions.iWidth)
+	    {
+	    iVideoDimensions.iWidth = currentScreenSize.iWidth;
+	    }
+	if (currentScreenSize.iHeight > iVideoDimensions.iHeight)
+	    {
+	    iVideoDimensions.iHeight = currentScreenSize.iHeight;
+	    }
+
+    TInt64 currentDelay(0);
+ 
+    // play a beep sound every 30th frame
+    if (iCurrentFrameNumber%30 == 0)
+        PlayBeepSound();
+
+    // create a new frame
+    TVideoFrame frame;
+    frame.iDelay = 500; // use default delay 5.00 secs
+    
+    // get info of the RAM drive
+    TDriveNumber ramDrive = EDriveD;
+    TVolumeInfo ramDriveInfo;
+    iEnv->FsSession().Volume(ramDriveInfo, ramDrive);
+    
+    // init the directory for saving the file, preferably use ram drive if there is enough disk space, otherwise use always C drive
+    TFileName tempDirectory;
+    TFileName sessionPath;
+    
+    if (ramDriveInfo.iFree > (iVideoDimensions.iWidth*iVideoDimensions.iHeight+50000))
+        sessionPath.Copy( _L("D:") );
+    else
+        sessionPath.Copy( _L("C:") );
+    
+    sessionPath.Append(KSGTemporaryDirectory);
+    tempDirectory.Copy(KSGTemporaryDirectory);
+    
+    iEnv->FsSession().MkDirAll(sessionPath);
+    iEnv->FsSession().SetSessionPath(sessionPath);
+
+    // create a temp file, path to the bitmap is saved automatically to frame.iFileStorePath
+    RFile file;
+    User::LeaveIfError( file.Temp(iEnv->FsSession(), tempDirectory, frame.iFileStorePath, EFileWrite) );
+    RFileWriteStream writeStream(file);
+    
+    TBool ignoreFrame(EFalse);
+    
+    // check if is this the first frame
+    if (iCurrentFrameNumber == 0)
+        {
+        // first frame is always the full one
+        frame.iWidth = currentScreenSize.iWidth;    
+        frame.iHeight = currentScreenSize.iHeight;  
+        frame.iXPos = 0;
+        frame.iYPos = 0;
+        frame.iEnableTransparency = EFalse;
+        frame.iFillsWholeScreen = ETrue;
+        
+        currentCapturedBitmap->ExternalizeL(writeStream);  
+
+        }
+    
+    else
+        {
+        // next frame is a difference between the previous one
+        currentDelay = timeNow.MicroSecondsFrom(iPreviousFrameTaken).Int64();
+        
+        // get reference to previos frame
+        TVideoFrame& prevFrame = iVideoFrameArray->At(iVideoFrameArray->Count()-1);
+        
+        
+        // check if video dimensions have changed
+        if (currentScreenSize.iWidth != iPreviousFrameScreenDimension.iWidth
+            || currentScreenSize.iHeight != iPreviousFrameScreenDimension.iHeight)
+            {
+            // dimensions have changed -> save a full bitmap
+            frame.iWidth = currentScreenSize.iWidth;    
+            frame.iHeight = currentScreenSize.iHeight;  
+            frame.iXPos = 0;
+            frame.iYPos = 0;
+            frame.iEnableTransparency = EFalse;
+            frame.iFillsWholeScreen = ETrue;
+            
+            currentCapturedBitmap->ExternalizeL(writeStream);            
+
+            // update the previous frame to contain the new delay value
+            prevFrame.iDelay = TUint( (double) currentDelay / 10000 );
+            }
+
+        else
+            {
+            // compare the bitmaps
+            HBufC8* curImgScanLineBuf = HBufC8::NewLC(currentScreenSize.iWidth*3);
+            TPtr8 curImgScanLinePtr = curImgScanLineBuf->Des();
+            HBufC8* prevImgScanLineBuf = HBufC8::NewLC(currentScreenSize.iWidth*3);
+            TPtr8 prevImgScanLinePtr = prevImgScanLineBuf->Des();
+            
+            TPoint pt(0,0);
+            TBool differenceFound(EFalse);
+            TPoint leftTopDifferencePoint(0,0);
+            TPoint rightBottomDifferencePoint(currentScreenSize.iWidth,currentScreenSize.iHeight);
+            
+            // scan the image from top to bottom
+            for (TInt i=0; i<currentScreenSize.iHeight; i++)
+                {
+                pt.iY = i;
+                
+                currentCapturedBitmap->GetScanLine(curImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                iPreviouslyCapturedBitmap->GetScanLine(prevImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                
+                if (curImgScanLinePtr != prevImgScanLinePtr)
+                    {
+                    differenceFound = ETrue;
+                    
+                    // get the y-coordinate
+                    leftTopDifferencePoint.iY = i;
+
+                    break;    
+                    }
+                }
+                
+            if (differenceFound)
+                {
+                // now we know that there is some difference between those two captured frames,
+                // get the bottom value by scaning from bottom to top
+                for (TInt i=currentScreenSize.iHeight-1; i>=0; i--)
+                    {
+                    pt.iY = i;
+                    
+                    currentCapturedBitmap->GetScanLine(curImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                    iPreviouslyCapturedBitmap->GetScanLine(prevImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                    
+                    if (curImgScanLinePtr != prevImgScanLinePtr)
+                        {
+                        // get the y-coordinate
+                        rightBottomDifferencePoint.iY = i+1;
+
+                        break;    
+                        }
+                    }
+                    
+                // check that the height of the cropped image will be at least 1
+                if (rightBottomDifferencePoint.iY <= leftTopDifferencePoint.iY)
+                    rightBottomDifferencePoint.iY = leftTopDifferencePoint.iY+1;  
+                
+                      
+                // get also the x-coordinates by scanning vertical scan lines
+                HBufC8* curImgVerticalScanLineBuf = HBufC8::NewLC(currentScreenSize.iHeight*3);
+                TPtr8 curImgVerticalScanLinePtr = curImgScanLineBuf->Des();
+                HBufC8* prevImgVerticalScanLineBuf = HBufC8::NewLC(currentScreenSize.iHeight*3);
+                TPtr8 prevImgVerticalScanLinePtr = prevImgScanLineBuf->Des();
+                        
+                // first scan by from left to right
+                for (TInt i=0; i<currentScreenSize.iWidth; i++)
+                    {
+                    currentCapturedBitmap->GetVerticalScanLine(curImgVerticalScanLinePtr, i, EColor256);
+                    iPreviouslyCapturedBitmap->GetVerticalScanLine(prevImgVerticalScanLinePtr, i, EColor256);
+                    
+                    if (curImgVerticalScanLinePtr != prevImgVerticalScanLinePtr)
+                        {
+                        leftTopDifferencePoint.iX = i;
+                        break;
+                        }
+                    }
+
+                // finally scan from right to left
+                for (TInt i=currentScreenSize.iWidth-1; i>=0; i--)
+                    {
+                    currentCapturedBitmap->GetVerticalScanLine(curImgVerticalScanLinePtr, i, EColor256);
+                    iPreviouslyCapturedBitmap->GetVerticalScanLine(prevImgVerticalScanLinePtr, i, EColor256);
+                    
+                    if (curImgVerticalScanLinePtr != prevImgVerticalScanLinePtr)
+                        {
+                        rightBottomDifferencePoint.iX = i+1;
+                        break;
+                        }
+                    }
+                    
+                CleanupStack::PopAndDestroy(2); //curImgVerticalScanLineBuf,prevImgVerticalScanLineBuf               
+
+                
+                // check that the width of the cropped image will be at least 1
+                if (rightBottomDifferencePoint.iX <= leftTopDifferencePoint.iX)
+                    rightBottomDifferencePoint.iX = leftTopDifferencePoint.iX+1;
+                   
+                
+                // record dimensions and position of the image           
+                frame.iWidth = rightBottomDifferencePoint.iX - leftTopDifferencePoint.iX;    
+                frame.iHeight = rightBottomDifferencePoint.iY - leftTopDifferencePoint.iY;  
+                frame.iXPos = leftTopDifferencePoint.iX;
+                frame.iYPos = leftTopDifferencePoint.iY;
+                frame.iEnableTransparency = ETrue;
+                frame.iFillsWholeScreen = EFalse;
+            
+            
+                // take a copy of the current frame
+             	CFbsBitmap* workingBitmap = new(ELeave) CFbsBitmap;
+             	CleanupStack::PushL(workingBitmap);
+                User::LeaveIfError( workingBitmap->Create(currentScreenSize, EColor256) );
+
+                HBufC8* tempScanLineBuf = HBufC8::NewLC(currentScreenSize.iWidth*3);
+                TPtr8 tempScanLinePtr = tempScanLineBuf->Des();
+                
+                for (TInt i=0; i<currentScreenSize.iHeight; i++)
+                    {
+                    pt.iY = i;
+                    currentCapturedBitmap->GetScanLine(tempScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                    workingBitmap->SetScanLine(tempScanLinePtr, i);
+                    }
+                    
+                CleanupStack::PopAndDestroy(); //tempScanLineBuf
+                
+                
+                // mark the non-changed areas with transparency color
+                TUint8* curPtr = NULL;
+                TUint8* prevPtr = NULL;
+                for (TInt i=frame.iYPos; i<frame.iYPos+frame.iHeight; i++)
+                    {
+                    pt.iY = i;
+                    
+                    workingBitmap->GetScanLine(curImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                    iPreviouslyCapturedBitmap->GetScanLine(prevImgScanLinePtr, pt, currentScreenSize.iWidth, EColor256);
+                    
+                    // check single pixels in the scanline
+                    for (TInt j=frame.iXPos; j<frame.iXPos+frame.iWidth; j++)
+                        {
+                        curPtr = &curImgScanLinePtr[j];
+                        prevPtr = &prevImgScanLinePtr[j];
+                        
+                        // check that our transparency index isn't already in use
+                        if (curPtr[0] == TRANSPARENCY_INDEX)
+                            curPtr[0] = TRANSPARENCY_ALTERNATIVE_INDEX;
+                        
+                        // replace with transparency index if there is no change compared to the previous frame
+                        if (curPtr[0] == prevPtr[0])
+                            curPtr[0] = TRANSPARENCY_INDEX;
+                        }
+                        
+                    // set new scanline    
+                    workingBitmap->SetScanLine(curImgScanLinePtr, i);
+                    }
+
+
+                // externalize the bitmap
+                TRect changedRect(leftTopDifferencePoint, rightBottomDifferencePoint);
+                workingBitmap->ExternalizeRectangleL(writeStream, changedRect);
+                
+                CleanupStack::PopAndDestroy(); //workingBitmap
+ 
+                // update the previous frame to contain the new delay value
+                prevFrame.iDelay = TUint( (double) currentDelay / 10000 );
+                }
+
+            else
+                {
+                // frames are identical, we can just ignore this one
+                ignoreFrame = ETrue;     
+                }
+            
+            CleanupStack::PopAndDestroy(2); //curImgScanLineBuf,prevImgScanLineBuf
+
+            } // if (videoDimensionsHaveChanged)
+
+        } //if (iCurrentFrameNumber == 0)
+            
+    // close the stream
+    writeStream.CommitL();
+    writeStream.Close();
+    file.Close();
+    
+
+    if (ignoreFrame)
+        {
+        // delete the temp file since we don't need that
+        iEnv->FsSession().Delete(frame.iFileStorePath);
+        }
+    else
+        {
+        // remember for the next frame when this frame was taken
+        iPreviousFrameTaken = timeNow;
+
+        // take a copy of currentCapturedBitmap to iPreviouslyCapturedBitmap
+        User::LeaveIfError( iPreviouslyCapturedBitmap->Create(iVideoDimensions, EColor256) );
+
+        TPoint pt(0,0);
+        HBufC8* tempScanLineBuf = HBufC8::NewMaxLC(iVideoDimensions.iWidth);
+        TPtr8 tempScanLinePtr = tempScanLineBuf->Des();
+        
+        for (TInt i=0; i<iVideoDimensions.iHeight; i++)
+            {
+            pt.iY = i;
+            currentCapturedBitmap->GetScanLine(tempScanLinePtr, pt, iVideoDimensions.iWidth, EColor256);
+            iPreviouslyCapturedBitmap->SetScanLine(tempScanLinePtr, i);
+            }
+            
+        CleanupStack::PopAndDestroy(); //tempScanLineBuf
+        
+        // append frame information to the array
+        iVideoFrameArray->AppendL(frame);
+        
+        // remember screen size
+        iPreviousFrameScreenDimension = currentScreenSize;
+        }    
+
+    
+    CleanupStack::PopAndDestroy(); //currentCapturedBitmap
+    
+
+    // set the state of the active object
+	iState = ENextVideoFrame;
+	
+    // check time spent on the work above (probably this is not so important)
+	TTime timeNow2;
+    timeNow2.HomeTime();
+    TInt64 handlingDelay = timeNow2.MicroSecondsFrom(timeNow).Int64();
+    
+	// calculate delay till next frame
+	TUint idealDelay = VIDEO_CAPTURE_DELAY*1000;
+	TInt usedDelay; 
+	if (currentDelay > idealDelay)
+	    usedDelay = idealDelay - (currentDelay - idealDelay) - handlingDelay;
+	else
+	    usedDelay = idealDelay - handlingDelay;
+	
+	// check that the delay is atleast minimum delay anyway
+	if (usedDelay < VIDEO_CAPTURE_MINIMUM_DELAY*1000)
+	    usedDelay = VIDEO_CAPTURE_MINIMUM_DELAY*1000;
+	
+	iTimer.After(iStatus, usedDelay);
+
+    // indicate an outstanding request
+    SetActive();
+    }
+    
+// ---------------------------------------------------------------------------
+    
+void CScreenGrabberModel::RunL()
+    {
+	switch (iState) 
+		{
+        // encoding of the image is now finished
+		case EEncodingImage: 
+			{
+            if (iGrabSettings.iCaptureMode == ECaptureModeSingleCapture)
+                {
+                // single shot done
+                CapturingFinishedL( iStatus.Int() );
+                }
+
+            else if (iGrabSettings.iCaptureMode == ECaptureModeSequantialCapture)
+                {
+                // increase the counter    
+                iNumberOfTakenShots++;
+                
+                // check if we can take more shots or just finish
+                if (!iStopCapturing && iStatus.Int()==KErrNone)
+                    {
+                    // notify the new file to Media Gallery
+                    UpdateFileToGallery(iSaveFileName);
+        
+                    // some delay before the next shot can be taken    
+                    iState = ESequenceDelay;
+                    
+                    // some checking that the value of delay is valid
+                    TInt delay(iGrabSettings.iSequantialCaptureDelay); //ms
+                    if (delay<0 && delay > 999999)
+                        delay = DEFAULT_SEQ_CAPTURE_DELAY_MS;
+                      
+                    iTimer.After(iStatus, delay*1000);
+                    SetActive();  
+                    }
+                else
+                    {
+                    // finished
+                    CapturingFinishedL( iStatus.Int() );
+                    }                       
+               }
+            else
+                User::Panic(_L("Wrong mode"), 32);            
+
+            break;
+			}
+
+        // delay finished, ready to take the next shot
+		case ESequenceDelay: 
+			{
+			TakeScreenShotAndSaveL();
+
+            break;
+			}
+			
+		// asked to cancel capturing	
+		case ECancelCapturing:
+			{
+            // finished
+            CapturingFinishedL( iStatus.Int() );
+
+            break;
+			}
+			
+		case ENextVideoFrame:
+		    {
+		    // increase the counter
+		    iCurrentFrameNumber++;
+		    
+            // check if we can take more frames or just finish
+            if (!iStopCapturing && iStatus.Int()==KErrNone)
+                {
+                // take next frame
+                CaptureFrameForVideoL();
+                }
+            else
+                {
+                // finished, save video
+                SaveVideoL( iStatus.Int() );
+                } 		        
+		    }
+		    break;
+
+		case ECancelVideoCapturing:
+		    {
+            // finished, save video
+            SaveVideoL( iStatus.Int() ); 		        
+		    }
+		    break;
+		    			        
+        // delay of the query is now finished
+        case EQueryDelay:
+			{
+    		iState = EIdle;
+
+            // now remove the query
+            iSavedQuery->Cancel();
+
+            // capturing can now be restarted
+            iCapturingInProgress = EFalse;
+            iStopCapturing = EFalse;
+
+            break;
+			}
+
+		default:
+			{
+            break;
+			}
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::SaveVideoL(TInt aErr)
+    {
+    if (aErr)
+        CapturingFinishedL(aErr);   
+   
+    else if (iGrabSettings.iVideoCaptureVideoFormat == EVideoFormatAnimatedGIF)
+        {
+        TInt err(KErrNone);
+        
+        // init the path for saving the file
+
+#ifdef SCREENGRABBER_MULTIDRIVE_SUPPORT
+        if (PathInfo::GetRootPath(iSaveFileName, iGrabSettings.iVideoCaptureMemoryInUseMultiDrive) != KErrNone || !DriveOK(iGrabSettings.iVideoCaptureMemoryInUseMultiDrive))
+            iSaveFileName.Copy( PathInfo::PhoneMemoryRootPath() );
+#else
+        if (iGrabSettings.iVideoCaptureMemoryInUse == CAknMemorySelectionSettingPage::EPhoneMemory || !MemoryCardOK())
+            iSaveFileName.Copy( PathInfo::PhoneMemoryRootPath() );
+        else
+            iSaveFileName.Copy( PathInfo::MemoryCardRootPath() );
+#endif
+
+        iSaveFileName.Append( PathInfo::ImagesPath() );     // animated gif is actually an image, not a video
+        iSaveFileName.Append( KScreenShotsSubDirectory );
+ 
+    
+        // a quick check that filename is valid
+        if (iGrabSettings.iVideoCaptureFileName.Length() > 0 && iGrabSettings.iVideoCaptureFileName.Length() <= 255) 
+            iSaveFileName.Append( iGrabSettings.iVideoCaptureFileName );
+        else
+            iSaveFileName.Append( KDefaultVideoFileName );
+
+        iSaveFileName.Append( _L(".gif") );
+
+        CApaApplication::GenerateFileName(iEnv->FsSession(), iSaveFileName );  // unique filename
+
+        // create and save the gif animation
+        err = CGifAnimator::CreateGifAnimation(iSaveFileName, iVideoDimensions, iVideoFrameArray);
+        
+        // remove the saved file in case of errors since it's likely corrupted
+        if (err != KErrNone)
+            iEnv->FsSession().Delete(iSaveFileName);
+        
+        CapturingFinishedL(err);   
+        }
+        
+    else
+        CapturingFinishedL(KErrNotSupported);
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::CleanTemporaryFilesL()
+    {
+    // delete temporary files from C and D drives    
+    CFileMan* fileMan = CFileMan::NewL(iEnv->FsSession());
+
+    TFileName delFilesPath;
+        
+    for (TInt i=0; i<1; i++)
+        {
+        delFilesPath.Copy(KNullDesC);
+        delFilesPath.Append('C'+i);
+        delFilesPath.Append(_L(":"));
+        delFilesPath.Append(KSGTemporaryDirectory);
+        delFilesPath.Append(_L("*.$$$"));
+        
+        fileMan->Delete(delFilesPath);
+        }
+
+    delete fileMan;    
+    }
+
+// ---------------------------------------------------------------------------
+    
+void CScreenGrabberModel::CapturingFinishedL(TInt aErr)
+    {
+    // display a global query to show the results
+
+    if (aErr == KErrNone)
+        {
+        switch (iGrabSettings.iCaptureMode)
+            {
+            case ECaptureModeSingleCapture:
+                {
+                iSavedQuery->DisplayL(KSingleShotSaved);
+                }
+                break;
+            
+            case ECaptureModeSequantialCapture:
+                {
+                if (iNumberOfTakenShots == 1)
+                    iSavedQuery->DisplayL(KSingleShotSaved);
+                else
+                    {
+                    TBuf<256> note;
+                    note.Format(KMultipleShotsSaved, iNumberOfTakenShots);
+                    iSavedQuery->DisplayL(note);
+                    }
+                }
+                break;            
+    
+            case ECaptureModeVideoCapture:
+                {
+                iSavedQuery->DisplayL(KVideoSaved);
+                }
+                break;             
+    
+            default:
+                User::Panic(_L("Inv.capt.mode"), 51);
+                break;
+            }            
+       
+        // notify the new file to Media Gallery
+        UpdateFileToGallery(iSaveFileName);
+        }
+    else
+        {
+        TBuf<256> errorNote;
+        errorNote.Copy( KErrorOccured );
+
+        CTextResolver* textResolver = CTextResolver::NewLC();
+        errorNote.Append( textResolver->ResolveErrorString(aErr) );
+        CleanupStack::PopAndDestroy();  //textResolver    
+          
+        iSavedQuery->DisplayL(errorNote, ETrue);
+        }
+
+    // reset values
+    iNumberOfTakenShots = 0;
+    iCurrentFrameNumber = 0;
+    iVideoFrameArray->Reset();
+
+
+    // remove the query after 2.0 secs
+    iState = EQueryDelay;
+    iTimer.After(iStatus, 2000000);
+    SetActive();
+
+    }
+    
+// ---------------------------------------------------------------------------
+
+TBool CScreenGrabberModel::MemoryCardOK()
+	{
+	return DriveOK(EDriveE); // hardcoding EDriveE here maybe is not so good idea..   
+	}
+
+// ---------------------------------------------------------------------------
+
+TBool CScreenGrabberModel::DriveOK(TDriveNumber aNumber)
+	{
+	TBool isOK(EFalse);
+
+    TVolumeInfo vInfo;
+
+	// check if we can access the drive
+	if (iEnv->FsSession().Volume(vInfo, aNumber) == KErrNone)
+		isOK = ETrue;
+
+	// returns ETrue if memory card working properly
+	return isOK;
+	}
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::PlayBeepSound()
+    {
+    TMdaAudioToneUtilityState toneState = iMdaAudioToneUtility->State();
+    
+    if (toneState == EMdaAudioToneUtilityPlaying)
+        iMdaAudioToneUtility->CancelPlay();
+    else if (toneState == EMdaAudioToneUtilityNotReady)
+        iMdaAudioToneUtility->CancelPrepare();
+
+    iMdaAudioToneUtility->PrepareToPlayTone(500, TTimeIntervalMicroSeconds(100000));
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::MatoPrepareComplete(TInt aError)
+    {
+    if (aError == KErrNone)
+        iMdaAudioToneUtility->Play();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CScreenGrabberModel::MatoPlayComplete(TInt /*aError*/)
+    {
+    }
+
+// ---------------------------------------------------------------------------
+
+TInt CScreenGrabberModel::UpdateFileToGallery(const TDesC& aFullPath)
+    {
+    // first check if this feature is supported    
+    if (iGalleryUpdaterSupported)
+        {
+        // check if has been initialized
+        if (!iGalleryUpdaterInitialized)
+            {
+            // not initialized, first try to load the DLL    
+            if (iGalleryUpdaterDLL.Load(_L("MGXMediaFileAPI.dll")) == KErrNone)
+                {
+                // construct the object, equals:
+                // CMGXFileManager* mgxFileManager = (MGXFileManagerFactory::NewFileManagerL)(NewFileManagerLEntry)(iEnv->FsSession());
+            
+                typedef CMGXFileManager* (*TMyFunc)(RFs& aFs);
+                TMyFunc theFunc = (TMyFunc)iGalleryUpdaterDLL.Lookup(1);
+                if (theFunc)
+                    {
+                    TRAPD( err, iMGXFileManager = theFunc(iEnv->FsSession()) );
+                    if (iMGXFileManager && err == KErrNone)
+                        {
+                        // construction completed succesfully
+                        iGalleryUpdaterInitialized = ETrue;
+                        }
+                    else
+                        {
+                        // out of memory or other unknown error?    
+                        iGalleryUpdaterDLL.Close();
+                        }
+                    }
+                else
+                    {
+                    // ordinal not found from the DLL 
+                    iGalleryUpdaterDLL.Close();
+                    }    
+                }
+            else
+                {
+                // DLL does not exist in the device
+                }
+            }
+
+        // update the file if gallery updater has been initialized
+        if (iGalleryUpdaterInitialized)
+            {
+            TRAPD(err, iMGXFileManager->UpdateL(aFullPath));
+            return err;    
+            }
+        else
+            {
+            // gallery updater not supported if initialization failed    
+            iGalleryUpdaterSupported = EFalse;
+            return KErrNotSupported;    
+            }            
+        }
+    else
+        {
+        return KErrNotSupported;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+/*************************************************************************************************/
+// a class to display an info message that the screen shot was saved to disk
+
+CSavedQuery::CSavedQuery() : CActive(EPriorityLow)
+    {
+	CActiveScheduler::Add(this);
+    }
+
+void CSavedQuery::ConstructL()
+    {
+    iGlobalConfirmationQuery = CAknGlobalConfirmationQuery::NewL();
+    }
+
+CSavedQuery* CSavedQuery::NewL()
+    {
+    CSavedQuery* self = new(ELeave) CSavedQuery();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CSavedQuery::~CSavedQuery()
+    {
+    delete iGlobalConfirmationQuery;
+    }
+
+void CSavedQuery::DisplayL(const TDesC &aText, TBool aDisplayErrorNote)
+    {
+    if (!iVisible)
+        {
+        TRAPD(err, DisplayWithGraphicsL(aText, aDisplayErrorNote));
+        if (err != KErrNone)
+            {
+            DisplayWithoutGraphicsL(aText);
+            }
+        iVisible = ETrue;
+        SetActive();
+        }
+    }
+
+void CSavedQuery::DoCancel()
+    {
+    if (iGlobalConfirmationQuery)
+        {
+        iGlobalConfirmationQuery->CancelConfirmationQuery();
+        }
+    iVisible = EFalse;
+    }
+
+void CSavedQuery::RunL()
+    {
+    iVisible = EFalse;
+    }
+
+void CSavedQuery::DisplayWithGraphicsL(const TDesC &aText, TBool aDisplayErrorNote)
+    {
+    if (aDisplayErrorNote)
+        {
+        iGlobalConfirmationQuery->ShowConfirmationQueryL
+            (iStatus, aText, R_AVKON_SOFTKEYS_EMPTY, R_QGN_NOTE_ERROR_ANIM,
+            KNullDesC, 0, 0, CAknQueryDialog::EErrorTone, ETrue);
+        }
+    else
+        {
+        iGlobalConfirmationQuery->ShowConfirmationQueryL
+            (iStatus, aText, R_AVKON_SOFTKEYS_EMPTY, R_QGN_NOTE_OK_ANIM,
+            KNullDesC, 0, 0, CAknQueryDialog::EConfirmationTone, ETrue);
+        }
+    }
+
+void CSavedQuery::DisplayWithoutGraphicsL(const TDesC &aText)
+    {
+	iGlobalConfirmationQuery->ShowConfirmationQueryL
+        (iStatus, aText, R_AVKON_SOFTKEYS_OK_EMPTY);
+    }
+
+/*************************************************************************************************/