Browse Source

created thread class to handle threading operations for qpaste wnd

git-svn-id: svn://svn.code.sf.net/p/ditto-cp/code/trunk@478 595ec19a-5cb4-439b-94a8-42fb3063c22c
sabrogden 16 years ago
parent
commit
8c12e0e7ba
14 changed files with 1834 additions and 1636 deletions
  1. 10 7
      CP_Main.cpp
  2. 10 0
      CP_Main.vcxproj
  3. 4 4
      Clip.h
  4. 141 0
      EventThread.cpp
  5. 38 0
      EventThread.h
  6. 1 1
      ExternalWindowTracker.cpp
  7. 1296 1285
      MainFrm.cpp
  8. 6 1
      MainFrm.h
  9. 73 0
      MessagePumpThread.cpp
  10. 29 0
      MessagePumpThread.h
  11. 78 64
      QListCtrl.cpp
  12. 11 3
      QListCtrl.h
  13. 119 265
      QPasteWnd.cpp
  14. 18 6
      QPasteWnd.h

+ 10 - 7
CP_Main.cpp

@@ -266,7 +266,7 @@ BOOL CCP_MainApp::InitInstance()
 	pFrame->ShowWindow(SW_SHOW);
 	pFrame->UpdateWindow();
 
-	m_Addins.LoadAll();
+	//m_Addins.LoadAll();
 
 	return TRUE;
 }
@@ -319,10 +319,7 @@ void CCP_MainApp::AfterMainCreate()
 	m_pCutBuffer3 = new CHotKey("CopyBufferCutHotKey_2", 0, true);
 
 	g_HotKeys.RegisterAll();
-
-	// CopyThread initialization
 	StartCopyThread();
-	
 	StartStopServerThread();
 
 	m_bAppRunning = true;
@@ -349,12 +346,12 @@ void CCP_MainApp::StopServerThread()
 
 void CCP_MainApp::BeforeMainClose()
 {
-	ASSERT( m_bAppRunning && !m_bAppExiting );
+	/*ASSERT( m_bAppRunning && !m_bAppExiting );
 	m_bAppRunning = false;
 	m_bAppExiting = true;
 	g_HotKeys.UnregisterAll();
 	StopServerThread();
-	StopCopyThread();
+	StopCopyThread();*/
 }
 
 void CCP_MainApp::StartCopyThread()
@@ -402,10 +399,13 @@ bool CCP_MainApp::ToggleConnectCV()
 //   lose that connection, "Disconnect from Clipboard" will have a check next to it.
 void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
 {
+	//CString b=_T("Scott");
+	//pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, b);
 	if(pMenu == NULL)
 		return;
 
-	bool bConnect = theApp.GetConnectCV();
+	bool bConnect = false;
+	bool b = theApp.GetConnectCV();
 	CString cs;
 
 	if(bConnect)
@@ -470,7 +470,10 @@ long CCP_MainApp::SaveCopyClips()
 
 	CClipList* pClips = m_CopyThread.GetClips(); // we now own pClips
 	if(!pClips)
+	{
+		Log(_T("End of function SaveCopyClips, no clips to save"));
 		return 0;
+	}
 
 	CClipList* pCopyOfClips = NULL;
 	if(g_Opt.m_lAutoSendClientCount > 0)

+ 10 - 0
CP_Main.vcxproj

@@ -369,6 +369,7 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Unicode Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Unicode Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="ClipFormatQListCtrl.cpp" />
     <ClCompile Include="Clip_ImportExport.cpp" />
     <ClCompile Include="ClipboardSaveRestore.cpp" />
     <ClCompile Include="ClipboardViewer.cpp">
@@ -451,7 +452,11 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Unicode Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Unicode Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="EventThread.cpp" />
+    <ClCompile Include="MainFrmThread.cpp" />
+    <ClCompile Include="MessagePumpThread.cpp" />
     <ClCompile Include="Popup.cpp" />
+    <ClCompile Include="QPasteWndThread.cpp" />
     <ClCompile Include="sqlite\CppSQLite3.cpp">
       <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -1289,12 +1294,17 @@
   <ItemGroup>
     <ClInclude Include="AlphaBlend.h" />
     <ClInclude Include="ArrayEx.h" />
+    <ClInclude Include="ClipFormatQListCtrl.h" />
+    <ClInclude Include="EventThread.h" />
     <ClInclude Include="FormattedTextDraw.h" />
     <ClInclude Include="GroupStatic.h" />
+    <ClInclude Include="MainFrmThread.h" />
     <ClInclude Include="memdc.h" />
+    <ClInclude Include="MessagePumpThread.h" />
     <ClInclude Include="NumberEdit.h" />
     <ClInclude Include="Popup.h" />
     <ClInclude Include="QListCtrl.h" />
+    <ClInclude Include="QPasteWndThread.h" />
     <ClInclude Include="RichEditCtrlEx.h" />
     <ClInclude Include="SearchEditBox.h" />
     <ClInclude Include="ToolTipEx.h" />

+ 4 - 4
Clip.h

@@ -34,10 +34,10 @@ public:
 class CClipFormat : public IClipFormat
 {
 public:
-	CLIPFORMAT	m_cfType;
-    HGLOBAL		m_hgData;
-	bool		m_autoDeleteData;
-	long		m_lDBID;
+	CLIPFORMAT m_cfType;
+    HGLOBAL m_hgData;
+	bool m_autoDeleteData;
+	long m_lDBID;
 
 	CClipFormat(CLIPFORMAT cfType = 0, HGLOBAL hgData = 0, long lDBID = -1);
 	~CClipFormat();

+ 141 - 0
EventThread.cpp

@@ -0,0 +1,141 @@
+#include "StdAfx.h"
+#include "EventThread.h"
+
+#define EXIT_EVENT -1
+
+CEventThread::CEventThread(void)
+{
+	AddEvent(EXIT_EVENT);
+	m_hEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
+	m_waitTimeout = 1000;
+	m_threadRunning = false;
+	m_exitThread = false;
+}
+
+CEventThread::~CEventThread(void)
+{
+	Stop();
+
+	for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++)
+	{
+		CloseHandle(it->first);
+	}
+}
+
+UINT CEventThread::EventThreadFnc(void* thisptr) 
+{
+	CEventThread *threadClass = (CEventThread*)thisptr;
+	threadClass->RunThread();
+	return 0;
+}
+
+void CEventThread::AddEvent(int eventId)
+{
+	HANDLE handle = CreateEvent(NULL, FALSE, FALSE, _T(""));
+	m_eventMap[handle] = eventId;
+}
+
+bool CEventThread::FireEvent(int eventId)
+{
+	HANDLE eventHandle = NULL;
+	for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++)
+	{
+		if(it->second == eventId)
+		{
+			eventHandle = it->first;
+		}
+	}
+
+	if(eventHandle != NULL)
+	{
+		SetEvent(eventHandle);
+		return true;
+	}
+	
+	return false;
+}
+
+void CEventThread::Start(void *param) 
+{
+	if(m_threadRunning == false)
+	{
+		m_exitThread = false;
+		m_param = param;
+		m_thread = (HANDLE)_beginthreadex(NULL, 0, EventThreadFnc, this, 0, &m_threadID);
+
+		// now wait until the thread is up and really running
+		WaitForSingleObject(m_hEvt, 1000);
+	}
+}
+
+void CEventThread::Stop(int waitTime) 
+{
+	m_exitThread = true;
+	FireEvent(EXIT_EVENT);
+
+	if (WAIT_OBJECT_0 != WaitForSingleObject(m_hEvt, waitTime))
+	{
+		if(TerminateThread(m_thread, 0))
+		{
+			m_threadRunning = false;
+		}
+	}
+};
+
+void CEventThread::RunThread()
+{
+	m_threadRunning = true;
+	HANDLE *pHandleArray = new HANDLE[m_eventMap.size()];
+
+	int indexPos = 0;
+	for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++)
+	{
+		pHandleArray[indexPos] = it->first;
+		indexPos++;
+	}
+
+	SetEvent(m_hEvt);
+
+	while(true)
+	{
+		DWORD event = WaitForMultipleObjects(m_eventMap.size(), pHandleArray, FALSE, m_waitTimeout);
+
+		if(event == WAIT_FAILED)
+		{
+			LPVOID lpMsgBuf = NULL;
+			DWORD dwErr = GetLastError();
+			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+							FORMAT_MESSAGE_FROM_SYSTEM |
+							FORMAT_MESSAGE_IGNORE_INSERTS,
+							NULL,
+							dwErr,
+							MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+							(LPTSTR) &lpMsgBuf,
+							0,
+							NULL);
+
+			ASSERT(!lpMsgBuf);
+			LocalFree(lpMsgBuf);
+		}
+		else if(event == WAIT_TIMEOUT)
+		{
+			OnTimeOut(m_param);
+		}
+		else
+		{
+			HANDLE firedHandle = pHandleArray[event - WAIT_OBJECT_0];
+			int eventId = m_eventMap[firedHandle];
+			if(eventId == EXIT_EVENT)
+			{
+				SetEvent(m_hEvt);
+				break;
+			}
+			else
+			{
+				OnEvent(eventId, m_param);
+			}
+		}
+	}
+
+	m_threadRunning = false;
+}

+ 38 - 0
EventThread.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include <vector>
+#include <map>
+
+typedef std::map<HANDLE, int> EventMapType;
+
+class CEventThread
+{
+public:
+	CEventThread(void);
+	~CEventThread(void);
+
+	static unsigned int __stdcall EventThreadFnc(void* thisptr);
+
+protected:
+	virtual void OnEvent(int eventId, void *param)	{ return; }
+	virtual void OnTimeOut(void *param) { return; }
+	void RunThread();
+
+	UINT m_threadID;
+	HANDLE m_thread;
+	HANDLE m_hEvt;
+	EventMapType m_eventMap;
+	bool m_exitThread;
+	bool m_threadRunning;
+	void *m_param;
+	int m_waitTimeout;
+
+public:
+	void Start(void *param = NULL);
+	void Stop(int waitTime = 5000); 
+	void AddEvent(int eventId);
+	bool FireEvent(int eventId);
+	bool IsCancelled() { return m_exitThread; }
+	bool IsRunning() { return m_threadRunning; }
+};
+

+ 1 - 1
ExternalWindowTracker.cpp

