From 45b83a0d09b39bc1c962cb33a2cc7c109eebaac4 Mon Sep 17 00:00:00 2001 From: blikblum Date: Sat, 23 Jan 2010 23:35:25 +0000 Subject: [PATCH] * (4.8 branch) Synchronize with main svn up to version 206 git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1134 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../branches/4.8/VirtualTrees.pas | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/components/virtualtreeview-new/branches/4.8/VirtualTrees.pas b/components/virtualtreeview-new/branches/4.8/VirtualTrees.pas index 640850059..dcb0b85e7 100644 --- a/components/virtualtreeview-new/branches/4.8/VirtualTrees.pas +++ b/components/virtualtreeview-new/branches/4.8/VirtualTrees.pas @@ -27,6 +27,10 @@ unit VirtualTrees; // (C) 1999-2001 digital publishing AG. All Rights Reserved. //---------------------------------------------------------------------------------------------------------------------- // +// July 2009 +// - Bug fix: TWorkerThread will no longer reference the tree after it has been destroyed (Mantis issue #384) +// - Bug fix: TBaseVirtualTree.InternalConnectNode checked the expanded state of the wrong node if Mode was +// amAddChildFirst or amAddChildLast // June 2009 // - Bug fix: fixed some issues concerning the vista theme handling // - Improvement: removed hidden node handling in this branch @@ -4008,6 +4012,7 @@ type FWaiterList: TThreadList; FRefCount: Cardinal; protected + procedure CancelValidation(Tree: TBaseVirtualTree); procedure ChangeTreeStates(EnterStates, LeaveStates: TChangeStates); procedure Execute; override; public @@ -4987,6 +4992,10 @@ begin // Make sure there is no reference remaining to the releasing tree. Tree.InterruptValidation; + // Borland change (used to debug shutdown issue with dangling FCurrentTree reference) + Assert(WorkerThread.FCurrentTree <> Tree, 'WorkerThread.FCurrentTree dangling reference!'); + + if WorkerThread.FRefCount = 0 then begin with WorkerThread do @@ -5036,6 +5045,26 @@ end; //---------------------------------------------------------------------------------------------------------------------- +procedure TWorkerThread.CancelValidation(Tree: TBaseVirtualTree); + +var + Msg: TMsg; + +begin + // Wait for any references to this tree to be released. + // Pump WM_CHANGESTATE messages so the thread doesn't block on SendMessage calls. + while FCurrentTree = Tree do + begin + if Tree.HandleAllocated and PeekMessage(Msg, Tree.Handle, WM_CHANGESTATE, WM_CHANGESTATE, PM_REMOVE) then + begin + TranslateMessage(Msg); + DispatchMessage(Msg); + end; + end; +end; + +//---------------------------------------------------------------------------------------------------------------------- + procedure TWorkerThread.ChangeTreeStates(EnterStates, LeaveStates: TChangeStates); begin @@ -5078,20 +5107,21 @@ begin end; // Something to do? - try - if Assigned(FCurrentTree) then - begin + if Assigned(FCurrentTree) then + begin + try ChangeTreeStates([csValidating], [csUseCache]); EnterStates := []; if not (tsStopValidation in FCurrentTree.FStates) and FCurrentTree.DoValidateCache then EnterStates := [csUseCache]; + + finally + LeaveStates := [csValidating, csStopValidation]; + if csUseCache in EnterStates then + Include(LeaveStates, csValidationNeeded); + ChangeTreeStates(EnterStates, LeaveStates); + FCurrentTree := nil; end; - finally - LeaveStates := [csValidating, csStopValidation]; - if csUseCache in EnterStates then - Include(LeaveStates, csValidationNeeded); - ChangeTreeStates(EnterStates, LeaveStates); - FCurrentTree := nil; end; end; end; @@ -5113,6 +5143,7 @@ begin finally FWaiterList.UnlockList; end; + CancelValidation(Tree); end; //---------------------------------------------------------------------------------------------------------------------- @@ -12900,10 +12931,8 @@ end; procedure TBaseVirtualTree.InterruptValidation; -// Waits until the worker thread has stopped validating the caches of this tree. - -//var -// Msg: TMsg; +var + WasValidating: Boolean; begin DoStateChange([tsStopValidation], [tsUseCache]); @@ -12911,35 +12940,13 @@ begin // Check the worker thread existance. It might already be gone (usually on destruction of the last tree). if Assigned(WorkerThread) then begin - if tsValidating in FStates then - begin - // Do a hard break until the worker thread has stopped validation. - while (tsValidating in FStates) and (WorkerThread.CurrentTree = Self) and not Application.Terminated do - begin - // Pump our own messages to avoid a deadlock. - //todo_lcl_check - Application.ProcessMessages; - { - if PeekMessage(Msg, Handle, 0, 0, PM_REMOVE) then - begin - if Msg.message = WM_QUIT then - begin - PostQuitMessage(Msg.WParam); - Break; - end; - TranslateMessage(Msg); - DispatchMessage(Msg); - end; - } - end; + WasValidating := (tsValidating in FStates); + WorkerThread.RemoveTree(Self); + if WasValidating then DoStateChange([tsValidationNeeded]); - end - else // Remove any pending validation. - WorkerThread.RemoveTree(Self); end; {$endif} end; - //---------------------------------------------------------------------------------------------------------------------- function TBaseVirtualTree.IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean; @@ -21505,7 +21512,7 @@ begin Include(Destination.States, vsHasChildren); AdjustTotalCount(Destination, Node.TotalCount, True); // Add the new node's height only if its parent is expanded. - if Destination.Parent.States * [vsExpanded, vsVisible] = [vsExpanded, vsVisible] then + if Destination.States * [vsExpanded, vsVisible] = [vsExpanded, vsVisible] then AdjustTotalHeight(Destination, Node.TotalHeight, True); if FullyVisible[Node] then Inc(FVisibleCount, CountVisibleChildren(Node) + 1); @@ -21536,7 +21543,7 @@ begin Include(Destination.States, vsHasChildren); AdjustTotalCount(Destination, Node.TotalCount, True); // Add the new node's height only if its parent is expanded. - if Destination.Parent.States * [vsExpanded, vsVisible] = [vsExpanded, vsVisible] then + if Destination.States * [vsExpanded, vsVisible] = [vsExpanded, vsVisible] then AdjustTotalHeight(Destination, Node.TotalHeight, True); if FullyVisible[Node] then Inc(FVisibleCount, CountVisibleChildren(Node) + 1);