Use postmessage send message to main thread handle UI operation to avoid dead lock when use waitforsingle object when try to terminate back thread
Signed-off-by: Frank Li <lznuaa@gmail.com>
ON_NOTIFY_REFLECT(LVN_ODFINDITEM,OnLvnOdfinditemLoglist)\r
ON_WM_CREATE()\r
ON_WM_DESTROY()\r
+ ON_MESSAGE(MSG_LOADED,OnLoad)\r
END_MESSAGE_MAP()\r
\r
int CGitLogListBase:: OnCreate(LPCREATESTRUCT lpCreateStruct)\r
\r
\r
//this->m_logEntries.ParserFromLog();\r
- SetItemCountEx(this->m_logEntries.size());\r
+ if(IsInWorkingThread())\r
+ PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL);\r
+ else\r
+ SetItemCountEx(this->m_logEntries.size());\r
\r
this->m_arShownList.RemoveAll();\r
\r
DiffSelectedRevWithPrevious();\r
}\r
\r
-int CGitLogListBase::FetchLogAsync(CALLBACK_PROCESS *proc,void * data)\r
+int CGitLogListBase::FetchLogAsync(void * data)\r
{\r
- m_ProcCallBack=proc;\r
m_ProcData=data;\r
m_bExitThread=FALSE;\r
InterlockedExchange(&m_bThreadRunning, TRUE);\r
UINT CGitLogListBase::LogThread()\r
{\r
\r
- if(m_ProcCallBack)\r
- m_ProcCallBack(m_ProcData,GITLOG_START);\r
+// if(m_ProcCallBack)\r
+// m_ProcCallBack(m_ProcData,GITLOG_START);\r
+ ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START,0);\r
\r
InterlockedExchange(&m_bThreadRunning, TRUE);\r
InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
\r
if(this->m_bExitThread)\r
return 0;\r
-\r
+#if 0\r
RedrawItems(0, m_arShownList.GetCount());\r
SetRedraw(false);\r
ResizeAllListCtrlCols();\r
SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
}\r
}\r
+#endif\r
InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
\r
int index=0;\r
if(!m_logEntries.FetchFullInfo(i))\r
{\r
updated++;\r
- this->GetItemRect(i,&rect,LVIR_BOUNDS);\r
- this->InvalidateRect(rect);\r
}\r
m_LogCache.AddCacheEntry(m_logEntries[i]);\r
\r
updated++;\r
InterlockedExchange(&m_logEntries[i].m_IsUpdateing,FALSE);\r
InterlockedExchange(&m_logEntries[i].m_IsFull,TRUE);\r
-\r
- this->GetItemRect(i,&rect,LVIR_BOUNDS);\r
- this->InvalidateRect(rect);\r
}\r
\r
+ ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)i,0);\r
+\r
if(m_bExitThread)\r
return 0;\r
\r
if(percent == GITLOG_END)\r
percent = GITLOG_END -1;\r
\r
- if(m_ProcCallBack)\r
- m_ProcCallBack(m_ProcData,percent);\r
+ ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0);\r
\r
\r
}\r
// make sure the filter is applied (if any) now, after we refreshed/fetched\r
// the log messages\r
\r
- \r
-\r
- if(m_ProcCallBack)\r
- m_ProcCallBack(m_ProcData,GITLOG_END);\r
+ ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_END,0);\r
\r
InterlockedExchange(&m_bThreadRunning, FALSE);\r
\r
\r
void CGitLogListBase::OnDestroy()\r
{\r
+ if(this->m_bThreadRunning)\r
+ {\r
+ this->m_bExitThread=true;\r
+ DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
+ if(ret == WAIT_TIMEOUT)\r
+ TerminateThread();\r
+ }\r
while(m_LogCache.SaveCache())\r
{\r
if(CMessageBox::Show(NULL,_T("Can Save Log Cache to Disk,click yes for retry, click no for give up"),_T("TortoiseGit"),\r
break;\r
}\r
CHintListCtrl::OnDestroy();\r
-}
\ No newline at end of file
+}\r
+\r
+LRESULT CGitLogListBase::OnLoad(WPARAM wParam,LPARAM lParam)\r
+{\r
+ CRect rect;\r
+ int i=(int)wParam;\r
+ this->GetItemRect(i,&rect,LVIR_BOUNDS);\r
+ this->InvalidateRect(rect);\r
+ return 0;\r
+}\r
#define LOGFILTER_REGEX 6\r
#define LOGFILTER_BUGID 7\r
\r
-typedef void CALLBACK_PROCESS(void * data, int progress);\r
+//typedef void CALLBACK_PROCESS(void * data, int progress);\r
+#define MSG_LOADED (WM_USER+110)\r
+#define MSG_LOAD_PERCENTAGE (WM_USER+111)\r
\r
class CGitLogListBase : public CHintListCtrl\r
{\r
int FillGitLog(CTGitPath *path,int infomask=CGit:: LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE);\r
\r
inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }\r
- int FetchLogAsync(CALLBACK_PROCESS *proc=NULL, void * data=NULL);\r
+ int FetchLogAsync(void * data=NULL);\r
CPtrArray m_arShownList;\r
void Refresh();\r
void RecalculateShownList(CPtrArray * pShownlist);\r
if(this->m_LoadingThread)\r
AfxTermThread((HINSTANCE)m_LoadingThread->m_hThread);\r
};\r
+\r
+ bool IsInWorkingThread()\r
+ {\r
+ return (AfxGetThread() == m_LoadingThread);\r
+ }\r
\r
volatile bool m_bExitThread;\r
CWinThread* m_LoadingThread;\r
afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);\r
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);\r
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);\r
+ afx_msg LRESULT OnLoad(WPARAM wParam, LPARAM lParam);\r
void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);\r
afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);\r
void PreSubclassWindow();\r
CRegDWORD m_regMaxBugIDColWidth;\r
int m_nSearchIndex;\r
\r
- CALLBACK_PROCESS *m_ProcCallBack;\r
void *m_ProcData;\r
CStoreSelection* m_pStoreSelection;\r
MAP_HASH_NAME m_HashMap;\r
\r
ON_MESSAGE(WM_FILTEREDIT_INFOCLICKED, OnClickedInfoIcon)\r
ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)\r
+\r
+ ON_MESSAGE(MSG_LOAD_PERCENTAGE,OnLogListLoading)\r
\r
ON_EN_CHANGE(IDC_SEARCHEDIT, OnEnChangeSearchedit)\r
ON_WM_TIMER()\r
//m_tFrom = (DWORD)-1;\r
\r
m_LogList.m_Path=m_path;\r
- m_LogList.FetchLogAsync(LogCallBack,this);\r
+ m_LogList.FetchLogAsync(this);\r
\r
GetDlgItem(IDC_LOGLIST)->SetFocus();\r
return FALSE;\r
}\r
\r
-void CLogDlg::LogRunStatus(int cur)\r
+LRESULT CLogDlg::OnLogListLoading(WPARAM wParam, LPARAM lParam)\r
{\r
+ int cur=(int)wParam;\r
+\r
if( cur == GITLOG_START )\r
{\r
CString temp;\r
}\r
\r
m_LogProgress.SetPos(cur);\r
+ return 0;\r
}\r
void CLogDlg::SetDlgTitle(bool bOffline)\r
{\r
SetWindowText(m_sTitle + _T(" - "));\r
break;\r
}\r
- //m_LogList.m_bExitThread=TRUE;\r
- //::WaitForSingleObject(m_LogList.m_LoadingThread->m_hThread,INFINITE);\r
-\r
- m_LogList.TerminateThread();\r
+ m_LogList.m_bExitThread=TRUE;\r
+ DWORD ret =::WaitForSingleObject(m_LogList.m_LoadingThread->m_hThread,20000);\r
+ if(ret == WAIT_TIMEOUT)\r
+ m_LogList.TerminateThread();\r
\r
m_LogList.Clear();\r
- m_LogList.FetchLogAsync(LogCallBack,this);\r
-#if 0\r
- m_ChangedFileListCtrl.SetItemCountEx(0);\r
- m_ChangedFileListCtrl.Invalidate();\r
- // We need to create CStoreSelection on the heap or else\r
- // the variable will run out of the scope before the\r
- // thread ends. Therefore we let the thread delete\r
- // the instance.\r
- m_pStoreSelection = new CStoreSelection(this);\r
- m_LogList.SetItemCountEx(0);\r
- m_LogList.Invalidate();\r
- InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
- CWnd * pMsgView = GetDlgItem(IDC_MSGVIEW);\r
- pMsgView->SetWindowText(_T(""));\r
-\r
- SetSortArrow(&m_LogList, -1, true);\r
-\r
- m_LogList.DeleteAllItems();\r
- m_arShownList.RemoveAll();\r
- m_logEntries.ClearAll();\r
-\r
- m_logcounter = 0;\r
- m_bCancelled = FALSE;\r
- m_tTo = 0;\r
- m_tFrom = (DWORD)-1;\r
- m_limit = 0;\r
+ m_LogList.FetchLogAsync(this);\r
\r
- InterlockedExchange(&m_bThreadRunning, TRUE);\r
- if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
- {\r
- InterlockedExchange(&m_bThreadRunning, FALSE);\r
- CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
- }\r
- GetDlgItem(IDC_LOGLIST)->UpdateData(FALSE);\r
- InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
-#endif\r
}\r
\r
void CLogDlg::OnBnClickedRefresh()\r
afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);\r
afx_msg LRESULT OnClickedInfoIcon(WPARAM wParam, LPARAM lParam);\r
afx_msg LRESULT OnClickedCancelFilter(WPARAM wParam, LPARAM lParam);\r
+ afx_msg LRESULT OnLogListLoading(WPARAM wParam, LPARAM lParam);\r
+\r
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);\r
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);\r
afx_msg void OnBnClickedGetall();\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\explorer.ico"\r
+ RelativePath=".\explorer.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\explorer.ico"\r
+ RelativePath="..\Resources\explorer.ico"\r
>\r
</File>\r
<File\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\newfolder.ico"\r
+ RelativePath=".\newfolder.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\newfolder.ico"\r
+ RelativePath="..\Resources\newfolder.ico"\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\open.ico"\r
+ RelativePath=".\open.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\open.ico"\r
+ RelativePath="..\Resources\open.ico"\r
>\r
</File>\r
<File\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\save.ico"\r
+ RelativePath=".\save.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\save.ico"\r
+ RelativePath="..\Resources\save.ico"\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\saveas.ico"\r
+ RelativePath=".\saveas.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\saveas.ico"\r
+ RelativePath="..\Resources\saveas.ico"\r
>\r
</File>\r
<File\r
>\r
</File>\r
<File\r
- RelativePath="..\Resources\up.ico"\r
+ RelativePath=".\up.ico"\r
>\r
</File>\r
<File\r
- RelativePath=".\up.ico"\r
+ RelativePath="..\Resources\up.ico"\r
>\r
</File>\r
<File\r