@@ -18,7 +18,7 @@ ExternalWindowTracker::~ExternalWindowTracker(void)
 
 bool ExternalWindowTracker::TrackActiveWnd(HWND focus)
 {
-	BOOL fromHook = true
+	BOOL fromHook = true;
 	HWND newFocus = focus;
 	HWND newActive = ::GetForegroundWindow();
 	if(newFocus == NULL)

+ 1296 - 1285
MainFrm.cpp

@@ -1,1286 +1,1297 @@
-// MainFrm.cpp : implementation of the CMainFrame class
-//
-
-#include "stdafx.h"
-#include "CP_Main.h"
-#include "MainFrm.h"
-#include "afxole.h"
-#include "Misc.h"
-#include "CopyProperties.h"
-#include "InternetUpdate.h"
-#include ".\mainfrm.h"
-#include "focusdll\focusdll.h"
-#include "HyperLink.h"
-#include "tinyxml.h"
-#include "Path.h"
-#include "DittoCopyBuffer.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#define	WM_ICON_NOTIFY			WM_APP+10
-
-
-bool CShowMainFrame::m_bShowingMainFrame = false;
-
-UINT RemoveDeletedItemsThread(LPVOID pParam)
-{
-	CMainFrame *mainWindow = (CMainFrame*)pParam;
-	if(mainWindow != NULL)
-	{
-		if(mainWindow->m_deletingEntries == false)
-		{
-			mainWindow->m_deletingEntries = true;
-			RemoveOldEntries();
-			mainWindow->m_deletingEntries = false;
-		}
-	}
-
-	return true;
-}
-
-CShowMainFrame::CShowMainFrame() : 
-	m_bHideMainFrameOnExit(false), 
-	m_hWnd(NULL)
-{
-	if(m_bShowingMainFrame == false)
-	{
-		theApp.m_pMainFrame->m_TrayIcon.MaximiseFromTray(theApp.m_pMainFrame);
-		m_bHideMainFrameOnExit = true;
-		m_bShowingMainFrame = true;
-	}
-
-	m_hWnd = theApp.m_pMainFrame->GetSafeHwnd();
-}
-CShowMainFrame::~CShowMainFrame()
-{
-	if(m_bHideMainFrameOnExit && m_hWnd && ::IsWindow(m_hWnd))
-	{
-		theApp.m_pMainFrame->m_TrayIcon.MinimiseToTray(theApp.m_pMainFrame);
-		m_bShowingMainFrame = false;
-	}
-}
-
-
-IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
-
-BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
-	//{{AFX_MSG_MAP(CMainFrame)
-	ON_WM_CREATE()
-	ON_COMMAND(ID_FIRST_OPTION, OnFirstOption)
-	ON_COMMAND(ID_FIRST_EXIT, OnFirstExit)
-	ON_WM_TIMER()
-	ON_COMMAND(ID_FIRST_SHOWQUICKPASTE, OnFirstShowquickpaste)
-	ON_COMMAND(ID_FIRST_TOGGLECONNECTCV, OnFirstToggleConnectCV)
-	ON_UPDATE_COMMAND_UI(ID_FIRST_TOGGLECONNECTCV, OnUpdateFirstToggleConnectCV)
-	ON_COMMAND(ID_FIRST_HELP, OnFirstHelp)
-	//}}AFX_MSG_MAP
-	ON_MESSAGE(WM_HOTKEY, OnHotKey)
-	ON_MESSAGE(WM_SHOW_TRAY_ICON, OnShowTrayIcon)
-	ON_MESSAGE(WM_COPYPROPERTIES, OnCopyProperties)
-	ON_MESSAGE(WM_CLOSE_APP, OnShutDown)
-	ON_MESSAGE(WM_CLIPBOARD_COPIED, OnClipboardCopied)
-	ON_WM_CLOSE()
-	ON_MESSAGE(WM_ADD_TO_DATABASE_FROM_SOCKET, OnAddToDatabaseFromSocket)
-	ON_MESSAGE(WM_SEND_RECIEVE_ERROR, OnErrorOnSendRecieve)
-	ON_MESSAGE(WM_FOCUS_CHANGED, OnFocusChanged)
-	ON_MESSAGE(WM_FOCUS_CHANGED+1, OnKeyBoardChanged)
-	ON_MESSAGE(WM_CUSTOMIZE_TRAY_MENU, OnCustomizeTrayMenu)
-	ON_COMMAND(ID_FIRST_IMPORT, OnFirstImport)
-	ON_MESSAGE(WM_EDIT_WND_CLOSING, OnEditWndClose)
-	ON_WM_DESTROY()
-	ON_COMMAND(ID_FIRST_NEWCLIP, OnFirstNewclip)
-	ON_MESSAGE(WM_SET_CONNECTED, OnSetConnected)
-END_MESSAGE_MAP()
-
-static UINT indicators[] =
-{
-	ID_SEPARATOR,           // status line indicator
-	ID_INDICATOR_CAPS,
-	ID_INDICATOR_NUM,
-	ID_INDICATOR_SCRL,
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame construction/destruction
-
-CMainFrame::CMainFrame()
-{
-	m_pEditFrameWnd = NULL;
-	m_keyStateModifiers = 0;
-	m_startKeyStateTime = 0;
-	m_bMovedSelectionMoveKeyState = false;
-	m_keyModifiersTimerCount = 0;
-	m_deletingEntries = false;
-}
-
-CMainFrame::~CMainFrame()
-{
-	if(g_Opt.m_bUseHookDllForFocus)
-	{
-		Log(_T("Unloading focus dll for tracking focus changes"));
-		StopMonitoringFocusChanges();
-	}
-	
-	CGetSetOptions::SetMainHWND(0);
-}
-
-int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
-{
-	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
-		return -1;
-
-	//Center the main window so message boxes are in the center
-	CRect rcScreen;
-	GetMonitorRect(0, &rcScreen);
-	CPoint cpCenter = rcScreen.CenterPoint();
-	MoveWindow(cpCenter.x,cpCenter.x, -2, -2);
-
-	//Then set the main window to transparent so it's never shown
-	//if it is shown then only the task tray icon
-	m_Transparency.SetTransparent(m_hWnd, 0, true);
-
-	SetWindowText(_T(""));
-
-	if(g_Opt.m_bUseHookDllForFocus)
-	{
-		Log(_T("Loading hook dll to track focus changes"));
-		MonitorFocusChanges(m_hWnd, WM_FOCUS_CHANGED);
-	}
-	else
-	{
-		Log(_T("Setting polling timer to track focus"));
-		SetTimer(ACTIVE_WINDOW_TIMER, g_Opt.FocusWndTimerTimeout(), 0);
-	}
-	
-	SetWindowText(_T("Ditto"));
-
-	HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
-
-	m_TrayIcon.Create(
-						NULL,				// Let icon deal with its own messages
-						WM_ICON_NOTIFY,	// Icon notify message to use
-						_T("Ditto"),	// tooltip
-						hIcon,
-						IDR_MENU,			// ID of tray icon
-						FALSE,
-						_T(""),			// balloon tip
-						_T(""),			// balloon title
-						NULL,				// balloon icon
-						20 );
-
-	m_TrayIcon.SetSingleClickSelect(TRUE);
-	m_TrayIcon.MinimiseToTray(this);
-	m_TrayIcon.SetMenuDefaultItem(ID_FIRST_SHOWQUICKPASTE, FALSE);
-
-	//Only if in release
-	#ifndef _DEBUG
-	{
-		//If not showing the icon show it for 40 seconds so they can get to the option
-		//in case they can't remember the hot keys or something like that
-		if(!(CGetSetOptions::GetShowIconInSysTray()))
-			SetTimer(HIDE_ICON_TIMER, 40000, 0);
-	}
-	#endif
-
-	//don't check for updates if running from a U3 device
-	if(!g_Opt.m_bU3)
-	{
-		SetTimer(CHECK_FOR_UPDATE, ONE_MINUTE*5, 0);
-	}
-
-	SetTimer(CLOSE_WINDOW_TIMER, ONE_MINUTE*60, 0);
-	SetTimer(REMOVE_OLD_REMOTE_COPIES, ONE_DAY, 0);
-	SetTimer(REMOVE_OLD_ENTRIES_TIMER, 2000, 0);
-
-	m_ulCopyGap = CGetSetOptions::GetCopyGap();
-
-	theApp.AfterMainCreate();
-
-	return 0;
-}
-
-BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
-{
-	if(cs.hMenu!=NULL)  
-	{
-		::DestroyMenu(cs.hMenu);      // delete menu if loaded
-		cs.hMenu = NULL;              // no menu for this window
-	}
-
-	if( !CFrameWnd::PreCreateWindow(cs) )
-		return FALSE;
-
-	WNDCLASS wc;	
-	wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
-	wc.lpfnWndProc = AfxWndProc;
-	wc.cbClsExtra = 0;
-	wc.cbWndExtra = 0;
-	wc.hInstance = AfxGetInstanceHandle();
-	wc.hIcon = NULL;
-	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
-	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
-	wc.lpszMenuName =  NULL;
-	wc.lpszClassName = _T("Ditto");
-
-	// Create the QPaste window class
-	if (!AfxRegisterClass(&wc))
-		return FALSE;
-
-	cs.lpszClass = wc.lpszClassName;
-	
-	return TRUE;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame diagnostics
-
-#ifdef _DEBUG
-void CMainFrame::AssertValid() const
-{
-	CFrameWnd::AssertValid();
-}
-
-void CMainFrame::Dump(CDumpContext& dc) const
-{
-	CFrameWnd::Dump(dc);
-}
-
-#endif //_DEBUG
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame message handlers
-
-
-void CMainFrame::OnFirstOption() 
-{
-	theApp.ShowOptionsDlg();
-}
-
-void CMainFrame::OnFirstExit() 
-{
-//	CloseAllOpenDialogs();
-	this->SendMessage(WM_CLOSE, 0, 0);
-}
-
-LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam)
-{
-	if(theApp.m_pDittoHotKey && wParam == theApp.m_pDittoHotKey->m_Atom)
-	{
-		//If they still have the shift/ctrl keys down
-		if(m_keyStateModifiers != 0 && m_quickPaste.IsWindowVisibleEx())
-		{
-			if(m_bMovedSelectionMoveKeyState == false)
-			{
-				Log(_T("Setting flag m_bMovedSelectionMoveKeyState to true, will paste when modifer keys are up"));
-			}
-
-			m_quickPaste.MoveSelection(true);
-			m_bMovedSelectionMoveKeyState = true;
-		}
-		else if(g_Opt.m_HideDittoOnHotKeyIfAlreadyShown && m_quickPaste.IsWindowVisibleEx())
-		{
-			m_quickPaste.HideQPasteWnd();
-		}
-		else
-		{
-			m_keyModifiersTimerCount = 0;
-			m_bMovedSelectionMoveKeyState = false;
-			m_startKeyStateTime = GetTickCount();
-			m_keyStateModifiers = GetKeyStateModifiers();
-			SetTimer(KEY_STATE_MODIFIERS, 50, NULL);
-			
-			theApp.m_activeWnd.TrackActiveWnd(NULL);
-			
-			m_quickPaste.ShowQPasteWnd(this, false, true, FALSE);
-		}		
-	}
-	else if(theApp.m_pNamedCopy && wParam == theApp.m_pNamedCopy->m_Atom)
-	{
-		if(g_Opt.m_bU3 == false)
-		{
-			if(theApp.m_QuickPasteMode == CCP_MainApp::NONE_QUICK_PASTE)
-			{
-				theApp.m_QuickPasteMode = CCP_MainApp::ADDING_QUICK_PASTE;
-
-				theApp.m_activeWnd.SendCopy();
-
-				m_pTypingToolTip = new CToolTipEx;
-				m_pTypingToolTip->Create(this);
-
-				csTypeToolTipTitle = theApp.m_Language.GetString("Named_Copy_Title", "Ditto - Named Copy");
-
-				m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle);
-
-				CRect rcScreen;
-				GetMonitorRect(0, &rcScreen);
-
-				m_ToolTipPoint = theApp.m_activeWnd.FocusCaret();
-				if(m_ToolTipPoint.x < 0 || m_ToolTipPoint.y < 0)
-				{
-					CRect cr;
-					::GetWindowRect(theApp.m_activeWnd.FocusWnd(), cr);
-					m_ToolTipPoint = cr.CenterPoint();
-				}
-				m_ToolTipPoint.Offset(-15, 15);
-				m_pTypingToolTip->Show(m_ToolTipPoint);
-
-				//If they don't type anything for 2 seconds stop looking
-				SetTimer(STOP_LOOKING_FOR_KEYBOARD, 20000, NULL);
-
-				MonitorKeyboardChanges(m_hWnd, WM_FOCUS_CHANGED+1);
-				SetCaptureKeys(true);
-			}
-		}
-	}
-	else if(theApp.m_pNamedPaste && wParam == theApp.m_pNamedPaste->m_Atom)
-	{
-		if(g_Opt.m_bU3 == false)
-		{
-			if(theApp.m_QuickPasteMode == CCP_MainApp::NONE_QUICK_PASTE)
-			{
-				theApp.m_QuickPasteMode = CCP_MainApp::PASTING_QUICK_PASTE;
-
-				m_pTypingToolTip = new CToolTipEx;
-				m_pTypingToolTip->Create(this);
-
-				csTypeToolTipTitle = theApp.m_Language.GetString("Named_Paste_Title", "Ditto - Named Paste");
-				m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle);
-
-				CRect rcScreen;
-
-				m_ToolTipPoint = theApp.m_activeWnd.FocusCaret();
-				if(m_ToolTipPoint.x < 0 || m_ToolTipPoint.y < 0)
-				{
-					CRect cr;
-					::GetWindowRect(theApp.m_activeWnd.FocusWnd(), cr);
-					m_ToolTipPoint = cr.CenterPoint();
-				}
-				m_ToolTipPoint.Offset(-15, 15);
-				m_pTypingToolTip->Show(m_ToolTipPoint);
-
-				//If they don't type anything for 2 seconds stop looking
-				SetTimer(STOP_LOOKING_FOR_KEYBOARD, 20000, NULL);
-
-				MonitorKeyboardChanges(m_hWnd, WM_FOCUS_CHANGED+1);
-				SetCaptureKeys(true);
-			}
-		}
-	}
-	else if(theApp.m_pPosOne && wParam == theApp.m_pPosOne->m_Atom)
-	{
-		DoFirstTenPositionsPaste(0);
-	}
-	else if(theApp.m_pPosTwo && wParam == theApp.m_pPosTwo->m_Atom)
-	{
-		DoFirstTenPositionsPaste(1);
-	}
-	else if(theApp.m_pPosThree && wParam == theApp.m_pPosThree->m_Atom)
-	{
-		DoFirstTenPositionsPaste(2);
-	}
-	else if(theApp.m_pPosFour && wParam == theApp.m_pPosFour->m_Atom)
-	{
-		DoFirstTenPositionsPaste(3);
-	}
-	else if(theApp.m_pPosFive && wParam == theApp.m_pPosFive->m_Atom)
-	{
-		DoFirstTenPositionsPaste(4);
-	}
-	else if(theApp.m_pPosSix && wParam == theApp.m_pPosSix->m_Atom)
-	{
-		DoFirstTenPositionsPaste(5);
-	}
-	else if(theApp.m_pPosSeven && wParam == theApp.m_pPosSeven->m_Atom)
-	{
-		DoFirstTenPositionsPaste(6);
-	}
-	else if(theApp.m_pPosEight && wParam == theApp.m_pPosEight->m_Atom)
-	{
-		DoFirstTenPositionsPaste(7);
-	}
-	else if(theApp.m_pPosNine && wParam == theApp.m_pPosNine->m_Atom)
-	{
-		DoFirstTenPositionsPaste(8);
-	}
-	else if(theApp.m_pPosTen && wParam == theApp.m_pPosTen->m_Atom)
-	{
-		DoFirstTenPositionsPaste(9);
-	}
-	else if(theApp.m_pCopyBuffer1 && wParam == theApp.m_pCopyBuffer1->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(0);
-	}
-	else if(theApp.m_pPasteBuffer1 && wParam == theApp.m_pPasteBuffer1->m_Atom)
-	{
-		theApp.m_CopyBuffer.PastCopyBuffer(0);
-	}
-	else if(theApp.m_pCutBuffer1 && wParam == theApp.m_pCutBuffer1->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(0, true);
-	}
-	else if(theApp.m_pCopyBuffer2 && wParam == theApp.m_pCopyBuffer2->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(1);
-	}
-	else if(theApp.m_pPasteBuffer2 && wParam == theApp.m_pPasteBuffer2->m_Atom)
-	{
-		theApp.m_CopyBuffer.PastCopyBuffer(1);
-	}
-	else if(theApp.m_pCutBuffer2 && wParam == theApp.m_pCutBuffer2->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(1, true);
-	}
-	else if(theApp.m_pCopyBuffer3 && wParam == theApp.m_pCopyBuffer3->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(2);
-	}
-	else if(theApp.m_pPasteBuffer3 && wParam == theApp.m_pPasteBuffer3->m_Atom)
-	{	
-		theApp.m_CopyBuffer.PastCopyBuffer(2);
-	}
-	else if(theApp.m_pCutBuffer3 && wParam == theApp.m_pCutBuffer3->m_Atom)
-	{
-		theApp.m_CopyBuffer.StartCopy(2, true);
-	}
-
-	return TRUE;
-}
-
-void CMainFrame::DoFirstTenPositionsPaste(int nPos)
-{
-	try
-	{	
-		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID, bIsGroup, lDate FROM Main ")
-							_T("WHERE ((bIsGroup = 1 AND lParentID = -1) OR bIsGroup = 0) ")
-							_T("ORDER BY bIsGroup ASC, lDate DESC ")
-							_T("LIMIT 1 OFFSET %d"), nPos);
-
-		if(q.eof() == false)
-		{
-			if(q.getIntField(_T("bIsGroup")) == FALSE)
-			{	
-				//Don't move these to the top
-				BOOL bItWas = g_Opt.m_bUpdateTimeOnPaste;
-				g_Opt.m_bUpdateTimeOnPaste = FALSE;
-
-				CProcessPaste paste;
-				paste.GetClipIDs().Add(q.getIntField(_T("lID")));
-				paste.m_bActivateTarget = false;
-				paste.m_bSendPaste = g_Opt.m_bSendPasteOnFirstTenHotKeys ? true : false;
-				paste.DoPaste();
-				theApp.OnPasteCompleted();
-
-				g_Opt.m_bUpdateTimeOnPaste = bItWas;
-			}
-		}
-	}
-	CATCH_SQLITE_EXCEPTION
-}
-
-void CMainFrame::DoDittoCopyBufferPaste(int nCopyBuffer)
-{
-	try
-	{	
-		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID FROM Main WHERE CopyBuffer = %d"), nCopyBuffer);
-
-		if(q.eof() == false)
-		{	
-			//Don't move these to the top
-			BOOL bItWas = g_Opt.m_bUpdateTimeOnPaste;
-			g_Opt.m_bUpdateTimeOnPaste = FALSE;
-
-			CProcessPaste paste;
-			paste.GetClipIDs().Add(q.getIntField(_T("lID")));
-			paste.m_bActivateTarget = false;
-			paste.DoPaste();
-			theApp.OnPasteCompleted();
-
-			g_Opt.m_bUpdateTimeOnPaste = bItWas;
-		}
-	}
-	CATCH_SQLITE_EXCEPTION
-}
-
-void CMainFrame::OnTimer(UINT nIDEvent) 
-{
-	switch(nIDEvent)
-	{
-	case HIDE_ICON_TIMER:
-		{
-			m_TrayIcon.HideIcon();
-			KillTimer(nIDEvent);
-			break;
-		}
-	case CLOSE_WINDOW_TIMER:
-		{
-			m_quickPaste.CloseQPasteWnd();
-			break;
-		}
-	case REMOVE_OLD_ENTRIES_TIMER:
-		{
-			if(m_deletingEntries == false)
-			{
-				AfxBeginThread(RemoveDeletedItemsThread, this);
-			}
-			break;
-		}
-	case CHECK_FOR_UPDATE:
-		{
-			KillTimer(CHECK_FOR_UPDATE);
-
-			CInternetUpdate Update;
-			if(Update.CheckForUpdate(NULL, TRUE, FALSE))
-			{
-				PostMessage(WM_CLOSE, 0, 0);
-			}
-			else
-			{
-				SetTimer(CHECK_FOR_UPDATE, ONE_MINUTE*60*24, NULL);
-			}
-			break;
-		}
-	case CLOSE_APP:
-		{
-			PostMessage(WM_CLOSE, 0, 0);
-			KillTimer(CLOSE_APP);
-			
-			break;
-		}
-	case STOP_MONITORING_KEYBOARD_TIMER:
-		{
-			StopLookingForKeystrokes(false);
-			if(m_csKeyboardPaste.IsEmpty() == FALSE)
-			{
-				if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
-				{
-					PasteQuickPasteEntry(m_csKeyboardPaste);
-				}
-				else
-				{
-					SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
-				}
-
-				StopLookingForKeystrokes(true);
-			}
-						
-			break;
-		}
-	case STOP_LOOKING_FOR_KEYBOARD:
-		{
-			if(theApp.m_QuickPasteMode == CCP_MainApp::ADDING_QUICK_PASTE)
-			{
-				SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
-			}
-
-			//They didn't type anything within 2 seconds stop looking
-			StopLookingForKeystrokes(true);
-
-			break;
-		}
-	case REMOVE_OLD_REMOTE_COPIES:
-		AfxBeginThread(CMainFrame::RemoteOldRemoteFilesThread, NULL);
-		break;
-
-	case KEY_STATE_MODIFIERS:
-		m_keyModifiersTimerCount++;
-		if(m_keyStateModifiers != 0)
-		{
-			BYTE keyState = GetKeyStateModifiers();
-			//Have they release the key state modifiers yet(ctrl, shift, alt)
-			if((m_keyStateModifiers & keyState) == 0)
-			{
-				KillTimer(KEY_STATE_MODIFIERS);
-				long waitTime = (long)(GetTickCount() - m_startKeyStateTime);
-
-				if(m_bMovedSelectionMoveKeyState || m_keyModifiersTimerCount > g_Opt.GetKeyStateWaitTimerCount())
-				{
-					Log(StrF(_T("Timer KEY_STATE_MODIFIERS timeout count hit(%d), count (%d), time (%d), Move Selection from Modifer (%d) sending paste"), g_Opt.GetKeyStateWaitTimerCount(), m_keyModifiersTimerCount, waitTime, m_bMovedSelectionMoveKeyState));
-					m_quickPaste.OnKeyStateUp();
-				}				
-				else
-				{
-					Log(StrF(_T("Timer KEY_STATE_MODIFIERS count NOT hit(%d), count (%d) time (%d)"), g_Opt.GetKeyStateWaitTimerCount(), m_keyModifiersTimerCount, waitTime));
-					m_quickPaste.SetKeyModiferState(false);
-				}
-
-				m_keyStateModifiers = 0;
-				m_keyModifiersTimerCount = 0;
-				m_bMovedSelectionMoveKeyState = 0;
-			}
-		}
-		else
-		{
-			KillTimer(KEY_STATE_MODIFIERS);
-		}
-		break;
-	case ACTIVE_WINDOW_TIMER:
-		if(m_quickPaste.IsWindowVisibleEx())
-		{
-			theApp.m_activeWnd.TrackActiveWnd(NULL);
-		}
-		break;
-
-	case FOCUS_CHANGED_TIMER:
-		KillTimer(FOCUS_CHANGED_TIMER);
-		//Log(StrF(_T("Focus Timer %d"), m_tempFocusWnd));
-		theApp.m_activeWnd.TrackActiveWnd(m_tempFocusWnd);
-		break;
-	}
-
-	CFrameWnd::OnTimer(nIDEvent);
-}
-
-void CMainFrame::StopLookingForKeystrokes(bool bInitAppVaribles)
-{
-	StopMonitoringKeyboardChanges();
-	SetCaptureKeys(false);
-	
-	KillTimer(STOP_MONITORING_KEYBOARD_TIMER);
-	KillTimer(STOP_LOOKING_FOR_KEYBOARD);
-
-	if(bInitAppVaribles)
-	{
-		theApp.m_QuickPasteMode = CCP_MainApp::NONE_QUICK_PASTE;
-
-		m_csKeyboardPaste.Empty();
-
-		delete theApp.m_pQuickPasteClip;
-		theApp.m_pQuickPasteClip = NULL;
-
-		m_pTypingToolTip->Hide();
-		m_pTypingToolTip->DestroyWindow();
-	}	
-}
-
-LRESULT CMainFrame::OnShowTrayIcon(WPARAM wParam, LPARAM lParam)
-{
-	if(lParam)
-	{
-		if(!m_TrayIcon.Visible())
-		{
-			KillTimer(HIDE_ICON_TIMER);
-			SetTimer(HIDE_ICON_TIMER, 40000, 0);
-		}
-	}
-
-	if(wParam)
-		m_TrayIcon.ShowIcon();
-	else 
-		m_TrayIcon.HideIcon();
-
-	return TRUE;
-}
-
-void CMainFrame::OnFirstShowquickpaste() 
-{
-	m_quickPaste.ShowQPasteWnd(this, true, false, FALSE);
-}
-
-void CMainFrame::OnFirstToggleConnectCV()
-{
-	theApp.ToggleConnectCV();
-}
-
-void CMainFrame::OnUpdateFirstToggleConnectCV(CCmdUI* pCmdUI) 
-{
-	theApp.UpdateMenuConnectCV( pCmdUI->m_pMenu, ID_FIRST_TOGGLECONNECTCV );
-}
-
-LRESULT CMainFrame::OnCopyProperties(WPARAM wParam, LPARAM lParam)
-{
-	long lID = (long)wParam;
-
-	if(lID > 0)
-	{
-		bool bOldState = theApp.EnableCbCopy(false);
-
-		CCopyProperties props(lID, this);
-		props.SetHideOnKillFocus(true);
-		props.DoModal();
-
-		theApp.EnableCbCopy( bOldState );
-	}
-
-	return TRUE;
-}
-
-LRESULT CMainFrame::OnShutDown(WPARAM wParam, LPARAM lParam)
-{
-	SetTimer(CLOSE_APP, 100, NULL);
-
-	return TRUE;
-}
-
-LRESULT CMainFrame::OnClipboardCopied(WPARAM wParam, LPARAM lParam)
-{
-	Log(_T("Start of function OnClipboardCopied"));
-	// if the delay is undesirable, this could be altered to save one at a time,
-	//  allowing the processing of other messages between saving clips.
-	theApp.SaveCopyClips();
-
-	Log(_T("End of function OnClipboardCopied"));
-	return TRUE;
-}
-
-BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
-{
-	// target before mouse messages change the focus
-	if( theApp.m_bShowingQuickPaste &&
-		WM_MOUSEFIRST <= pMsg->message && pMsg->message <= WM_MOUSELAST )
-	{	
-		if(g_Opt.m_bUseHookDllForFocus == false)
-		{
-			theApp.m_activeWnd.TrackActiveWnd(NULL);
-		}
-	}
-
-	return CFrameWnd::PreTranslateMessage(pMsg);
-}
-
-void CMainFrame::OnClose()
-{	
-	CloseAllOpenDialogs();
-
-	if(m_pEditFrameWnd)
-	{
-		if(m_pEditFrameWnd->CloseAll() == false)
-			return;
-	}
-
-	theApp.BeforeMainClose();
-	CFrameWnd::OnClose();
-}
-
-bool CMainFrame::CloseAllOpenDialogs()
-{
-	bool bRet = false;
-	DWORD dwordProcessId;
-	DWORD dwordChildWindowProcessId;
-	GetWindowThreadProcessId(this->m_hWnd, &dwordProcessId);
-	ASSERT(dwordProcessId);
-
-	CWnd *pTempWnd = GetDesktopWindow()->GetWindow(GW_CHILD);
-	while((pTempWnd = pTempWnd->GetWindow(GW_HWNDNEXT)) != NULL)
-	{
-		if(pTempWnd->GetSafeHwnd() == NULL)
-			break;
-
-		GetWindowThreadProcessId(pTempWnd->GetSafeHwnd(), &dwordChildWindowProcessId);
-		if(dwordChildWindowProcessId == dwordProcessId)
-		{
-			TCHAR szTemp[100];
-			GetClassName(pTempWnd->GetSafeHwnd(), szTemp, 100);
-
-			// #32770 is class name for dialogs so don't process the message if it is a dialog
-			if(STRCMP(szTemp, _T("#32770")) == 0)
-			{
-				pTempWnd->SendMessage(WM_CLOSE, 0, 0);
-				bRet = true;
-			}
-		}
-	}
-
-	MSG msg;
-	while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
-	{
-		TranslateMessage(&msg);
-		DispatchMessage(&msg);
-	}
-
-	return bRet;
-}
-
-LRESULT CMainFrame::OnAddToDatabaseFromSocket(WPARAM wParam, LPARAM lParam)
-{
-	LogSendRecieveInfo("---------Start of OnAddToDatabaseFromSocket");
-	
-	CProcessPaste paste;
-	CClipList *pClipList = (CClipList*)wParam;
-	if(pClipList == NULL)
-	{
-		LogSendRecieveInfo("---------ERROR pClipList == NULL");
-		return FALSE;
-	}
-	
-	BOOL bSetToClipBoard = (BOOL)lParam;
-
-	if(bSetToClipBoard)
-	{
-		LogSendRecieveInfo("---------Start of Set to ClipBoard");
-
-		CClip *pClip = pClipList->GetTail();
-		if(pClip)
-		{
-			CClip NewClip;
-			NewClip = *pClip;
-
-			LogSendRecieveInfo("---------After =");
-
-			//Don't send the paste just load it into memory
-			paste.m_bSendPaste = false;
-			paste.m_pOle->PutFormatOnClipboard(&NewClip.m_Formats);
-			paste.m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
-
-			LogSendRecieveInfo("---------After LoadFormats");
-		}
-		else
-		{
-			LogSendRecieveInfo("---------GetTail returned NULL");
-
-		}
-
-		LogSendRecieveInfo("---------Start of Set to ClipBoard");
-	}
-
-	pClipList->AddToDB(true);
-
-	LogSendRecieveInfo("---------After AddToDB");
-
-	CClip *pClip = pClipList->GetTail();
-	if(pClip)
-	{
-		theApp.m_FocusID = pClip->m_ID;
-
-		//Wait till after we add the clip to the db before we call DoPaste
-		if(bSetToClipBoard)
-		{
-			LogSendRecieveInfo(StrF(_T("---------Setting clip id: %d on ole clipboard"), pClip->m_ID));
-			paste.GetClipIDs().Add(pClip->m_ID);
-			paste.DoPaste();
-		}
-	}
-
-	theApp.RefreshView();
-
-	delete pClipList;
-	pClipList = NULL;
-
-	LogSendRecieveInfo("---------End of OnAddToDatabaseFromSocket");
-
-	return TRUE;
-}
-
-LRESULT CMainFrame::OnErrorOnSendRecieve(WPARAM wParam, LPARAM lParam)
-{
-	CString csNewText = (TCHAR*)wParam;
-
-	ShowErrorMessage(_T("Ditto - Send/Receive Error"), csNewText);
-
-	return TRUE;
-}
-
-LRESULT CMainFrame::OnKeyBoardChanged(WPARAM wParam, LPARAM lParam)
-{
-	if(wParam == VK_ESCAPE)
-	{
-		StopLookingForKeystrokes(true);
-	}
-	else if(wParam == VK_RETURN)
-	{
-		StopLookingForKeystrokes(false);
-		if(m_csKeyboardPaste.IsEmpty() == FALSE)
-		{
-			if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
-			{
-				PasteQuickPasteEntry(m_csKeyboardPaste);
-			}
-			else
-			{
-				SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
-			}
-		}
-		StopLookingForKeystrokes(true);
-	}
-	else if((wParam >= 32 && wParam <= 96) || wParam == VK_BACK)
-	{
-		KillTimer(STOP_LOOKING_FOR_KEYBOARD);
-		KillTimer(STOP_MONITORING_KEYBOARD_TIMER);
-
-		bool bContinue = true;
-
-		if(wParam == VK_BACK)     
-		{
-			m_csKeyboardPaste = m_csKeyboardPaste.Left(m_csKeyboardPaste.GetLength()-1);
-		}
-		else
-		{
-			CString cs((char)wParam);
-			m_csKeyboardPaste += cs;
-
-			if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
-			{
-				try
-				{
-					int nCount = theApp.m_db.execScalarEx(_T("SELECT COUNT(lID) FROM Main WHERE QuickPasteText LIKE \'%%%s%%\'"), m_csKeyboardPaste);
-					if(nCount == 1)
-					{
-						nCount = theApp.m_db.execScalarEx(_T("SELECT COUNT(lID) FROM Main WHERE QuickPasteText = \'%s\'"), m_csKeyboardPaste);
-						if(nCount == 1)
-						{
-							StopLookingForKeystrokes(false);
-							PasteQuickPasteEntry(m_csKeyboardPaste);
-							StopLookingForKeystrokes(true);
-							bContinue = false;
-						}
-					}
-				}
-				CATCH_SQLITE_EXCEPTION
-			}
-		}
-
-		if(bContinue)
-		{
-			m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle + "\n\n" + m_csKeyboardPaste);
-			m_pTypingToolTip->Show(m_ToolTipPoint);
-
-			SetTimer(STOP_MONITORING_KEYBOARD_TIMER, 10000, NULL);
-
-			Log(StrF(_T("OnKeyboard Changed - %d - %s"), wParam, m_csKeyboardPaste));
-		}
-	}
-	else
-	{
-		CString cs((char)wParam);
-		Log(StrF(_T("INVALID Key OnKeyboard Changed - %d - %s"), wParam, m_csKeyboardPaste));
-	}
-
-	return TRUE;
-}
-
-CString WndName(HWND hParent) 
-{
-	TCHAR cWindowText[200];
-
-	::GetWindowText(hParent, cWindowText, 100);
-
-	int nCount = 0;
-
-	while(STRLEN(cWindowText) <= 0)
-	{
-		hParent = ::GetParent(hParent);
-		if(hParent == NULL)
-			break;
-
-		::GetWindowText(hParent, cWindowText, 100);
-
-		nCount++;
-		if(nCount > 100)
-		{
-			Log(_T("GetTargetName reached maximum search depth of 100"));
-			break;
-		}
-	}
-
-	return cWindowText; 
-}
-
-LRESULT CMainFrame::OnFocusChanged(WPARAM wParam, LPARAM lParam)
-{
-	if(m_quickPaste.IsWindowVisibleEx())
-	{
-		HWND focus = (HWND)wParam;
-		static DWORD dLastDittoHasFocusTick = 0;
-
-		//Sometimes when we bring ditto up there will come a null focus 
-		//rite after that
-		if(focus == NULL && (GetTickCount() - dLastDittoHasFocusTick < 500))
-		{
-			Log(_T("NULL focus within 500 ticks of bringing up ditto"));
-			return TRUE;
-		}
-		else if(focus == NULL)
-		{
-			Log(_T("NULL focus received"));
-		}
-
-		if(theApp.m_activeWnd.DittoHasFocus())
-		{
-			dLastDittoHasFocusTick = GetTickCount();
-		}
-
-		//Log(StrF(_T("OnFocusChanged %d, title %s"), focus, WndName(focus)));
-		m_tempFocusWnd = focus;
-
-		KillTimer(FOCUS_CHANGED_TIMER);
-		SetTimer(FOCUS_CHANGED_TIMER, g_Opt.FocusChangedDelay(), NULL);
-	}
-
-	return TRUE;
-}
-
-void CMainFrame::OnFirstHelp() 
-{
-	CString csFile = CGetSetOptions::GetPath(PATH_HELP);
-	csFile += "DittoGettingStarted.htm";
-	CHyperLink::GotoURL(csFile, SW_SHOW);
-}
-
-LRESULT CMainFrame::OnCustomizeTrayMenu(WPARAM wParam, LPARAM lParam)
-{
-	CMenu *pMenu = (CMenu*)wParam;
-	if(pMenu)
-	{
-		theApp.m_Language.UpdateTrayIconRightClickMenu(pMenu);
-	}
-
-	return true;
-}
-
-bool CMainFrame::PasteQuickPasteEntry(CString csQuickPaste)
-{
-	Log(StrF(_T("PasteQuickPasteEntry -- %s"), csQuickPaste));
-
-	CString csTitle = theApp.m_Language.GetString("Named_Paste_Title", "Ditto - Named Paste");
-	bool bRet = false;
-	try
-	{
-		csQuickPaste.Replace(_T("'"), _T("''"));
-		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID FROM Main WHERE QuickPasteText = '%s'"), csQuickPaste);
-			
-		if(q.eof() == false)
-		{
-			CClip Clip;
-			if(Clip.LoadFormats(q.getIntField(_T("lID"))))
-			{
-				CProcessPaste paste;
-				paste.m_pOle->PutFormatOnClipboard(&Clip.m_Formats);
-				paste.m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
-					
-				if(paste.DoPaste())
-				{
-					bRet = TRUE;
-				}
-			}
-			else
-			{
-				CString csError = theApp.m_Language.GetString("Named_Paste_Error1", "Error loading data");
-				ShowErrorMessage(csTitle, StrF(_T("%s - id:%d"), csError, q.getIntField(_T("lID"))));
-			}
-		}
-		else
-		{
-			CString csError = theApp.m_Language.GetString("Named_Paste_Error2", "Error finding clip with QuickPaste Text of");
-			ShowErrorMessage(csTitle, StrF(_T("%s - '%s'"), csError, csQuickPaste));
-		}
-	}
-	catch (CppSQLite3Exception& e)
-	{
-		CString csError = theApp.m_Language.GetString("Named_Paste_Error3", "Exception finding the clip");
-		ShowErrorMessage(csTitle, StrF(_T("%s - '%s'  -  %s"), csError, csQuickPaste, e.errorMessage()));
-	}	
-
-	return bRet;
-}
-
-bool CMainFrame::SaveQuickPasteEntry(CString csQuickPaste, CClipList *pClipList)
-{
-	Log(StrF(_T("SaveQuickPasteEntry text = %s - recived copy = %d"), csQuickPaste, pClipList != NULL));
-	CString csTitle = theApp.m_Language.GetString("Named_Copy_Title", "Ditto - Named Copy");
-
-	bool bRet = false;
-
-	if(pClipList)
-	{
-		try
-		{
-			CClip *pClip = pClipList->GetHead();
-			pClip->m_csQuickPaste = csQuickPaste;
-			pClip->m_lDontAutoDelete = (long)CTime::GetCurrentTime().GetTime();
-
-			if(csQuickPaste.IsEmpty() == FALSE)
-			{
-				//Remove any other instances of this quick paste
-				csQuickPaste.Replace(_T("'"), _T("''"));
-				int nCount = theApp.m_db.execDMLEx(_T("UPDATE Main SET QuickPasteText = '' WHERE QuickPasteText = '%s';"), csQuickPaste);
-
-				if(nCount > 0)
-				{
-					Log(StrF(_T("Removed quick paste '%s', count = %d"), csQuickPaste, nCount));
-				}
-			}
-				
-			int count = pClipList->AddToDB(true);
-			if(count > 0)
-			{
-				long lID = pClipList->GetTail()->m_ID;
-				theApp.OnCopyCompleted(lID, count);
-
-				bRet = true;
-			}
-			else
-			{
-				CString csError = theApp.m_Language.GetString("Named_Copy_Error1", "Error saving Named Coy to Database");
-				ShowErrorMessage(csTitle, csError);
-			}
-		}
-		catch (CppSQLite3Exception& e)
-		{
-			Log(StrF(_T("SQLITE Exception %d - %s"), e.errorCode(), e.errorMessage()));
-			ASSERT(FALSE);
-
-			CString csError = theApp.m_Language.GetString("Named_Copy_Error2", "Exception saving Named Copy");
-			ShowErrorMessage(csTitle, StrF(_T("%s - %s"), csError, e.errorMessage()));
-		}	
-	}
-	else
-	{
-		CString csError = theApp.m_Language.GetString("Named_Copy_Error3", "Ditto did not receive a copy");
-		ShowErrorMessage(csTitle, csError);
-	}
-
-	return bRet;
-}
-
-void CMainFrame::ShowErrorMessage(CString csTitle, CString csMessage)
-{
-	Log(StrF(_T("ShowErrorMessage %s - %s"), csTitle, csMessage));
-
-	CToolTipEx *pErrorWnd = new CToolTipEx;
-	pErrorWnd->Create(this);
-	pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
-
-	CPoint pt;
-	CRect rcScreen;
-	GetMonitorRect(0, &rcScreen);
-	pt = rcScreen.BottomRight();
-
-	CRect cr = pErrorWnd->GetBoundsRect();
-
-	pt.x -= max(cr.Width()+50, 150);
-	pt.y -= max(cr.Height()+50, 150);
-
-	pErrorWnd->Show(pt);
-	pErrorWnd->HideWindowInXMilliSeconds(4000);
-}
-
-void CMainFrame::DeleteOldRemoteCopies(CString csDir)
-{
-	//must be deleting a sub folder in the musicgen directory
-	if(csDir.Find(_T("\\ReceivedFiles\\")) == -1)
-		return;
-
-	FIX_CSTRING_PATH(csDir);
-
-	CTime ctOld = CTime::GetCurrentTime();
-	CTime ctFile;
-	ctOld -= CTimeSpan(0, 0, 0, 1);
-
-	CFileFind Find;
-
-	CString csFindString;
-	csFindString.Format(_T("%s*.*"), csDir);
-
-	BOOL bFound = Find.FindFile(csFindString);
-	while(bFound)
-	{
-		bFound = Find.FindNextFile();
-
-		if(Find.IsDots())
-			continue;
-
-		if(Find.IsDirectory())
-		{
-			CString csDir(Find.GetFilePath());
-			DeleteOldRemoteCopies(csDir);
-			RemoveDirectory(csDir);
-		}
-
-		if(Find.GetLastAccessTime(ctFile))
-		{
-			//Delete the remote copied file if it has'nt been used for the last day
-			if(ctFile < ctOld)
-			{
-				DeleteFile(Find.GetFilePath());
-			}
-		}
-		else
-		{
-			DeleteFile(Find.GetFilePath());
-		}
-	}
-}
-
-UINT CMainFrame::RemoteOldRemoteFilesThread(LPVOID pParam)
-{
-	CString csDir = CGetSetOptions::GetPath(PATH_REMOTE_FILES);
-	if(FileExists(csDir))
-	{
-		DeleteOldRemoteCopies(csDir);
-	}
-
-	return TRUE;
-}
-void CMainFrame::OnFirstImport()
-{
-	theApp.ImportClips(theApp.m_MainhWnd);
-}
-
-void CMainFrame::ShowEditWnd(CClipIDs &Ids)
-{
-	CWaitCursor wait;
-
-	bool bCreatedWindow = false;
-	if(m_pEditFrameWnd == NULL)
-	{
-		m_pEditFrameWnd = new CEditFrameWnd;
-		m_pEditFrameWnd->LoadFrame(IDR_MAINFRAME);
-		bCreatedWindow = true;
-	}
-	if(m_pEditFrameWnd)
-	{		
-		m_pEditFrameWnd->EditIds(Ids);
-		m_pEditFrameWnd->SetNotifyWnd(m_hWnd);
-
-		if(bCreatedWindow)
-		{
-			CSize sz;
-			CPoint pt;
-			CGetSetOptions::GetEditWndSize(sz);
-			CGetSetOptions::GetEditWndPoint(pt);
-			CRect cr(pt, sz);
-			EnsureWindowVisible(&cr);
-			m_pEditFrameWnd->MoveWindow(cr);
-		}
-
-		m_pEditFrameWnd->ShowWindow(SW_SHOW);
-		m_pEditFrameWnd->SetForegroundWindow();
-		m_pEditFrameWnd->SetFocus();
-	}
-}
-
-LRESULT CMainFrame::OnEditWndClose(WPARAM wParam, LPARAM lParam)
-{
-	m_pEditFrameWnd = NULL;
-	return TRUE;
-}
-
-LRESULT CMainFrame::OnSetConnected(WPARAM wParam, LPARAM lParam)
-{
-	if(wParam)
-		theApp.SetConnectCV(true);
-	else if(lParam)
-		theApp.SetConnectCV(false);
-
-	return TRUE;
-}
-
-void CMainFrame::OnDestroy()
-{
-	CFrameWnd::OnDestroy();
-
-	if(m_pEditFrameWnd)
-	{
-		m_pEditFrameWnd->DestroyWindow();
-	}
-}
-
-void CMainFrame::OnFirstNewclip()
-{
-	CClipIDs IDs;
-	IDs.Add(-1);
-	theApp.EditItems(IDs, true);
+// MainFrm.cpp : implementation of the CMainFrame class
+//
+
+#include "stdafx.h"
+#include "CP_Main.h"
+#include "MainFrm.h"
+#include "afxole.h"
+#include "Misc.h"
+#include "CopyProperties.h"
+#include "InternetUpdate.h"
+#include ".\mainfrm.h"
+#include "focusdll\focusdll.h"
+#include "HyperLink.h"
+#include "tinyxml.h"
+#include "Path.h"
+#include "DittoCopyBuffer.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define	WM_ICON_NOTIFY			WM_APP+10
+#define MYWM_NOTIFYICON (WM_USER+1)
+
+
+bool CShowMainFrame::m_bShowingMainFrame = false;
+
+CShowMainFrame::CShowMainFrame() : 
+	m_bHideMainFrameOnExit(false), 
+	m_hWnd(NULL)
+{
+	if(m_bShowingMainFrame == false)
+	{
+		theApp.m_pMainFrame->m_TrayIcon.MaximiseFromTray(theApp.m_pMainFrame);
+		m_bHideMainFrameOnExit = true;
+		m_bShowingMainFrame = true;
+	}
+
+	m_hWnd = theApp.m_pMainFrame->GetSafeHwnd();
+}
+
+CShowMainFrame::~CShowMainFrame()
+{
+	if(m_bHideMainFrameOnExit && m_hWnd && ::IsWindow(m_hWnd))
+	{
+		theApp.m_pMainFrame->m_TrayIcon.MinimiseToTray(theApp.m_pMainFrame);
+		m_bShowingMainFrame = false;
+	}
+}
+
+
+IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
+
+BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
+	//{{AFX_MSG_MAP(CMainFrame)
+	ON_WM_CREATE()
+	ON_COMMAND(ID_FIRST_OPTION, OnFirstOption)
+	ON_COMMAND(ID_FIRST_EXIT, OnFirstExit)
+	ON_WM_TIMER()
+	ON_COMMAND(ID_FIRST_SHOWQUICKPASTE, OnFirstShowquickpaste)
+	ON_COMMAND(ID_FIRST_TOGGLECONNECTCV, OnFirstToggleConnectCV)
+	ON_UPDATE_COMMAND_UI(ID_FIRST_TOGGLECONNECTCV, OnUpdateFirstToggleConnectCV)
+	ON_COMMAND(ID_FIRST_HELP, OnFirstHelp)
+	//}}AFX_MSG_MAP
+	ON_MESSAGE(WM_HOTKEY, OnHotKey)
+	ON_MESSAGE(WM_SHOW_TRAY_ICON, OnShowTrayIcon)
+	ON_MESSAGE(WM_COPYPROPERTIES, OnCopyProperties)
+	ON_MESSAGE(WM_CLOSE_APP, OnShutDown)
+	ON_MESSAGE(WM_CLIPBOARD_COPIED, OnClipboardCopied)
+	ON_WM_CLOSE()
+	ON_MESSAGE(WM_ADD_TO_DATABASE_FROM_SOCKET, OnAddToDatabaseFromSocket)
+	ON_MESSAGE(WM_SEND_RECIEVE_ERROR, OnErrorOnSendRecieve)
+	ON_MESSAGE(WM_FOCUS_CHANGED, OnFocusChanged)
+	ON_MESSAGE(WM_FOCUS_CHANGED+1, OnKeyBoardChanged)
+	ON_MESSAGE(WM_CUSTOMIZE_TRAY_MENU, OnCustomizeTrayMenu)
+	ON_COMMAND(ID_FIRST_IMPORT, OnFirstImport)
+	ON_MESSAGE(WM_EDIT_WND_CLOSING, OnEditWndClose)
+	ON_WM_DESTROY()
+	ON_COMMAND(ID_FIRST_NEWCLIP, OnFirstNewclip)
+	ON_MESSAGE(WM_SET_CONNECTED, OnSetConnected)
+	ON_MESSAGE(MYWM_NOTIFYICON, OnTrayNotify)
+END_MESSAGE_MAP()
+
+static UINT indicators[] =
+{
+	ID_SEPARATOR,           // status line indicator
+	ID_INDICATOR_CAPS,
+	ID_INDICATOR_NUM,
+	ID_INDICATOR_SCRL,
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame construction/destruction
+
+CMainFrame::CMainFrame()
+{
+	m_pEditFrameWnd = NULL;
+	m_keyStateModifiers = 0;
+	m_startKeyStateTime = 0;
+	m_bMovedSelectionMoveKeyState = false;
+	m_keyModifiersTimerCount = 0;
+}
+
+CMainFrame::~CMainFrame()
+{
+	if(g_Opt.m_bUseHookDllForFocus)
+	{
+		Log(_T("Unloading focus dll for tracking focus changes"));
+		StopMonitoringFocusChanges();
+	}
+	
+	CGetSetOptions::SetMainHWND(0);
+}
+
+int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
+		return -1;
+
+	//Center the main window so message boxes are in the center
+		CRect rcScreen;
+	GetMonitorRect(0, &rcScreen);
+	CPoint cpCenter = rcScreen.CenterPoint();
+	MoveWindow(cpCenter.x,cpCenter.x, -2, -2);
+
+	//Then set the main window to transparent so it's never shown
+	//if it is shown then only the task tray icon
+	m_Transparency.SetTransparent(m_hWnd, 0, true);
+
+	SetWindowText(_T(""));
+
+	if(g_Opt.m_bUseHookDllForFocus)
+	{
+		Log(_T("Loading hook dll to track focus changes"));
+		MonitorFocusChanges(m_hWnd, WM_FOCUS_CHANGED);
+	}
+	else
+	{
+		Log(_T("Setting polling timer to track focus"));
+		SetTimer(ACTIVE_WINDOW_TIMER, g_Opt.FocusWndTimerTimeout(), 0);
+	}
+
+	SetWindowText(_T("Ditto"));
+
+	HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+
+	m_TrayIcon.Create(NULL,				// Let icon deal with its own messages
+						WM_ICON_NOTIFY,	// Icon notify message to use
+						_T("Ditto"),	// tooltip
+						hIcon,
+						IDR_MENU,			// ID of tray icon
+						FALSE,
+						_T(""),			// balloon tip
+						_T(""),			// balloon title
+						NULL,				// balloon icon
+						20 );
+
+	m_TrayIcon.SetSingleClickSelect(TRUE);
+	m_TrayIcon.MinimiseToTray(this);
+	m_TrayIcon.SetMenuDefaultItem(ID_FIRST_SHOWQUICKPASTE, FALSE);
+
+	//Only if in release
+	#ifndef _DEBUG
+	{
+		//If not showing the icon show it for 40 seconds so they can get to the option
+		//in case they can't remember the hot keys or something like that
+		if(!(CGetSetOptions::GetShowIconInSysTray()))
+			SetTimer(HIDE_ICON_TIMER, 40000, 0);
+	}
+	#endif
+
+	//don't check for updates if running from a U3 device
+	if(!g_Opt.m_bU3)
+	{
+		SetTimer(CHECK_FOR_UPDATE, ONE_MINUTE*5, 0);
+	}
+
+	SetTimer(CLOSE_WINDOW_TIMER, ONE_MINUTE*60, 0);
+	SetTimer(REMOVE_OLD_REMOTE_COPIES, ONE_DAY, 0);
+	SetTimer(REMOVE_OLD_ENTRIES_TIMER, 3000, 0);
+
+	m_ulCopyGap = CGetSetOptions::GetCopyGap();
+
+	theApp.AfterMainCreate();
+
+	m_thread.Start(this);
+
+	return 0;
+}
+
+BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+	if(cs.hMenu!=NULL)  
+	{
+		::DestroyMenu(cs.hMenu);      // delete menu if loaded
+		cs.hMenu = NULL;              // no menu for this window
+	}
+
+	if( !CFrameWnd::PreCreateWindow(cs) )
+		return FALSE;
+
+	WNDCLASS wc;	
+	wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
+	wc.lpfnWndProc = AfxWndProc;
+	wc.cbClsExtra = 0;
+	wc.cbWndExtra = 0;
+	wc.hInstance = AfxGetInstanceHandle();
+	wc.hIcon = NULL;
+	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+	wc.lpszMenuName =  NULL;
+	wc.lpszClassName = _T("Ditto");
+
+	// Create the QPaste window class
+	if (!AfxRegisterClass(&wc))
+		return FALSE;
+
+	cs.lpszClass = wc.lpszClassName;
+	
+	return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame diagnostics
+
+#ifdef _DEBUG
+void CMainFrame::AssertValid() const
+{
+	CFrameWnd::AssertValid();
+}
+
+void CMainFrame::Dump(CDumpContext& dc) const
+{
+	CFrameWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame message handlers
+
+
+void CMainFrame::OnFirstOption() 
+{
+	theApp.ShowOptionsDlg();
+}
+
+void CMainFrame::OnFirstExit() 
+{
+//	CloseAllOpenDialogs();
+	this->SendMessage(WM_CLOSE, 0, 0);
+}
+
+LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam)
+{
+	if(theApp.m_pDittoHotKey && wParam == theApp.m_pDittoHotKey->m_Atom)
+	{
+		//If they still have the shift/ctrl keys down
+		if(m_keyStateModifiers != 0 && m_quickPaste.IsWindowVisibleEx())
+		{
+			if(m_bMovedSelectionMoveKeyState == false)
+			{
+				Log(_T("Setting flag m_bMovedSelectionMoveKeyState to true, will paste when modifer keys are up"));
+			}
+
+			m_quickPaste.MoveSelection(true);
+			m_bMovedSelectionMoveKeyState = true;
+		}
+		else if(g_Opt.m_HideDittoOnHotKeyIfAlreadyShown && m_quickPaste.IsWindowVisibleEx())
+		{
+			m_quickPaste.HideQPasteWnd();
+		}
+		else
+		{
+			m_keyModifiersTimerCount = 0;
+			m_bMovedSelectionMoveKeyState = false;
+			m_startKeyStateTime = GetTickCount();
+			m_keyStateModifiers = GetKeyStateModifiers();
+			SetTimer(KEY_STATE_MODIFIERS, 50, NULL);
+			
+			theApp.m_activeWnd.TrackActiveWnd(NULL);
+			
+			m_quickPaste.ShowQPasteWnd(this, false, true, FALSE);
+		}		
+	}
+	else if(theApp.m_pNamedCopy && wParam == theApp.m_pNamedCopy->m_Atom)
+	{
+		if(g_Opt.m_bU3 == false)
+		{
+			if(theApp.m_QuickPasteMode == CCP_MainApp::NONE_QUICK_PASTE)
+			{
+				theApp.m_QuickPasteMode = CCP_MainApp::ADDING_QUICK_PASTE;
+
+				theApp.m_activeWnd.SendCopy();
+
+				m_pTypingToolTip = new CToolTipEx;
+				m_pTypingToolTip->Create(this);
+
+				csTypeToolTipTitle = theApp.m_Language.GetString("Named_Copy_Title", "Ditto - Named Copy");
+
+				m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle);
+
+				CRect rcScreen;
+				GetMonitorRect(0, &rcScreen);
+
+				m_ToolTipPoint = theApp.m_activeWnd.FocusCaret();
+				if(m_ToolTipPoint.x < 0 || m_ToolTipPoint.y < 0)
+				{
+					CRect cr;
+					::GetWindowRect(theApp.m_activeWnd.FocusWnd(), cr);
+					m_ToolTipPoint = cr.CenterPoint();
+				}
+				m_ToolTipPoint.Offset(-15, 15);
+				m_pTypingToolTip->Show(m_ToolTipPoint);
+
+				//If they don't type anything for 2 seconds stop looking
+				SetTimer(STOP_LOOKING_FOR_KEYBOARD, 20000, NULL);
+
+				MonitorKeyboardChanges(m_hWnd, WM_FOCUS_CHANGED+1);
+				SetCaptureKeys(true);
+			}
+		}
+	}
+	else if(theApp.m_pNamedPaste && wParam == theApp.m_pNamedPaste->m_Atom)
+	{
+		if(g_Opt.m_bU3 == false)
+		{
+			if(theApp.m_QuickPasteMode == CCP_MainApp::NONE_QUICK_PASTE)
+			{
+				theApp.m_QuickPasteMode = CCP_MainApp::PASTING_QUICK_PASTE;
+
+				m_pTypingToolTip = new CToolTipEx;
+				m_pTypingToolTip->Create(this);
+
+				csTypeToolTipTitle = theApp.m_Language.GetString("Named_Paste_Title", "Ditto - Named Paste");
+				m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle);
+
+				CRect rcScreen;
+
+				m_ToolTipPoint = theApp.m_activeWnd.FocusCaret();
+				if(m_ToolTipPoint.x < 0 || m_ToolTipPoint.y < 0)
+				{
+					CRect cr;
+					::GetWindowRect(theApp.m_activeWnd.FocusWnd(), cr);
+					m_ToolTipPoint = cr.CenterPoint();
+				}
+				m_ToolTipPoint.Offset(-15, 15);
+				m_pTypingToolTip->Show(m_ToolTipPoint);
+
+				//If they don't type anything for 2 seconds stop looking
+				SetTimer(STOP_LOOKING_FOR_KEYBOARD, 20000, NULL);
+
+				MonitorKeyboardChanges(m_hWnd, WM_FOCUS_CHANGED+1);
+				SetCaptureKeys(true);
+			}
+		}
+	}
+	else if(theApp.m_pPosOne && wParam == theApp.m_pPosOne->m_Atom)
+	{
+		DoFirstTenPositionsPaste(0);
+	}
+	else if(theApp.m_pPosTwo && wParam == theApp.m_pPosTwo->m_Atom)
+	{
+		DoFirstTenPositionsPaste(1);
+	}
+	else if(theApp.m_pPosThree && wParam == theApp.m_pPosThree->m_Atom)
+	{
+		DoFirstTenPositionsPaste(2);
+	}
+	else if(theApp.m_pPosFour && wParam == theApp.m_pPosFour->m_Atom)
+	{
+		DoFirstTenPositionsPaste(3);
+	}
+	else if(theApp.m_pPosFive && wParam == theApp.m_pPosFive->m_Atom)
+	{
+		DoFirstTenPositionsPaste(4);
+	}
+	else if(theApp.m_pPosSix && wParam == theApp.m_pPosSix->m_Atom)
+	{
+		DoFirstTenPositionsPaste(5);
+	}
+	else if(theApp.m_pPosSeven && wParam == theApp.m_pPosSeven->m_Atom)
+	{
+		DoFirstTenPositionsPaste(6);
+	}
+	else if(theApp.m_pPosEight && wParam == theApp.m_pPosEight->m_Atom)
+	{
+		DoFirstTenPositionsPaste(7);
+	}
+	else if(theApp.m_pPosNine && wParam == theApp.m_pPosNine->m_Atom)
+	{
+		DoFirstTenPositionsPaste(8);
+	}
+	else if(theApp.m_pPosTen && wParam == theApp.m_pPosTen->m_Atom)
+	{
+		DoFirstTenPositionsPaste(9);
+	}
+	else if(theApp.m_pCopyBuffer1 && wParam == theApp.m_pCopyBuffer1->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(0);
+	}
+	else if(theApp.m_pPasteBuffer1 && wParam == theApp.m_pPasteBuffer1->m_Atom)
+	{
+		theApp.m_CopyBuffer.PastCopyBuffer(0);
+	}
+	else if(theApp.m_pCutBuffer1 && wParam == theApp.m_pCutBuffer1->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(0, true);
+	}
+	else if(theApp.m_pCopyBuffer2 && wParam == theApp.m_pCopyBuffer2->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(1);
+	}
+	else if(theApp.m_pPasteBuffer2 && wParam == theApp.m_pPasteBuffer2->m_Atom)
+	{
+		theApp.m_CopyBuffer.PastCopyBuffer(1);
+	}
+	else if(theApp.m_pCutBuffer2 && wParam == theApp.m_pCutBuffer2->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(1, true);
+	}
+	else if(theApp.m_pCopyBuffer3 && wParam == theApp.m_pCopyBuffer3->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(2);
+	}
+	else if(theApp.m_pPasteBuffer3 && wParam == theApp.m_pPasteBuffer3->m_Atom)
+	{	
+		theApp.m_CopyBuffer.PastCopyBuffer(2);
+	}
+	else if(theApp.m_pCutBuffer3 && wParam == theApp.m_pCutBuffer3->m_Atom)
+	{
+		theApp.m_CopyBuffer.StartCopy(2, true);
+	}
+
+	return TRUE;
+}
+
+void CMainFrame::DoFirstTenPositionsPaste(int nPos)
+{
+	try
+	{	
+		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID, bIsGroup, lDate FROM Main ")
+							_T("WHERE ((bIsGroup = 1 AND lParentID = -1) OR bIsGroup = 0) ")
+							_T("ORDER BY bIsGroup ASC, lDate DESC ")
+							_T("LIMIT 1 OFFSET %d"), nPos);
+
+		if(q.eof() == false)
+		{
+			if(q.getIntField(_T("bIsGroup")) == FALSE)
+			{	
+				//Don't move these to the top
+				BOOL bItWas = g_Opt.m_bUpdateTimeOnPaste;
+				g_Opt.m_bUpdateTimeOnPaste = FALSE;
+
+				CProcessPaste paste;
+				paste.GetClipIDs().Add(q.getIntField(_T("lID")));
+				paste.m_bActivateTarget = false;
+				paste.m_bSendPaste = g_Opt.m_bSendPasteOnFirstTenHotKeys ? true : false;
+				paste.DoPaste();
+				theApp.OnPasteCompleted();
+
+				g_Opt.m_bUpdateTimeOnPaste = bItWas;
+			}
+		}
+	}
+	CATCH_SQLITE_EXCEPTION
+}
+
+void CMainFrame::DoDittoCopyBufferPaste(int nCopyBuffer)
+{
+	try
+	{	
+		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID FROM Main WHERE CopyBuffer = %d"), nCopyBuffer);
+
+		if(q.eof() == false)
+		{	
+			//Don't move these to the top
+			BOOL bItWas = g_Opt.m_bUpdateTimeOnPaste;
+			g_Opt.m_bUpdateTimeOnPaste = FALSE;
+
+			CProcessPaste paste;
+			paste.GetClipIDs().Add(q.getIntField(_T("lID")));
+			paste.m_bActivateTarget = false;
+			paste.DoPaste();
+			theApp.OnPasteCompleted();
+
+			g_Opt.m_bUpdateTimeOnPaste = bItWas;
+		}
+	}
+	CATCH_SQLITE_EXCEPTION
+}
+
+void CMainFrame::OnTimer(UINT nIDEvent) 
+{
+	switch(nIDEvent)
+	{
+	case HIDE_ICON_TIMER:
+		{
+			m_TrayIcon.HideIcon();
+			KillTimer(nIDEvent);
+			break;
+		}
+	case CLOSE_WINDOW_TIMER:
+		{
+			m_quickPaste.CloseQPasteWnd();
+			break;
+		}
+	case REMOVE_OLD_ENTRIES_TIMER:
+		{
+			m_thread.FireDeleteEntries();
+			break;
+		}
+	case CHECK_FOR_UPDATE:
+		{
+			KillTimer(CHECK_FOR_UPDATE);
+
+			CInternetUpdate Update;
+			if(Update.CheckForUpdate(NULL, TRUE, FALSE))
+			{
+				PostMessage(WM_CLOSE, 0, 0);
+			}
+			else
+			{
+				SetTimer(CHECK_FOR_UPDATE, ONE_MINUTE*60*24, NULL);
+			}
+			break;
+		}
+	case CLOSE_APP:
+		{
+			PostMessage(WM_CLOSE, 0, 0);
+			KillTimer(CLOSE_APP);
+			
+			break;
+		}
+	case STOP_MONITORING_KEYBOARD_TIMER:
+		{
+			StopLookingForKeystrokes(false);
+			if(m_csKeyboardPaste.IsEmpty() == FALSE)
+			{
+				if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
+				{
+					PasteQuickPasteEntry(m_csKeyboardPaste);
+				}
+				else
+				{
+					SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
+				}
+
+				StopLookingForKeystrokes(true);
+			}
+						
+			break;
+		}
+	case STOP_LOOKING_FOR_KEYBOARD:
+		{
+			if(theApp.m_QuickPasteMode == CCP_MainApp::ADDING_QUICK_PASTE)
+			{
+				SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
+			}
+
+			//They didn't type anything within 2 seconds stop looking
+			StopLookingForKeystrokes(true);
+
+			break;
+		}
+	case REMOVE_OLD_REMOTE_COPIES:
+		AfxBeginThread(CMainFrame::RemoteOldRemoteFilesThread, NULL);
+		break;
+
+	case KEY_STATE_MODIFIERS:
+		m_keyModifiersTimerCount++;
+		if(m_keyStateModifiers != 0)
+		{
+			BYTE keyState = GetKeyStateModifiers();
+			//Have they release the key state modifiers yet(ctrl, shift, alt)
+			if((m_keyStateModifiers & keyState) == 0)
+			{
+				KillTimer(KEY_STATE_MODIFIERS);
+				long waitTime = (long)(GetTickCount() - m_startKeyStateTime);
+
+				if(m_bMovedSelectionMoveKeyState || m_keyModifiersTimerCount > g_Opt.GetKeyStateWaitTimerCount())
+				{
+					Log(StrF(_T("Timer KEY_STATE_MODIFIERS timeout count hit(%d), count (%d), time (%d), Move Selection from Modifer (%d) sending paste"), g_Opt.GetKeyStateWaitTimerCount(), m_keyModifiersTimerCount, waitTime, m_bMovedSelectionMoveKeyState));
+					m_quickPaste.OnKeyStateUp();
+				}				
+				else
+				{
+					Log(StrF(_T("Timer KEY_STATE_MODIFIERS count NOT hit(%d), count (%d) time (%d)"), g_Opt.GetKeyStateWaitTimerCount(), m_keyModifiersTimerCount, waitTime));
+					m_quickPaste.SetKeyModiferState(false);
+				}
+
+				m_keyStateModifiers = 0;
+				m_keyModifiersTimerCount = 0;
+				m_bMovedSelectionMoveKeyState = 0;
+			}
+		}
+		else
+		{
+			KillTimer(KEY_STATE_MODIFIERS);
+		}
+		break;
+	case ACTIVE_WINDOW_TIMER:
+		if(m_quickPaste.IsWindowVisibleEx())
+		{
+			theApp.m_activeWnd.TrackActiveWnd(NULL);
+		}
+		break;
+
+	case FOCUS_CHANGED_TIMER:
+		KillTimer(FOCUS_CHANGED_TIMER);
+		//Log(StrF(_T("Focus Timer %d"), m_tempFocusWnd));
+		theApp.m_activeWnd.TrackActiveWnd(m_tempFocusWnd);
+		break;
+	}
+
+	CFrameWnd::OnTimer(nIDEvent);
+}
+
+void CMainFrame::StopLookingForKeystrokes(bool bInitAppVaribles)
+{
+	StopMonitoringKeyboardChanges();
+	SetCaptureKeys(false);
+	
+	KillTimer(STOP_MONITORING_KEYBOARD_TIMER);
+	KillTimer(STOP_LOOKING_FOR_KEYBOARD);
+
+	if(bInitAppVaribles)
+	{
+		theApp.m_QuickPasteMode = CCP_MainApp::NONE_QUICK_PASTE;
+
+		m_csKeyboardPaste.Empty();
+
+		delete theApp.m_pQuickPasteClip;
+		theApp.m_pQuickPasteClip = NULL;
+
+		m_pTypingToolTip->Hide();
+		m_pTypingToolTip->DestroyWindow();
+	}	
+}
+
+LRESULT CMainFrame::OnShowTrayIcon(WPARAM wParam, LPARAM lParam)
+{
+	if(lParam)
+	{
+		if(!m_TrayIcon.Visible())
+		{
+			KillTimer(HIDE_ICON_TIMER);
+			SetTimer(HIDE_ICON_TIMER, 40000, 0);
+		}
+	}
+
+	if(wParam)
+		m_TrayIcon.ShowIcon();
+	else 
+		m_TrayIcon.HideIcon();
+
+	return TRUE;
+}
+
+void CMainFrame::OnFirstShowquickpaste() 
+{
+	m_quickPaste.ShowQPasteWnd(this, true, false, FALSE);
+}
+
+void CMainFrame::OnFirstToggleConnectCV()
+{
+	theApp.ToggleConnectCV();
+}
+
+void CMainFrame::OnUpdateFirstToggleConnectCV(CCmdUI* pCmdUI) 
+{
+	theApp.UpdateMenuConnectCV( pCmdUI->m_pMenu, ID_FIRST_TOGGLECONNECTCV );
+}
+
+LRESULT CMainFrame::OnCopyProperties(WPARAM wParam, LPARAM lParam)
+{
+	long lID = (long)wParam;
+
+	if(lID > 0)
+	{
+		bool bOldState = theApp.EnableCbCopy(false);
+
+		CCopyProperties props(lID, this);
+		props.SetHideOnKillFocus(true);
+		props.DoModal();
+
+		theApp.EnableCbCopy( bOldState );
+	}
+
+	return TRUE;
+}
+
+LRESULT CMainFrame::OnShutDown(WPARAM wParam, LPARAM lParam)
+{
+	SetTimer(CLOSE_APP, 100, NULL);
+
+	return TRUE;
+}
+
+LRESULT CMainFrame::OnClipboardCopied(WPARAM wParam, LPARAM lParam)
+{
+	Log(_T("Start of function OnClipboardCopied"));
+	// if the delay is undesirable, this could be altered to save one at a time,
+	//  allowing the processing of other messages between saving clips.
+	theApp.SaveCopyClips();
+
+	Log(_T("End of function OnClipboardCopied"));
+	return TRUE;
+}
+
+BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
+{
+	// target before mouse messages change the focus
+	if( theApp.m_bShowingQuickPaste &&
+		WM_MOUSEFIRST <= pMsg->message && pMsg->message <= WM_MOUSELAST )
+	{	
+		if(g_Opt.m_bUseHookDllForFocus == false)
+		{
+			theApp.m_activeWnd.TrackActiveWnd(NULL);
+		}
+	}
+
+	return CFrameWnd::PreTranslateMessage(pMsg);
+}
+
+void CMainFrame::OnClose()
+{	
+	CloseAllOpenDialogs();
+
+	if(m_pEditFrameWnd)
+	{
+		if(m_pEditFrameWnd->CloseAll() == false)
+			return;
+	}
+
+	Log(_T("OnClose - before stop MainFrm thread"));
+	m_thread.Stop();
+	Log(_T("OnClose - after stop MainFrm thread"));
+
+	theApp.BeforeMainClose();
+
+	CFrameWnd::OnClose();
+}
+
+bool CMainFrame::CloseAllOpenDialogs()
+{
+	bool bRet = false;
+	DWORD dwordProcessId;
+	DWORD dwordChildWindowProcessId;
+	GetWindowThreadProcessId(this->m_hWnd, &dwordProcessId);
+	ASSERT(dwordProcessId);
+
+	CWnd *pTempWnd = GetDesktopWindow()->GetWindow(GW_CHILD);
+	while((pTempWnd = pTempWnd->GetWindow(GW_HWNDNEXT)) != NULL)
+	{
+		if(pTempWnd->GetSafeHwnd() == NULL)
+			break;
+
+		GetWindowThreadProcessId(pTempWnd->GetSafeHwnd(), &dwordChildWindowProcessId);
+		if(dwordChildWindowProcessId == dwordProcessId)
+		{
+			TCHAR szTemp[100];
+			GetClassName(pTempWnd->GetSafeHwnd(), szTemp, 100);
+
+			// #32770 is class name for dialogs so don't process the message if it is a dialog
+			if(STRCMP(szTemp, _T("#32770")) == 0)
+			{
+				pTempWnd->SendMessage(WM_CLOSE, 0, 0);
+				bRet = true;
+			}
+		}
+	}
+
+	MSG msg;
+	while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
+	{
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+
+	return bRet;
+}
+
+LRESULT CMainFrame::OnAddToDatabaseFromSocket(WPARAM wParam, LPARAM lParam)
+{
+	LogSendRecieveInfo("---------Start of OnAddToDatabaseFromSocket");
+	
+	CProcessPaste paste;
+	CClipList *pClipList = (CClipList*)wParam;
+	if(pClipList == NULL)
+	{
+		LogSendRecieveInfo("---------ERROR pClipList == NULL");
+		return FALSE;
+	}
+	
+	BOOL bSetToClipBoard = (BOOL)lParam;
+
+	if(bSetToClipBoard)
+	{
+		LogSendRecieveInfo("---------Start of Set to ClipBoard");
+
+		CClip *pClip = pClipList->GetTail();
+		if(pClip)
+		{
+			CClip NewClip;
+			NewClip = *pClip;
+
+			LogSendRecieveInfo("---------After =");
+
+			//Don't send the paste just load it into memory
+			paste.m_bSendPaste = false;
+			paste.m_pOle->PutFormatOnClipboard(&NewClip.m_Formats);
+			paste.m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
+
+			LogSendRecieveInfo("---------After LoadFormats");
+		}
+		else
+		{
+			LogSendRecieveInfo("---------GetTail returned NULL");
+
+		}
+
+		LogSendRecieveInfo("---------Start of Set to ClipBoard");
+	}
+
+	pClipList->AddToDB(true);
+
+	LogSendRecieveInfo("---------After AddToDB");
+
+	CClip *pClip = pClipList->GetTail();
+	if(pClip)
+	{
+		theApp.m_FocusID = pClip->m_ID;
+
+		//Wait till after we add the clip to the db before we call DoPaste
+		if(bSetToClipBoard)
+		{
+			LogSendRecieveInfo(StrF(_T("---------Setting clip id: %d on ole clipboard"), pClip->m_ID));
+			paste.GetClipIDs().Add(pClip->m_ID);
+			paste.DoPaste();
+		}
+	}
+
+	theApp.RefreshView();
+
+	delete pClipList;
+	pClipList = NULL;
+
+	LogSendRecieveInfo("---------End of OnAddToDatabaseFromSocket");
+
+	return TRUE;
+}
+
+LRESULT CMainFrame::OnErrorOnSendRecieve(WPARAM wParam, LPARAM lParam)
+{
+	CString csNewText = (TCHAR*)wParam;
+
+	ShowErrorMessage(_T("Ditto - Send/Receive Error"), csNewText);
+
+	return TRUE;
+}
+
+LRESULT CMainFrame::OnKeyBoardChanged(WPARAM wParam, LPARAM lParam)
+{
+	if(wParam == VK_ESCAPE)
+	{
+		StopLookingForKeystrokes(true);
+	}
+	else if(wParam == VK_RETURN)
+	{
+		StopLookingForKeystrokes(false);
+		if(m_csKeyboardPaste.IsEmpty() == FALSE)
+		{
+			if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
+			{
+				PasteQuickPasteEntry(m_csKeyboardPaste);
+			}
+			else
+			{
+				SaveQuickPasteEntry(m_csKeyboardPaste, theApp.m_pQuickPasteClip);
+			}
+		}
+		StopLookingForKeystrokes(true);
+	}
+	else if((wParam >= 32 && wParam <= 96) || wParam == VK_BACK)
+	{
+		KillTimer(STOP_LOOKING_FOR_KEYBOARD);
+		KillTimer(STOP_MONITORING_KEYBOARD_TIMER);
+
+		bool bContinue = true;
+
+		if(wParam == VK_BACK)     
+		{
+			m_csKeyboardPaste = m_csKeyboardPaste.Left(m_csKeyboardPaste.GetLength()-1);
+		}
+		else
+		{
+			CString cs((char)wParam);
+			m_csKeyboardPaste += cs;
+
+			if(theApp.m_QuickPasteMode == CCP_MainApp::PASTING_QUICK_PASTE)
+			{
+				try
+				{
+					int nCount = theApp.m_db.execScalarEx(_T("SELECT COUNT(lID) FROM Main WHERE QuickPasteText LIKE \'%%%s%%\'"), m_csKeyboardPaste);
+					if(nCount == 1)
+					{
+						nCount = theApp.m_db.execScalarEx(_T("SELECT COUNT(lID) FROM Main WHERE QuickPasteText = \'%s\'"), m_csKeyboardPaste);
+						if(nCount == 1)
+						{
+							StopLookingForKeystrokes(false);
+							PasteQuickPasteEntry(m_csKeyboardPaste);
+							StopLookingForKeystrokes(true);
+							bContinue = false;
+						}
+					}
+				}
+				CATCH_SQLITE_EXCEPTION
+			}
+		}
+
+		if(bContinue)
+		{
+			m_pTypingToolTip->SetToolTipText(csTypeToolTipTitle + "\n\n" + m_csKeyboardPaste);
+			m_pTypingToolTip->Show(m_ToolTipPoint);
+
+			SetTimer(STOP_MONITORING_KEYBOARD_TIMER, 10000, NULL);
+
+			Log(StrF(_T("OnKeyboard Changed - %d - %s"), wParam, m_csKeyboardPaste));
+		}
+	}
+	else
+	{
+		CString cs((char)wParam);
+		Log(StrF(_T("INVALID Key OnKeyboard Changed - %d - %s"), wParam, m_csKeyboardPaste));
+	}
+
+	return TRUE;
+}
+
+CString WndName(HWND hParent) 
+{
+	TCHAR cWindowText[200];
+
+	::GetWindowText(hParent, cWindowText, 100);
+
+	int nCount = 0;
+
+	while(STRLEN(cWindowText) <= 0)
+	{
+		hParent = ::GetParent(hParent);
+		if(hParent == NULL)
+			break;
+
+		::GetWindowText(hParent, cWindowText, 100);
+
+		nCount++;
+		if(nCount > 100)
+		{
+			Log(_T("GetTargetName reached maximum search depth of 100"));
+			break;
+		}
+	}
+
+	return cWindowText; 
+}
+
+LRESULT CMainFrame::OnFocusChanged(WPARAM wParam, LPARAM lParam)
+{
+	if(m_quickPaste.IsWindowVisibleEx())
+	{
+		HWND focus = (HWND)wParam;
+		static DWORD dLastDittoHasFocusTick = 0;
+
+		//Sometimes when we bring ditto up there will come a null focus 
+		//rite after that
+		if(focus == NULL && (GetTickCount() - dLastDittoHasFocusTick < 500))
+		{
+			Log(_T("NULL focus within 500 ticks of bringing up ditto"));
+			return TRUE;
+		}
+		else if(focus == NULL)
+		{
+			Log(_T("NULL focus received"));
+		}
+
+		if(theApp.m_activeWnd.DittoHasFocus())
+		{
+			dLastDittoHasFocusTick = GetTickCount();
+		}
+
+		//Log(StrF(_T("OnFocusChanged %d, title %s"), focus, WndName(focus)));
+		m_tempFocusWnd = focus;
+
+		KillTimer(FOCUS_CHANGED_TIMER);
+		SetTimer(FOCUS_CHANGED_TIMER, g_Opt.FocusChangedDelay(), NULL);
+	}
+
+	return TRUE;
+}
+
+void CMainFrame::OnFirstHelp() 
+{
+	CString csFile = CGetSetOptions::GetPath(PATH_HELP);
+	csFile += "DittoGettingStarted.htm";
+	CHyperLink::GotoURL(csFile, SW_SHOW);
+}
+
+LRESULT CMainFrame::OnCustomizeTrayMenu(WPARAM wParam, LPARAM lParam)
+{
+	CMenu *pMenu = (CMenu*)wParam;
+	if(pMenu)
+	{
+		theApp.m_Language.UpdateTrayIconRightClickMenu(pMenu);
+	}
+
+	return true;
+}
+
+bool CMainFrame::PasteQuickPasteEntry(CString csQuickPaste)
+{
+	Log(StrF(_T("PasteQuickPasteEntry -- %s"), csQuickPaste));
+
+	CString csTitle = theApp.m_Language.GetString("Named_Paste_Title", "Ditto - Named Paste");
+	bool bRet = false;
+	try
+	{
+		csQuickPaste.Replace(_T("'"), _T("''"));
+		CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID FROM Main WHERE QuickPasteText = '%s'"), csQuickPaste);
+			
+		if(q.eof() == false)
+		{
+			CClip Clip;
+			if(Clip.LoadFormats(q.getIntField(_T("lID"))))
+			{
+				CProcessPaste paste;
+				paste.m_pOle->PutFormatOnClipboard(&Clip.m_Formats);
+				paste.m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
+					
+				if(paste.DoPaste())
+				{
+					bRet = TRUE;
+				}
+			}
+			else
+			{
+				CString csError = theApp.m_Language.GetString("Named_Paste_Error1", "Error loading data");
+				ShowErrorMessage(csTitle, StrF(_T("%s - id:%d"), csError, q.getIntField(_T("lID"))));
+			}
+		}
+		else
+		{
+			CString csError = theApp.m_Language.GetString("Named_Paste_Error2", "Error finding clip with QuickPaste Text of");
+			ShowErrorMessage(csTitle, StrF(_T("%s - '%s'"), csError, csQuickPaste));
+		}
+	}
+	catch (CppSQLite3Exception& e)
+	{
+		CString csError = theApp.m_Language.GetString("Named_Paste_Error3", "Exception finding the clip");
+		ShowErrorMessage(csTitle, StrF(_T("%s - '%s'  -  %s"), csError, csQuickPaste, e.errorMessage()));
+	}	
+
+	return bRet;
+}
+
+bool CMainFrame::SaveQuickPasteEntry(CString csQuickPaste, CClipList *pClipList)
+{
+	Log(StrF(_T("SaveQuickPasteEntry text = %s - recived copy = %d"), csQuickPaste, pClipList != NULL));
+	CString csTitle = theApp.m_Language.GetString("Named_Copy_Title", "Ditto - Named Copy");
+
+	bool bRet = false;
+
+	if(pClipList)
+	{
+		try
+		{
+			CClip *pClip = pClipList->GetHead();
+			pClip->m_csQuickPaste = csQuickPaste;
+			pClip->m_lDontAutoDelete = (long)CTime::GetCurrentTime().GetTime();
+
+			if(csQuickPaste.IsEmpty() == FALSE)
+			{
+				//Remove any other instances of this quick paste
+				csQuickPaste.Replace(_T("'"), _T("''"));
+				int nCount = theApp.m_db.execDMLEx(_T("UPDATE Main SET QuickPasteText = '' WHERE QuickPasteText = '%s';"), csQuickPaste);
+
+				if(nCount > 0)
+				{
+					Log(StrF(_T("Removed quick paste '%s', count = %d"), csQuickPaste, nCount));
+				}
+			}
+				
+			int count = pClipList->AddToDB(true);
+			if(count > 0)
+			{
+				long lID = pClipList->GetTail()->m_ID;
+				theApp.OnCopyCompleted(lID, count);
+
+				bRet = true;
+			}
+			else
+			{
+				CString csError = theApp.m_Language.GetString("Named_Copy_Error1", "Error saving Named Coy to Database");
+				ShowErrorMessage(csTitle, csError);
+			}
+		}
+		catch (CppSQLite3Exception& e)
+		{
+			Log(StrF(_T("SQLITE Exception %d - %s"), e.errorCode(), e.errorMessage()));
+			ASSERT(FALSE);
+
+			CString csError = theApp.m_Language.GetString("Named_Copy_Error2", "Exception saving Named Copy");
+			ShowErrorMessage(csTitle, StrF(_T("%s - %s"), csError, e.errorMessage()));
+		}	
+	}
+	else
+	{
+		CString csError = theApp.m_Language.GetString("Named_Copy_Error3", "Ditto did not receive a copy");
+		ShowErrorMessage(csTitle, csError);
+	}
+
+	return bRet;
+}
+
+void CMainFrame::ShowErrorMessage(CString csTitle, CString csMessage)
+{
+	Log(StrF(_T("ShowErrorMessage %s - %s"), csTitle, csMessage));
+
+	CToolTipEx *pErrorWnd = new CToolTipEx;
+	pErrorWnd->Create(this);
+	pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
+
+	CPoint pt;
+	CRect rcScreen;
+	GetMonitorRect(0, &rcScreen);
+	pt = rcScreen.BottomRight();
+
+	CRect cr = pErrorWnd->GetBoundsRect();
+
+	pt.x -= max(cr.Width()+50, 150);
+	pt.y -= max(cr.Height()+50, 150);
+
+	pErrorWnd->Show(pt);
+	pErrorWnd->HideWindowInXMilliSeconds(4000);
+}
+
+void CMainFrame::DeleteOldRemoteCopies(CString csDir)
+{
+	//must be deleting a sub folder in the musicgen directory
+	if(csDir.Find(_T("\\ReceivedFiles\\")) == -1)
+		return;
+
+	FIX_CSTRING_PATH(csDir);
+
+	CTime ctOld = CTime::GetCurrentTime();
+	CTime ctFile;
+	ctOld -= CTimeSpan(0, 0, 0, 1);
+
+	CFileFind Find;
+
+	CString csFindString;
+	csFindString.Format(_T("%s*.*"), csDir);
+
+	BOOL bFound = Find.FindFile(csFindString);
+	while(bFound)
+	{
+		bFound = Find.FindNextFile();
+
+		if(Find.IsDots())
+			continue;
+
+		if(Find.IsDirectory())
+		{
+			CString csDir(Find.GetFilePath());
+			DeleteOldRemoteCopies(csDir);
+			RemoveDirectory(csDir);
+		}
+
+		if(Find.GetLastAccessTime(ctFile))
+		{
+			//Delete the remote copied file if it has'nt been used for the last day
+			if(ctFile < ctOld)
+			{
+				DeleteFile(Find.GetFilePath());
+			}
+		}
+		else
+		{
+			DeleteFile(Find.GetFilePath());
+		}
+	}
+}
+
+UINT CMainFrame::RemoteOldRemoteFilesThread(LPVOID pParam)
+{
+	CString csDir = CGetSetOptions::GetPath(PATH_REMOTE_FILES);
+	if(FileExists(csDir))
+	{
+		DeleteOldRemoteCopies(csDir);
+	}
+
+	return TRUE;
+}
+void CMainFrame::OnFirstImport()
+{
+	theApp.ImportClips(theApp.m_MainhWnd);
+}
+
+void CMainFrame::ShowEditWnd(CClipIDs &Ids)
+{
+	CWaitCursor wait;
+
+	bool bCreatedWindow = false;
+	if(m_pEditFrameWnd == NULL)
+	{
+		m_pEditFrameWnd = new CEditFrameWnd;
+		m_pEditFrameWnd->LoadFrame(IDR_MAINFRAME);
+		bCreatedWindow = true;
+	}
+	if(m_pEditFrameWnd)
+	{		
+		m_pEditFrameWnd->EditIds(Ids);
+		m_pEditFrameWnd->SetNotifyWnd(m_hWnd);
+
+		if(bCreatedWindow)
+		{
+			CSize sz;
+			CPoint pt;
+			CGetSetOptions::GetEditWndSize(sz);
+			CGetSetOptions::GetEditWndPoint(pt);
+			CRect cr(pt, sz);
+			EnsureWindowVisible(&cr);
+			m_pEditFrameWnd->MoveWindow(cr);
+		}
+
+		m_pEditFrameWnd->ShowWindow(SW_SHOW);
+		m_pEditFrameWnd->SetForegroundWindow();
+		m_pEditFrameWnd->SetFocus();
+	}
+}
+
+LRESULT CMainFrame::OnEditWndClose(WPARAM wParam, LPARAM lParam)
+{
+	m_pEditFrameWnd = NULL;
+	return TRUE;
+}
+
+LRESULT CMainFrame::OnSetConnected(WPARAM wParam, LPARAM lParam)
+{
+	if(wParam)
+		theApp.SetConnectCV(true);
+	else if(lParam)
+		theApp.SetConnectCV(false);
+
+	return TRUE;
+}
+
+void CMainFrame::OnDestroy()
+{
+	Shell_NotifyIcon(NIM_DELETE, &tnd);
+	m_TrayMenu.DestroyMenu();
+
+	CFrameWnd::OnDestroy();
+
+	if(m_pEditFrameWnd)
+	{
+		m_pEditFrameWnd->DestroyWindow();
+	}
+}
+
+void CMainFrame::OnFirstNewclip()
+{
+	CClipIDs IDs;
+	IDs.Add(-1);
+	theApp.EditItems(IDs, true);
+}
+
+LRESULT CMainFrame::OnTrayNotify(WPARAM wParam, LPARAM lParam)
+{
+	UINT uMsg = (UINT) lParam; 
+	switch (uMsg ) 
+	{ 
+	case WM_LBUTTONDBLCLK:
+		//this->ShowWindow(SW_SHOW);
+		m_TrayMenu.DestroyMenu();
+		this->OnClose();
+		break;
+	case WM_RBUTTONUP:
+		CPoint pt;	
+		GetCursorPos(&pt);
+		m_TrayMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,pt.x,pt.y,this);
+		break;
+	} 
+	return TRUE;
 }

