git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jvcl@19 7f62d464-2af8-f54e-996c-e91b33f51cbe
355 lines
8.9 KiB
ObjectPascal
355 lines
8.9 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvThreadTimer.PAS, released on 2001-02-28.
|
|
|
|
The Initial Developer of the Original Code is S?stien Buysse [sbuysse att buypin dott com]
|
|
Portions created by S?stien Buysse are Copyright (C) 2001 S?stien Buysse.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
Michael Beck [mbeck att bigfoot dott com].
|
|
Peter Thrnqvist
|
|
Ivo Bauer
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.delphi-jedi.org
|
|
|
|
Known Issues:
|
|
|
|
History:
|
|
2003-07-24 (p3)
|
|
* Changed Active->Enabled and Delay->Interval to make property names match TTimer
|
|
* Changed implementation so that setting Enabled := false, frees the thread instead
|
|
of suspending it. This makes it possible to restart the timer interval.
|
|
2003-07-25 (ivobauer)
|
|
* Rewritten almost everything.
|
|
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvThreadTimer.pas 12501 2009-09-14 20:59:58Z ahuser $
|
|
|
|
unit JvThreadTimer;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
{$IFDEF MSWINDOWS}
|
|
Windows,
|
|
{$ENDIF MSWINDOWS}
|
|
{$IFDEF UNIX}
|
|
QWindows,
|
|
{$ENDIF UNIX}
|
|
SysUtils, Classes,
|
|
JvTypes, JvComponentBase;
|
|
|
|
type
|
|
TJvThreadTimer = class(TJvComponent)
|
|
private
|
|
FEnabled: Boolean;
|
|
FInterval: Cardinal;
|
|
FKeepAlive: Boolean;
|
|
FOnTimer: TNotifyEvent;
|
|
FPriority: TThreadPriority;
|
|
FStreamedEnabled: Boolean;
|
|
FThread: TThread;
|
|
function GetThread: TThread;
|
|
procedure SetEnabled(const Value: Boolean);
|
|
procedure SetInterval(const Value: Cardinal);
|
|
procedure SetOnTimer(const Value: TNotifyEvent);
|
|
procedure SetPriority(const Value: TThreadPriority);
|
|
procedure SetKeepAlive(const Value: Boolean);
|
|
protected
|
|
procedure DoOnTimer;
|
|
procedure Loaded; override;
|
|
procedure StopTimer;
|
|
procedure UpdateTimer;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
property Thread: TThread read GetThread;
|
|
published
|
|
// (p3) renamed Active->Enabled, Delay->Interval to make it compatible with TTimer
|
|
property Enabled: Boolean read FEnabled write SetEnabled default False;
|
|
property Interval: Cardinal read FInterval write SetInterval default 1000;
|
|
property KeepAlive: Boolean read FKeepAlive write SetKeepAlive default False;
|
|
property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
|
|
property Priority: TThreadPriority read FPriority write SetPriority
|
|
{$IFDEF MSWINDOWS} default tpNormal {$ENDIF};
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_39/run/JvThreadTimer.pas $';
|
|
Revision: '$Revision: 12501 $';
|
|
Date: '$Date: 2009-09-14 22:59:58 +0200 (lun., 14 sept. 2009) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Messages,
|
|
JvJCLUtils;
|
|
|
|
type
|
|
TJvTimerThread = class(TThread)
|
|
private
|
|
FEvent: THandle;
|
|
FHasBeenSuspended: Boolean;
|
|
FInterval: Cardinal;
|
|
FTimer: TJvThreadTimer;
|
|
FPriority: TThreadPriority;
|
|
protected
|
|
procedure DoSuspend;
|
|
procedure Execute; override;
|
|
public
|
|
constructor Create(ATimer: TJvThreadTimer);
|
|
destructor Destroy; override;
|
|
procedure Stop;
|
|
property Interval: Cardinal read FInterval;
|
|
property Timer: TJvThreadTimer read FTimer;
|
|
end;
|
|
|
|
function SubtractMin0(const Big, Small: Cardinal): Cardinal;
|
|
begin
|
|
if Big <= Small then
|
|
Result := 0
|
|
else
|
|
Result := Big - Small;
|
|
end;
|
|
|
|
//=== { TJvTimerThread } =====================================================
|
|
|
|
constructor TJvTimerThread.Create(ATimer: TJvThreadTimer);
|
|
begin
|
|
inherited Create(False);
|
|
|
|
FreeOnTerminate := True;
|
|
{ Manually reset = false; Initial State = false }
|
|
FEvent := CreateEvent(nil, False, False, nil);
|
|
if FEvent = 0 then
|
|
RaiseLastOSError;
|
|
FInterval := ATimer.FInterval;
|
|
FTimer := ATimer;
|
|
FPriority := ATimer.Priority; // setting the priority is deferred to Execute()
|
|
end;
|
|
|
|
destructor TJvTimerThread.Destroy;
|
|
begin
|
|
Stop;
|
|
inherited Destroy;
|
|
if FEvent <> 0 then
|
|
CloseHandle(FEvent);
|
|
end;
|
|
|
|
procedure TJvTimerThread.DoSuspend;
|
|
begin
|
|
FHasBeenSuspended := True;
|
|
Suspended := True;
|
|
end;
|
|
|
|
procedure TJvTimerThread.Execute;
|
|
var
|
|
Offset, TickCount: Cardinal;
|
|
begin
|
|
Priority := FPriority;
|
|
if WaitForSingleObject(FEvent, Interval) <> WAIT_TIMEOUT then
|
|
Exit;
|
|
|
|
while not Terminated do
|
|
begin
|
|
FHasBeenSuspended := False;
|
|
|
|
TickCount := GetTickCount;
|
|
if not Terminated then
|
|
Synchronize(FTimer.DoOnTimer);
|
|
|
|
// Determine how much time it took to execute OnTimer event handler. Take a care
|
|
// of wrapping the value returned by GetTickCount API around zero if Windows is
|
|
// run continuously for more than 49.7 days.
|
|
if FHasBeenSuspended then
|
|
Offset := 0
|
|
else
|
|
begin
|
|
Offset := GetTickCount;
|
|
if Offset >= TickCount then
|
|
Dec(Offset, TickCount)
|
|
else
|
|
Inc(Offset, High(Cardinal) - TickCount);
|
|
end;
|
|
|
|
// Make sure Offset is less than or equal to FInterval.
|
|
// (rb) Ensure it's atomic, because of KeepAlive
|
|
if WaitForSingleObject(FEvent, SubtractMin0(Interval, Offset)) <> WAIT_TIMEOUT then
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvTimerThread.Stop;
|
|
begin
|
|
Terminate;
|
|
SetEvent(FEvent);
|
|
if Suspended then
|
|
Suspended := False;
|
|
Sleep(0);
|
|
end;
|
|
|
|
//=== { TJvThreadTimer } =====================================================
|
|
|
|
constructor TJvThreadTimer.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FInterval := 1000;
|
|
{$IFDEF MSWINDOWS}
|
|
FPriority := tpNormal;
|
|
{$ENDIF MSWINDOWS}
|
|
{$IFDEF UNIX}
|
|
FPriority := 0;
|
|
{$ENDIF UNIX}
|
|
end;
|
|
|
|
destructor TJvThreadTimer.Destroy;
|
|
begin
|
|
StopTimer;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.DoOnTimer;
|
|
begin
|
|
if csDestroying in ComponentState then
|
|
Exit;
|
|
|
|
try
|
|
if Assigned(FOnTimer) then
|
|
FOnTimer(Self);
|
|
except
|
|
if Assigned(ApplicationHandleException) then
|
|
ApplicationHandleException(Self);
|
|
end;
|
|
end;
|
|
|
|
function TJvThreadTimer.GetThread: TThread;
|
|
begin
|
|
Result := FThread;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
SetEnabled(FStreamedEnabled);
|
|
end;
|
|
|
|
procedure TJvThreadTimer.SetEnabled(const Value: Boolean);
|
|
begin
|
|
if csLoading in ComponentState then
|
|
FStreamedEnabled := Value
|
|
else
|
|
if FEnabled <> Value then
|
|
begin
|
|
FEnabled := Value;
|
|
UpdateTimer;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.SetInterval(const Value: Cardinal);
|
|
begin
|
|
if FInterval <> Value then
|
|
begin
|
|
FInterval := Value;
|
|
UpdateTimer;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.SetKeepAlive(const Value: Boolean);
|
|
begin
|
|
if FKeepAlive <> Value then
|
|
begin
|
|
StopTimer;
|
|
FKeepAlive := Value;
|
|
UpdateTimer;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.SetOnTimer(const Value: TNotifyEvent);
|
|
begin
|
|
if @FOnTimer <> @Value then
|
|
begin
|
|
FOnTimer := Value;
|
|
UpdateTimer;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.SetPriority(const Value: TThreadPriority);
|
|
begin
|
|
if FPriority <> Value then
|
|
begin
|
|
FPriority := Value;
|
|
if FThread <> nil then
|
|
FThread.Priority := FPriority;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.StopTimer;
|
|
begin
|
|
if FThread is TJvTimerThread then
|
|
TJvTimerThread(FThread).Stop;
|
|
FThread := nil;
|
|
end;
|
|
|
|
procedure TJvThreadTimer.UpdateTimer;
|
|
var
|
|
DoEnable: Boolean;
|
|
begin
|
|
if ComponentState * [csDesigning, csLoading] <> [] then
|
|
Exit;
|
|
|
|
DoEnable := FEnabled and Assigned(FOnTimer) and (FInterval > 0);
|
|
|
|
if not KeepAlive then
|
|
StopTimer;
|
|
|
|
if DoEnable then
|
|
begin
|
|
if FThread is TJvTimerThread then
|
|
TJvTimerThread(FThread).FInterval := FInterval
|
|
else
|
|
FThread := TJvTimerThread.Create(Self);
|
|
|
|
if FThread.Suspended then
|
|
FThread.Suspended := False;
|
|
end
|
|
else
|
|
if FThread is TJvTimerThread then
|
|
begin
|
|
if not FThread.Suspended then
|
|
TJvTimerThread(FThread).DoSuspend;
|
|
|
|
TJvTimerThread(FThread).FInterval := FInterval;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|