fptimer.pp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by Michael Van Canneyt.
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {
  11. A generic timer component. Can be used in GUI and non-GUI apps.
  12. Based heavily on an idea by Graeme Geldenhuys, extended so
  13. the tick mechanism is pluggable.
  14. Note that the system implementation will only work for timers
  15. in the main thread, as it uses synchronize to do the job.
  16. You need to enable threads in your application for the system
  17. implementation to work.
  18. A nice improvement would be an implementation that works
  19. in all threads, such as the threadedtimer of IBX for linux.
  20. }
  21. unit fpTimer;
  22. {$mode objfpc}{$H+}
  23. interface
  24. uses
  25. Classes;
  26. type
  27. TFPTimerDriver = Class;
  28. TFPCustomTimer = class(TComponent)
  29. private
  30. FInterval: Integer;
  31. FDriver : TFPTimerDriver;
  32. FOnTimer: TNotifyEvent;
  33. FContinue: Boolean;
  34. FRunning: Boolean;
  35. FEnabled: Boolean;
  36. procedure SetEnabled(Value: Boolean );
  37. protected
  38. property Continue: Boolean read FContinue write FContinue;
  39. procedure Timer; virtual;
  40. Function CreateTimerDriver : TFPTimerDriver;
  41. public
  42. Constructor Create(AOwner: TComponent); override;
  43. Destructor Destroy; override;
  44. procedure StartTimer; virtual;
  45. procedure StopTimer; virtual;
  46. protected
  47. property Enabled: Boolean read FEnabled write SetEnabled;
  48. property Interval: Integer read FInterval write FInterval;
  49. property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  50. end;
  51. TFPTimer = Class(TFPCustomTimer)
  52. Published
  53. Property Enabled;
  54. Property Interval;
  55. Property OnTimer;
  56. end;
  57. TFPTimerDriver = Class(TObject)
  58. Protected
  59. FTimer : TFPCustomTimer;
  60. Public
  61. Constructor Create(ATimer : TFPCustomTimer); virtual;
  62. Procedure StartTimer; virtual; abstract;
  63. Procedure StopTimer; virtual; abstract;
  64. Property Timer : TFPCustomTimer Read FTimer;
  65. end;
  66. TFPTimerDriverClass = Class of TFPTimerDriver;
  67. Var
  68. DefaultTimerDriverClass : TFPTimerDriverClass = Nil;
  69. implementation
  70. uses
  71. SysUtils;
  72. { ---------------------------------------------------------------------
  73. TFPTimer
  74. ---------------------------------------------------------------------}
  75. constructor TFPCustomTimer.Create(AOwner: TComponent);
  76. begin
  77. inherited;
  78. FDriver:=CreateTimerDriver;
  79. end;
  80. destructor TFPCustomTimer.Destroy;
  81. begin
  82. If FEnabled then
  83. StopTimer;
  84. FDriver.FTimer:=Nil;
  85. FreeAndNil(FDriver);
  86. Inherited;
  87. end;
  88. Function TFPCustomTimer.CreateTimerDriver : TFPTimerDriver;
  89. begin
  90. Result:=DefaultTimerDriverClass.Create(Self);
  91. end;
  92. procedure TFPCustomTimer.SetEnabled(Value: Boolean);
  93. begin
  94. if Value <> FEnabled then
  95. begin
  96. if Value then
  97. StartTimer
  98. else
  99. StopTimer;
  100. end;
  101. end;
  102. procedure TFPCustomTimer.StartTimer;
  103. begin
  104. If FEnabled then
  105. Exit;
  106. FEnabled:=True;
  107. FContinue:=True;
  108. If Not (csDesigning in ComponentState) then
  109. FDriver.StartTimer;
  110. end;
  111. procedure TFPCustomTimer.StopTimer;
  112. begin
  113. If Not FEnabled then
  114. Exit;
  115. FEnabled:=False;
  116. FContinue:=False;
  117. FDriver.StopTimer;
  118. end;
  119. procedure TFPCustomTimer.Timer;
  120. begin
  121. { We check on FEnabled: If by any chance a tick comes in after it was
  122. set to false, the user won't notice, since no event is triggered.}
  123. If FEnabled and Assigned(FOnTimer) then
  124. FOnTimer(Self);
  125. end;
  126. { ---------------------------------------------------------------------
  127. TFPTimerDriver
  128. ---------------------------------------------------------------------}
  129. Constructor TFPTimerDriver.Create(ATimer : TFPCustomTimer);
  130. begin
  131. FTimer:=ATimer;
  132. end;
  133. { ---------------------------------------------------------------------
  134. Default implementation. Threaded timer, one thread per timer.
  135. ---------------------------------------------------------------------}
  136. Type
  137. TFPTimerThread = class(TThread)
  138. private
  139. FTimerDriver: TFPTimerDriver;
  140. Function Timer : TFPCustomTimer;
  141. public
  142. procedure Execute; override;
  143. constructor CreateTimerThread(ATimerDriver: TFPTimerDriver);
  144. end;
  145. TFPThreadedTimerDriver = Class(TFPTimerDriver)
  146. Private
  147. FThread : TFPTimerThread;
  148. Procedure DoNilTimer(Sender : TObject);
  149. Public
  150. Procedure StartTimer; override;
  151. Procedure StopTimer; override;
  152. end;
  153. function _GetTickCount: Cardinal;
  154. begin
  155. Result := Cardinal(Trunc(Now * 24 * 60 * 60 * 1000));
  156. end;
  157. { ---------------------------------------------------------------------
  158. TFPTimerThread
  159. ---------------------------------------------------------------------}
  160. constructor TFPTimerThread.CreateTimerThread(ATimerDriver: TFPTimerDriver);
  161. begin
  162. inherited Create(True);
  163. FTimerDriver:=ATimerDriver;
  164. FreeOnTerminate := True;
  165. end;
  166. Function TFPTimerThread.Timer : TFPCustomTimer;
  167. begin
  168. If Assigned(FTimerDriver) Then
  169. Result:=FTimerDriver.FTimer
  170. else
  171. Result:=Nil;
  172. end;
  173. procedure TFPTimerThread.Execute;
  174. var
  175. SleepTime: Integer;
  176. S,Last: Cardinal;
  177. T : TFPCustomTimer;
  178. begin
  179. while Not Terminated do
  180. begin
  181. Last := _GetTickCount;
  182. T:=Timer;
  183. If Assigned(T) then
  184. begin
  185. SleepTime := T.FInterval - (_GetTickCount - Last);
  186. if SleepTime < 10 then
  187. SleepTime := 10;
  188. Repeat
  189. S:=5;
  190. If S>SleepTime then
  191. S:=SleepTime;
  192. Sleep(S);
  193. Dec(Sleeptime,S);
  194. until (SleepTime<=0) or Terminated;
  195. T:=Timer;
  196. If Assigned(T) and not terminated then
  197. Synchronize(@T.Timer);
  198. end
  199. else
  200. Terminate;
  201. end;
  202. end;
  203. { ---------------------------------------------------------------------
  204. TFPThreadedTimerDriver
  205. ---------------------------------------------------------------------}
  206. Procedure TFPThreadedTimerDriver.DoNilTimer(Sender : TObject);
  207. begin
  208. FThread:=Nil;
  209. end;
  210. Procedure TFPThreadedTimerDriver.StartTimer;
  211. begin
  212. FThread:=TFPTimerThread.CreateTimerThread(Self);
  213. FThread.OnTerminate:=@DoNilTimer;
  214. FThread.Start;
  215. end;
  216. Procedure TFPThreadedTimerDriver.StopTimer;
  217. begin
  218. FThread.FTimerDriver:=Nil;
  219. FThread.Terminate; // Will free itself.
  220. CheckSynchronize; // make sure thread is not stuck at synchronize call.
  221. If Assigned(FThread) then
  222. Fthread.WaitFor;
  223. end;
  224. Initialization
  225. DefaultTimerDriverClass:=TFPThreadedTimerDriver;
  226. end.