+ 6 - 1
MainFrm.h

@@ -13,6 +13,7 @@
 #include "QuickPaste.h"
 #include "ToolTipEx.h"
 #include "EditFrameWnd.h"
+#include "MainFrmThread.h"
 
 
 #define CLOSE_WINDOW_TIMER				1	
@@ -72,7 +73,10 @@ public:
 	bool m_bMovedSelectionMoveKeyState;
 	short m_keyModifiersTimerCount;
 	HWND m_tempFocusWnd;
-	bool m_deletingEntries;
+	CMainFrmThread m_thread;
+
+	CMenu m_TrayMenu;
+	NOTIFYICONDATA tnd;
 
 	void DoDittoCopyBufferPaste(int nCopyBuffer);
 	void DoFirstTenPositionsPaste(int nPos);
@@ -122,6 +126,7 @@ public:
 	afx_msg void OnFirstImport();
 	afx_msg void OnDestroy();
 	afx_msg void OnFirstNewclip();
+	afx_msg LRESULT OnTrayNotify(WPARAM wParam, LPARAM lParam);
 };
 
 class CShowMainFrame

+ 73 - 0
MessagePumpThread.cpp

@@ -0,0 +1,73 @@
+#include "StdAfx.h"
+#include "MessagePumpThread.h"
+
+
+CMessagePumpThread::CMessagePumpThread(void)
+{
+}
+
+
+CMessagePumpThread::~CMessagePumpThread(void)
+{
+}
+
+UINT CMessagePumpThread::MessagePumpThread(void* thisptr) 
+{
+	CMessagePumpThread *threadClass = (CMessagePumpThread*)thisptr;
+	threadClass->RunMessagePump();
+	return 0;
+}
+
+void CMessagePumpThread::Start() 
+{
+	m_hEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	m_thread = _beginthreadex(NULL, 0, MessagePumpThread, this, 0, &m_threadID);
+	if (0 == m_thread)
+	{
+		throw "Could not create thread";
+	}
+
+	// now wait until the thread is up and really running
+	if (WAIT_OBJECT_0 != WaitForSingleObject(m_hEvt, 10000L))	// 10 seconds
+	{
+		throw "Timeout waiting for thread to start";
+	}
+}
+
+void CMessagePumpThread::Stop() 
+{
+	PostThreadMessage(m_threadID, WM_QUIT, 0, 0L);
+	if (WAIT_OBJECT_0 != WaitForSingleObject(m_hEvt, 10000L))
+	{
+		throw "Timeout waiting for thread to stop";
+	}
+};
+
+void CMessagePumpThread::PostMsg(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	PostThreadMessage(m_threadID, msg, wParam, lParam);
+}
+
+void CMessagePumpThread::RunMessagePump()
+{
+	MSG msg;
+
+	// create the message queue
+	PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
+
+	// we're far enough to let the creator know we're running
+	SetEvent(m_hEvt);
+
+	while(true)
+	{
+		BOOL bRet = GetMessage(&msg, NULL, 0, 0);
+		if (0 >= bRet) // just read the specs, it's a "MickeySoft BOOL" and can be TRUE, FALSE or -1 (right on)
+		{
+			SetEvent(m_hEvt);
+			break;	
+		}
+
+		TakeMsg(msg.message, msg.wParam, msg.lParam);
+	}
+}

+ 29 - 0
MessagePumpThread.h

@@ -0,0 +1,29 @@
+#pragma once
+
+class CMessagePumpThread
+{
+public:
+	CMessagePumpThread(void);
+	~CMessagePumpThread(void);
+
+	static unsigned int __stdcall MessagePumpThread(void* thisptr);
+
+protected:
+	virtual void TakeMsg(UINT msg, WPARAM wParam, LPARAM lParam)	{ return; }
+	void RunMessagePump();
+
+	UINT m_threadID;
+	uintptr_t m_thread;
+	HANDLE m_hEvt;
+
+public:
+	void Start();
+	void Stop(); 
+	void PostMsg(UINT msg, WPARAM wParam, LPARAM lParam);
+
+	UINT getThreadID() const { return m_threadID; }
+	uintptr_t getThread() const { return m_thread; }
+};
+
+
+

+ 78 - 64
QListCtrl.cpp

@@ -452,7 +452,7 @@ void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 				strSymbols.Delete(nFlag);
 		}
 		
-		DrawBitMap(nItem, rcText, pDC);
+		DrawBitMap(nItem, rcText, pDC, csText);
 
 		// draw the symbol box
 		if( strSymbols.GetLength() > 0 )
@@ -482,8 +482,10 @@ void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 			rcText.left += rectSym.Width() + 2;
 		}
 		
-		if(DrawText(nItem, rcText, pDC) == FALSE)
+		if(DrawRtfText(nItem, rcText, pDC) == FALSE)
+		{
 			pDC->DrawText(csText, rcText, DT_VCENTER|DT_EXPANDTABS|DT_NOPREFIX);
+		}
 		
         // Draw a focus rect around the item if necessary.
         if(bListHasFocus && (rItem.state & LVIS_FOCUSED))
@@ -529,32 +531,19 @@ void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 	}
 }
 
-BOOL CQListCtrl::DrawText(int nItem, CRect &crRect, CDC *pDC)
+BOOL CQListCtrl::DrawRtfText(int nItem, CRect &crRect, CDC *pDC)
 {
 	if(g_Opt.m_bDrawRTF == FALSE)
 		return FALSE;
 	
-	static CLIPFORMAT clFormat = GetFormatID(_T("Rich Text Format"));
-
 	BOOL bRet = FALSE;
 
-	long lDatabaseID = GetItemData(nItem);
-
-	CClipFormat* pThumbnail = &(m_RTFData[lDatabaseID]);
+	CClipFormat* pThumbnail = GetItem_CF_RTF_ClipFormat(nItem);
 	if(pThumbnail == NULL)
 		return FALSE;
 
-	//If it has not been read in
-	if(pThumbnail->m_cfType != clFormat)
-	{
-		pThumbnail->m_cfType = clFormat;
-
-		//Get the data from the database
-		GetClipData(nItem, *pThumbnail);
-	}
-
 	// if there's no data, then we're done.
-	if( pThumbnail->m_hgData == NULL )
+	if(pThumbnail->m_hgData == NULL)
 		return FALSE;
 
 	if(m_pFormatter == NULL)
@@ -586,59 +575,29 @@ BOOL CQListCtrl::DrawText(int nItem, CRect &crRect, CDC *pDC)
 // DrawBitMap loads a DIB from the DB, draws a crRect thumbnail of the image
 //  to pDC and caches that thumbnail as a DIB in m_ThumbNails[ ItemID ].
 // ALL items are cached in m_ThumbNails (those without images are cached with NULL m_hgData)
-BOOL CQListCtrl::DrawBitMap(int nItem, CRect &crRect, CDC *pDC)
+BOOL CQListCtrl::DrawBitMap(int nItem, CRect &crRect, CDC *pDC, const CString &csDescription)
 {
 	if(g_Opt.m_bDrawThumbnail == FALSE)
 		return FALSE;
-	
-	bool bFromDB = false;
-	long lDatabaseID = GetItemData(nItem);
-
-	CClipFormat* pThumbnail = &(m_ThumbNails[lDatabaseID]);
-	if(pThumbnail == NULL)
-		return FALSE;
 
-	//If it has not been read in
-	if(pThumbnail->m_cfType != CF_DIB)
+	CClipFormatQListCtrl *format = GetItem_CF_DIB_ClipFormat(nItem);
+	if(format != NULL)
 	{
-		pThumbnail->m_cfType = CF_DIB;
-
-		//Get the data from the database
-		GetClipData(nItem, *pThumbnail);
-		
-		//convert to a small bitmap
-		CBitmap Bitmap;
-		if( !CBitmapHelper::GetCBitmap(pThumbnail, pDC, &Bitmap, crRect.Height()) )
+		HGLOBAL smallImage = format->GetDib(pDC, crRect.Height());
+		if(smallImage != NULL)
 		{
-			Bitmap.DeleteObject();
-			// the data is useless, so free it.
-			pThumbnail->Free(); 
-			return FALSE;
+			//Will return the width of the bitmap in nWidth
+			int nWidth = 0;
+			if(CBitmapHelper::DrawDIB(pDC, smallImage, crRect.left, crRect.top, nWidth))
+			{
+				// adjust the rect so other information can be drawn next to the thumbnail
+				crRect.left += nWidth + 3;
+			}
 		}
-
-		// delete the large image data loaded from the db
-		pThumbnail->Free();
-		pThumbnail->m_cfType = CF_DIB;
-
-		//Convert the smaller bitmap back to a dib
-		HPALETTE hPal = NULL;
-		pThumbnail->m_hgData = CBitmapHelper::hBitmapToDIB( (HBITMAP)Bitmap, BI_RGB, hPal );
-
-		ASSERT( pThumbnail->m_autoDeleteData ); // the map owns the data.
-
-		Bitmap.DeleteObject();
 	}
-
-	// if there's no data, then we're done.
-	if( pThumbnail->m_hgData == NULL )
-		return TRUE;
-
-	//Will return the width of the bitmap in nWidth
-	int nWidth = 0;
-	if(CBitmapHelper::DrawDIB(pDC, pThumbnail->m_hgData, crRect.left, crRect.top, nWidth))
+	else if(csDescription.Find(_T("CF_DIB")) == 0)
 	{
-		// adjust the rect so other information can be drawn next to the thumbnail
-		crRect.left += nWidth + 3;
+		crRect.left += crRect.Height();
 	}
 
 	return TRUE;
@@ -1154,6 +1113,62 @@ DWORD CQListCtrl::GetItemData(int nItem)
 	return CListCtrl::GetItemData(nItem);
 }
 
+CClipFormatQListCtrl* CQListCtrl::GetItem_CF_DIB_ClipFormat(int nItem)
+{
+	CClipFormatQListCtrl *format = NULL;
+
+	CWnd* pParent=GetParent();
+	if(pParent && (pParent->GetSafeHwnd() != NULL))
+	{
+		LV_DISPINFO info;
+		memset(&info, 0, sizeof(info));
+		info.hdr.code = LVN_GETDISPINFO;
+		info.hdr.hwndFrom = GetSafeHwnd();
+		info.hdr.idFrom = GetDlgCtrlID();
+
+		info.item.iItem = nItem;
+		info.item.lParam = NULL;
+		info.item.mask = LVIF_CF_DIB;
+
+		pParent->SendMessage(WM_NOTIFY,(WPARAM)info.hdr.idFrom,(LPARAM)&info);
+
+		if(info.item.lParam != NULL)
+		{
+			format = (CClipFormatQListCtrl *)info.item.lParam;
+		}
+	}
+
+	return format;
+}
+
+CClipFormatQListCtrl* CQListCtrl::GetItem_CF_RTF_ClipFormat(int nItem)
+{
+	CClipFormatQListCtrl *format = NULL;
+
+	CWnd* pParent=GetParent();
+	if(pParent && (pParent->GetSafeHwnd() != NULL))
+	{
+		LV_DISPINFO info;
+		memset(&info, 0, sizeof(info));
+		info.hdr.code = LVN_GETDISPINFO;
+		info.hdr.hwndFrom = GetSafeHwnd();
+		info.hdr.idFrom = GetDlgCtrlID();
+
+		info.item.iItem = nItem;
+		info.item.lParam = NULL;
+		info.item.mask = LVIF_CF_RICHTEXT;
+
+		pParent->SendMessage(WM_NOTIFY, (WPARAM)info.hdr.idFrom, (LPARAM)&info);
+
+		if(info.item.lParam != NULL)
+		{
+			format = (CClipFormatQListCtrl *)info.item.lParam;
+		}
+	}
+
+	return format;
+}
+
 void CQListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
 {	
 	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
@@ -1309,8 +1324,7 @@ BOOL CQListCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESU
 
 BOOL CQListCtrl::OnItemDeleted(long lID)
 {
-	BOOL bRet = m_ThumbNails.RemoveKey(lID);
 	BOOL bRet2 = m_RTFData.RemoveKey(lID);
 
-	return (bRet || bRet2);
+	return (bRet2);
 }

+ 11 - 3
QListCtrl.h

@@ -10,6 +10,7 @@
 #include "ToolTipEx.h"
 #include "FormattedTextDraw.h"
 #include "sqlite/CppSQLite3.h"
+#include "ClipFormatQListCtrl.h"
 
 #define NM_SELECT					WM_USER+0x100
 #define NM_RIGHT					WM_USER+0x101
@@ -31,11 +32,15 @@
 #define NM_ITEM_DELETED				WM_USER+0x118
 #define NM_ALL_SELECTED				WM_USER+0x119
 #define NM_REFRESH_ROW				WM_USER+0x120
+#define NM_REFRESH_ROW_EXTRA_DATA	WM_USER+0x121
 
 #define COPY_BUFFER_HOT_KEY_1_ID	-100
 #define COPY_BUFFER_HOT_KEY_2_ID	-101
 #define COPY_BUFFER_HOT_KEY_3_ID	-102
 
+#define LVIF_CF_DIB 0x10000000
+#define LVIF_CF_RICHTEXT 0x10000000
+
 
 //#define NM_LIST_CUT			        WM_USER+0x111
 //#define NM_LIST_COPY		        WM_USER+0x112
@@ -50,6 +55,8 @@ public:
 	int cchTextMax; 
 };
 
+
+
 typedef CMap<long, long, CClipFormat, CClipFormat&> CMapIDtoCF;
 
 class CQListCtrl : public CListCtrl
@@ -102,6 +109,8 @@ public:
 	bool PutSelectedItemOnDittoCopyBuffer(long lBuffer);
 
 	DWORD GetItemData(int nItem);
+	CClipFormatQListCtrl* GetItem_CF_DIB_ClipFormat(int nItem);
+	CClipFormatQListCtrl* GetItem_CF_RTF_ClipFormat(int nItem);
 	void GetToolTipText(int nItem, CString &csText);
 
 	void SetShowTextForFirstTenHotKeys(BOOL bVal)	{ m_bShowTextForFirstTenHotKeys = bVal;	}
@@ -126,16 +135,15 @@ protected:
 	void LoadCopyOrCutToClipboard();
 	void SendSelection(ARRAY &arrItems);
 	BOOL GetClipData(int nItem, CClipFormat &Clip);
-	BOOL DrawBitMap(int nItem, CRect &crRect, CDC *pDC);
+	BOOL DrawBitMap(int nItem, CRect &crRect, CDC *pDC, const CString &csDescription);
 	void LoadDittoCopyBufferHotkeys();
 
-	BOOL DrawText(int nItem, CRect &crRect, CDC *pDC);
+	BOOL DrawRtfText(int nItem, CRect &crRect, CDC *pDC);
 		
 	WCHAR *m_pwchTip;
 	TCHAR *m_pchTip;
 	HFONT m_SmallFont;
 	CAccels	m_Accels;
-	CMapIDtoCF m_ThumbNails;
 	CMapIDtoCF m_RTFData;
 	CToolTipEx *m_pToolTip;
 	CFont m_Font;

+ 119 - 265
QPasteWnd.cpp

@@ -43,6 +43,7 @@ static char THIS_FILE[] = __FILE__;
 #define THREAD_FILL_ACCELERATORS	2
 #define THREAD_DESTROY_ACCELERATORS	3
 #define THREAD_LOAD_ITEMS			4
+#define THREAD_LOAD_EXTRA_DATA		5
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -61,15 +62,8 @@ CQPasteWnd::CQPasteWnd()
 
 CQPasteWnd::~CQPasteWnd()
 {
-	CloseHandle(m_Events[0]);
-	CloseHandle(m_Events[1]);
-	CloseHandle(m_Events[2]);
-	CloseHandle(m_Events[3]);
-	CloseHandle(m_ExitEvent);
-	CloseHandle(m_SearchingEvent);	
 }
 
-
 BEGIN_MESSAGE_MAP(CQPasteWnd, CWndEx)
 //{{AFX_MSG_MAP(CQPasteWnd)
 	ON_WM_CREATE()
@@ -218,18 +212,6 @@ BOOL CQPasteWnd::Create(const POINT& ptStart, CWnd* pParentWnd)
 	return CWndEx::Create(CRect(ptStart, szWnd), pParentWnd);
 }
 
-UINT  StartThread(LPVOID pParam)
-{
-	Log(_T("Starting fill list thread"));
-
-	CQPasteWnd *pWnd = (CQPasteWnd*)pParam;
-	pWnd->RunThread();
-
-	Log(_T("Ending fill list thread"));
-
-	return TRUE;
-}
-
 int CQPasteWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
 {
 	if (CWndEx::OnCreate(lpCreateStruct) == -1)
@@ -303,15 +285,8 @@ int CQPasteWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
 
 	UpdateFont();
 
-	m_Events[0] = CreateEvent(NULL, TRUE, FALSE, _T(""));
-	m_Events[1] = CreateEvent(NULL, TRUE, FALSE, _T(""));
-	m_Events[2] = CreateEvent(NULL, TRUE, FALSE, _T(""));
-	m_Events[3] = CreateEvent(NULL, TRUE, FALSE, _T(""));
-	m_ExitEvent = CreateEvent(NULL, TRUE, FALSE, _T(""));
-	m_SearchingEvent = CreateEvent(NULL, TRUE, FALSE, _T(""));
+	m_thread.Start(this);
 
-	AfxBeginThread(StartThread, this);
-		
 	return 0;
 }
 
@@ -389,7 +364,7 @@ void CQPasteWnd::OnSetFocus(CWnd* pOldWnd)
 void CQPasteWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
 {
 	CWndEx::OnActivate(nState, pWndOther, bMinimized);
-	
+
 	if(m_bHideWnd == false || m_lstHeader.GetToolTipHWnd() == pWndOther->GetSafeHwnd())
 		return;
 	
@@ -422,10 +397,13 @@ void CQPasteWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
 
 BOOL CQPasteWnd::HideQPasteWindow()
 {
-	Log(_T("HideQPasteWindow"));
+	Log(_T("Start of HideQPasteWindow"));
 
-	if(!theApp.m_bShowingQuickPaste) 
+	if(!theApp.m_bShowingQuickPaste)
+	{
+		Log(_T("End of HideQPasteWindow, !theApp.m_bShowingQuickPaste"));
 		return FALSE;
+	}
 
 	m_CritSection.Lock();
 		m_bStopQuery = true;
@@ -435,7 +413,7 @@ BOOL CQPasteWnd::HideQPasteWindow()
 	theApp.m_bShowingQuickPaste = false;
 	theApp.m_activeWnd.ReleaseFocus();
 	
-	SetEvent(m_Events[THREAD_DESTROY_ACCELERATORS]);
+	m_thread.FireUnloadAccelerators();
 	
 	KillTimer(TIMER_FILL_CACHE);
 	
@@ -462,16 +440,17 @@ BOOL CQPasteWnd::HideQPasteWindow()
 		m_CritSection.Unlock();
 
 		//Wait for the thread to stop fill the cache so we can clear it
-		WaitForSingleObject(m_SearchingEvent, INFINITE);
+		WaitForSingleObject(m_thread.m_SearchingEvent, 5000);
 
 		m_CritSection.Lock();
 		{
 			m_mapCache.clear();
 		}
 		m_CritSection.Unlock();
-
 	}
 	
+	Log(_T("End of HideQPasteWindow"));
+
 	return TRUE;
 }
 
@@ -490,8 +469,8 @@ BOOL CQPasteWnd::ShowQPasteWindow(BOOL bFillList)
 	m_bAllowRepaintImmediately = false;
 	UpdateStatus();
 	
-	SetEvent(m_Events[THREAD_FILL_ACCELERATORS]);
-	
+	m_thread.FireLoadAccelerators();
+
 	m_bHideWnd = true;
 	
 #ifdef AFTER_98
@@ -721,7 +700,7 @@ LRESULT CQPasteWnd::OnRefreshView(WPARAM wParam, LPARAM lParam)
 	else
 	{
 		//Wait for the thread to stop fill the cache so we can clear it
-		WaitForSingleObject(m_SearchingEvent, INFINITE);
+		WaitForSingleObject(m_thread.m_SearchingEvent, 5000);
 
 		m_CritSection.Lock();
 		{
@@ -870,8 +849,8 @@ BOOL CQPasteWnd::FillList(CString csSQLSearch/*=""*/)
 		
 	m_CritSection.Unlock();
 
-	SetEvent(m_Events[THREAD_DO_QUERY]);
-		
+	m_thread.FireDoQuery();
+
 	return TRUE;
 }
 
@@ -1263,7 +1242,7 @@ void CQPasteWnd::OnMenuProperties()
 		}
 		m_CritSection.Unlock();
 
-		SetEvent(m_Events[THREAD_FILL_ACCELERATORS]);
+		m_thread.FireLoadAccelerators();
 
 		m_lstHeader.RefreshVisibleRows();
 		
@@ -2296,7 +2275,7 @@ void CQPasteWnd::GetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
 							m_loadItems.push_back(loadItem);
 						}
 						
-						SetEvent(m_Events[THREAD_LOAD_ITEMS]);
+						m_thread.FireLoadItems();
 					}
 				}
 				m_CritSection.Unlock();
@@ -2312,23 +2291,111 @@ void CQPasteWnd::GetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
 		switch(pItem->iSubItem)
 		{
 		case 0:
-			try
+			m_CritSection.Lock();
 			{
-				m_CritSection.Lock();
+				MainTypeMap::iterator iter = m_mapCache.find(pItem->iItem);
+				if(iter != m_mapCache.end())
 				{
-					MainTypeMap::iterator iter = m_mapCache.find(pItem->iItem);
-					if(iter != m_mapCache.end())
-					{
-						pItem->lParam = iter->second.m_lID;
-					}
+					pItem->lParam = iter->second.m_lID;
 				}
-				m_CritSection.Unlock();
 			}
-			CATCH_SQLITE_EXCEPTION
+			m_CritSection.Unlock();
 				
 			break;
 		}
 	}
+
+	if(pItem->mask & LVIF_CF_DIB)
+	{
+		m_CritSection.Lock();
+		{
+			MainTypeMap::iterator iter = m_mapCache.find(pItem->iItem);
+			if(iter != m_mapCache.end())
+			{
+				if(iter->second.m_hasCF_Dib == true)
+				{
+					CF_DibTypeMap::iterator iterDib = m_cf_dibCache.find(iter->second.m_lID);
+					if(iterDib == m_cf_dibCache.end())
+					{
+						bool exists = false;
+						int count = m_ExtraDataLoadItems.size();
+						for(int i = 0; i < count; i++)
+						{
+							if(m_ExtraDataLoadItems[i].m_cfType == CF_DIB &&
+								m_ExtraDataLoadItems[i].m_lDBID == iter->second.m_lID)
+							{
+								exists = true;
+								break;
+							}
+						}
+
+						if(exists == false)
+						{
+							CClipFormatQListCtrl format;
+							format.m_cfType = CF_DIB;
+							format.m_lDBID = iter->second.m_lID;
+							format.m_clipRow = pItem->iItem;
+							format.m_autoDeleteData = false;
+							m_ExtraDataLoadItems.push_back(format);
+
+							m_thread.FireLoadExtraData();
+						}
+					}
+					else
+					{
+						pItem->lParam = (LPARAM)&(iterDib->second);
+					}
+				}
+			}
+		}
+		m_CritSection.Unlock();
+	}
+
+	if(pItem->mask & LVIF_CF_RICHTEXT)
+	{
+		m_CritSection.Lock();
+		{
+			MainTypeMap::iterator iter = m_mapCache.find(pItem->iItem);
+			if(iter != m_mapCache.end())
+			{
+				if(iter->second.m_hasCF_Rtf == true)
+				{
+					CF_DibTypeMap::iterator iterDib = m_cf_rtfCache.find(iter->second.m_lID);
+					if(iterDib == m_cf_rtfCache.end())
+					{
+						bool exists = false;
+						int count = m_ExtraDataLoadItems.size();
+						for(int i = 0; i < count; i++)
+						{
+							if(m_ExtraDataLoadItems[i].m_cfType == theApp.m_RTFFormat &&
+								m_ExtraDataLoadItems[i].m_lDBID == iter->second.m_lID)
+							{
+								exists = true;
+								break;
+							}
+						}
+
+						if(exists == false)
+						{
+							CClipFormatQListCtrl format;
+							format.m_cfType = theApp.m_RTFFormat;
+							format.m_lDBID = iter->second.m_lID;
+							format.m_clipRow = pItem->iItem;
+							format.m_autoDeleteData = false;
+							m_ExtraDataLoadItems.push_back(format);
+
+							m_thread.FireLoadExtraData();
+						}
+					}
+					else
+					{
+						pItem->lParam = (LPARAM)&(iterDib->second);
+					}
+				}
+			}
+		}
+		m_CritSection.Unlock();
+	}
 }
 
 CString CQPasteWnd::GetDisplayText(long lDontAutoDelete, long lShortCut, bool bIsGroup, long lParentID, CString csText)
@@ -2833,223 +2900,10 @@ void CQPasteWnd::FillMainTable(CMainTable &table, CppSQLite3Query &q)
 	table.m_QuickPaste = q.fieldValue(_T("QuickPasteText"));
 }
 
-void CQPasteWnd::RunThread()
-{
-	try
-	{
-		CEvent UpdateTimeEvent(TRUE, TRUE, _T("Ditto_Update_Clip_Time"), NULL);
-		CppSQLite3DB db;
-
-		CString csDbPath = CGetSetOptions::GetDBPath();
-
-		DWORD dStart = GetTickCount();
-		db.open(csDbPath);
-		Log(StrF(_T("Thread RunThread is starting time to open the database - %d"), GetTickCount() - dStart));
-
-		bool bDatabaseOpen = true;
-
-		while(true)
-		{
-			DWORD dwEvent = WaitForMultipleObjects(5, m_Events, FALSE, ONE_MINUTE*10);
-
-			if(dwEvent == WAIT_FAILED)
-			{
-				LPVOID lpMsgBuf = NULL;
-				DWORD dwErr = GetLastError();
-				FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-							  FORMAT_MESSAGE_FROM_SYSTEM |
-							  FORMAT_MESSAGE_IGNORE_INSERTS,
-							  NULL,
-							  dwErr,
-							  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
-							  (LPTSTR) &lpMsgBuf,
-							  0,
-							  NULL);
-
-				ASSERT(!lpMsgBuf);
-				LocalFree(lpMsgBuf);
-				break;
-			}
-			if(dwEvent == WAIT_TIMEOUT)
-			{
-				if(bDatabaseOpen)
-				{
-					DWORD dStart = GetTickCount();
-
-					db.close();
-					bDatabaseOpen = false;
-
-					Log(StrF(_T("Thread do query is CLOSING the database timout was hit - %d"), GetTickCount() - dStart));
-				}
-			}
-			else
-			{
-				int nIndex = dwEvent - WAIT_OBJECT_0;
-				ResetEvent(m_Events[nIndex]);
-
-				if(nIndex == THREAD_EXIT_THREAD)
-				{
-					Log(_T("Exit thread handle set, exiting search thread"));
-
-					//get out of the waitfor loop
-					break;
-				}
-				else
-				{
-					//If the db path changed close the db then reopen it
-					if(csDbPath != CGetSetOptions::GetDBPath())
-					{
-						db.close();
-						csDbPath = CGetSetOptions::GetDBPath();
-						bDatabaseOpen = false;
-						Log(_T("database name changed closing db"));
-					}
-
-					if(bDatabaseOpen == false)
-					{
-						DWORD dStart = GetTickCount();
-						db.open(csDbPath);
-						bDatabaseOpen = true;
-						Log(StrF(_T("Thread do query is opening the database back up - %d"), GetTickCount() - dStart));
-					}
-				}
-
-				switch(nIndex)
-				{
-				case THREAD_DO_QUERY:
-				{
-					ResetEvent(m_SearchingEvent);
-
-					//If we pasted then wait for the time on the pasted event to be updated before we query the db
-					DWORD dRet = WaitForSingleObject(UpdateTimeEvent, 2000);
-
-					long lTick = GetTickCount();
-
-					m_CritSection.Lock();
-						m_bFoundClipToSetFocusTo = false;
-						CString CountSQL(m_CountSQL);
-						m_mapCache.clear();
-						m_loadItems.clear();
-						m_bStopQuery = false;
-					m_CritSection.Unlock();
-
-					long lRecordCount = 0;
-
-					try
-					{
-						lRecordCount = db.execScalar(CountSQL);
-						::PostMessage(m_hWnd, NM_SET_LIST_COUNT, lRecordCount, 0);
-					}
-					CATCH_SQLITE_EXCEPTION	
-					
-					SetEvent(m_SearchingEvent);
-					Log(StrF(_T("Set list count = %d, time = %d"), lRecordCount, GetTickCount() - lTick));
-				}
-				break;
-
-				case THREAD_LOAD_ITEMS:
-				{
-					ResetEvent(m_SearchingEvent);
-
-					long startTick = GetTickCount();
-					int loadItemsIndex = 0;
-					int loadItemsCount = 0;
-					int loadCount = 0;
-					CString localSql;
-					bool clearFirstLoadItem = false;
-
-					m_CritSection.Lock();
-						if(m_loadItems.size() > 0)
-						{
-							loadItemsIndex = m_loadItems[0].x;
-							loadItemsCount = m_loadItems[0].y - m_loadItems[0].x;
-							localSql = m_SQL;
-							m_bStopQuery = false;
-							clearFirstLoadItem = true;
-						}
-					m_CritSection.Unlock();
-
-					if(clearFirstLoadItem)
-					{
-						Log(StrF(_T("Load Items start = %d, count = %d"), loadItemsIndex, loadItemsCount));
-
-						CString limit;
-						limit.Format(_T(" LIMIT %d OFFSET %d"), loadItemsCount, loadItemsIndex);
-						localSql += limit;
-
-						CMainTable table;
-
-						CppSQLite3Query q = db.execQuery(localSql);
-						while(!q.eof())
-						{
-							FillMainTable(table, q);
-							table.m_listIndex = loadItemsIndex;
-
-							m_CritSection.Lock();
-							{
-								m_mapCache[loadItemsIndex] = table;
-							}
-							m_CritSection.Unlock();
-
-							if(m_bStopQuery)
-							{
-								Log(StrF(_T("StopQuery called exiting filling cache count = %d"), loadItemsIndex));
-								break;
-							}
-
-							q.nextRow();
-
-							loadItemsIndex++;
-							loadCount++;
-
-							::PostMessage(m_hWnd, NM_REFRESH_ROW, table.m_lID, table.m_listIndex);
-						}
-
-						::PostMessage(m_hWnd, NM_REFRESH_ROW, -1, 0);
-
-						if(clearFirstLoadItem)
-						{
-							m_CritSection.Lock();
-								m_loadItems.erase(m_loadItems.begin());
-							m_CritSection.Unlock();
-						}
-
-						Log(StrF(_T("Load items End count = %d, time = %d"), loadCount, GetTickCount() - startTick));
-					}
-					else
-					{
-						Log(_T("No load items in array not loading any clips"));
-					}
-
-					SetEvent(m_SearchingEvent);
-				}
-				break;
-
-				case THREAD_FILL_ACCELERATORS:
-				{
-					m_lstHeader.DestroyAndCreateAccelerator(TRUE, db);
-				}
-				break;
-
-				case THREAD_DESTROY_ACCELERATORS:
-				{
-					m_lstHeader.DestroyAndCreateAccelerator(FALSE, db);
-				}
-				break;
-				}
-			}
-		}
-	}
-	CATCH_SQLITE_EXCEPTION
-
-	ResetEvent(m_ExitEvent);
-}
-
 void CQPasteWnd::OnDestroy() 
 {
 	CWndEx::OnDestroy();
-	
-	SetEvent(m_Events[THREAD_EXIT_THREAD]);
+	m_thread.Stop();
 }
 
 void CQPasteWnd::OnTimer(UINT_PTR nIDEvent)
@@ -3113,14 +2967,14 @@ LRESULT CQPasteWnd::OnSelectAll(WPARAM wParam, LPARAM lParam)
 	BOOL ret = FALSE;
 	m_CritSection.Lock();
 
-	if(m_mapCache.size() < m_lstHeader.GetItemCount())
+	if((int)m_mapCache.size() < m_lstHeader.GetItemCount())
 	{
 		Log(_T("All items selected loading all items from the db"));
 
 		CPoint loadItem(0, m_lstHeader.GetItemCount());
 		m_loadItems.push_back(loadItem);
 
-		SetEvent(m_Events[THREAD_LOAD_ITEMS]);
+		m_thread.FireLoadItems();
 
 		ret = TRUE;
 

+ 18 - 6
QPasteWnd.h

@@ -17,6 +17,8 @@
 #include <vector>
 #include <map>
 #include <afxmt.h>
+#include "ClipFormatQListCtrl.h"
+#include "QPasteWndThread.h"
 
 class CMainTable
 {
@@ -27,9 +29,17 @@ public:
 		m_bIsGroup(false),
 		m_bHasShortCut(false),
 		m_bHasParent(false),
-		m_listIndex(-1)
+		m_listIndex(-1),
+		m_hasCF_Dib(true),
+		m_hasCF_Rtf(true)
 	{
 	}
+	
+	~CMainTable()
+	{
+		
+	}
+
 	long m_lID;
 	CString m_Desc;
 	bool m_bDontAutoDelete;
@@ -38,10 +48,13 @@ public:
 	bool m_bHasParent;
 	CString m_QuickPaste;
 	int m_listIndex;
+	bool m_hasCF_Dib;
+	bool m_hasCF_Rtf;
 };
 
 
 typedef std::map<int, CMainTable> MainTypeMap;
+typedef std::map<int, CClipFormatQListCtrl> CF_DibTypeMap;
 
 
 
@@ -103,13 +116,12 @@ public:
 	long			m_lItemsPerPage;
 	bool			m_bModifersMoveActive;
 
+	CQPasteWndThread m_thread;
 	MainTypeMap m_mapCache;
 	std::vector<CPoint> m_loadItems;
-
-	HANDLE m_Events[4];
-	HANDLE m_ExitEvent;
-	HANDLE m_SearchingEvent;
-
+	std::vector<CClipFormatQListCtrl> m_ExtraDataLoadItems;
+	CF_DibTypeMap m_cf_dibCache;
+	CF_DibTypeMap m_cf_rtfCache;
 	CCriticalSection m_CritSection;
 
 	CAccels m_MainAccels;