text: //---------------------------------------------------------------------------
  /*
  	TVP2 ( T Visual Presenter 2 )  A script authoring tool
  	Copyright (C) 2000-2007 W.Dee <dee@kikyou.info> and contributors
  
  	See details of license at "license.txt"
  */
  //---------------------------------------------------------------------------
  // Script Event Handling and Dispatching
  //---------------------------------------------------------------------------
  #include "tjsCommHead.h"
  
  #include "EventImpl.h"
  #include "MainFormUnit.h"
  #include "ThreadIntf.h"
  #include "TickCount.h"
  #include "TimerIntf.h"
  #include "SysInitIntf.h"
  #include "DebugIntf.h"
  
  
  //---------------------------------------------------------------------------
  // global variables
  //---------------------------------------------------------------------------
  tjs_int TVPContinousHandlerLimitFrequency = 0;
  //---------------------------------------------------------------------------
  static bool TVPOptionsInit = false;
  static void TVPInitOptions()
  {
  	if(TVPOptionsInit) return;
  	TVPOptionsInit = true;
  
  	tTJSVariant val;
  	if( TVPGetCommandLine(TJS_W("-contfreq"), &val) )
  	{
  		TVPContinousHandlerLimitFrequency = (tjs_int)val;
  	}
  
  }
  //---------------------------------------------------------------------------
  
  
  
  
  //---------------------------------------------------------------------------
  // TVPInvokeEvents
  //---------------------------------------------------------------------------
  bool TVPEventInvoked = false;
  void TVPInvokeEvents()
  {
  	if(TVPEventInvoked) return;
  	TVPEventInvoked = true;
  	if(TVPMainForm)
  	{
  		TVPMainForm->InvokeEvents();
  	}
  }
  //---------------------------------------------------------------------------
  
  
  //---------------------------------------------------------------------------
  // TVPEventReceived
  //---------------------------------------------------------------------------
  void TVPEventReceived()
  {
  	TVPEventInvoked = false;
  	TVPMainForm->NotifyEventDelivered();
  }
  //---------------------------------------------------------------------------
  
  
  
  
  //---------------------------------------------------------------------------
  // TVPCallDeliverAllEventsOnIdle
  //---------------------------------------------------------------------------
  void TVPCallDeliverAllEventsOnIdle()
  {
  	if(TVPMainForm)
  	{
  		TVPMainForm->CallDeliverAllEventsOnIdle();
  	}
  }
  //---------------------------------------------------------------------------
  
  
  
  
  
  //---------------------------------------------------------------------------
  // TVPBreathe
  //---------------------------------------------------------------------------
  static bool TVPBreathing = false;
  void TVPBreathe()
  {
  	TVPEventDisabled = true; // not to call TVP events...
  	TVPBreathing = true;
  	try
  	{
  		Application->ProcessMessages(); // do Windows message pumping
  	}
  	catch(...)
  	{
  		TVPBreathing = false;
  		TVPEventDisabled = false;
  		throw;
  	}
  
  	TVPBreathing = false;
  	TVPEventDisabled = false;
  }
  //---------------------------------------------------------------------------
  bool TVPGetBreathing()
  {
  	// return whether now is in event breathing
  	return TVPBreathing;
  }
  //---------------------------------------------------------------------------
  
  
  
  
  //---------------------------------------------------------------------------
  // TVPSystemEventDisabledState
  //---------------------------------------------------------------------------
  void TVPSetSystemEventDisabledState(bool en)
  {
  	TVPMainForm->EventButton->Down = !en;
  	if(!en) TVPDeliverAllEvents();
  }
  //---------------------------------------------------------------------------
  bool TVPGetSystemEventDisabledState()
  {
  	return !TVPMainForm->EventButton->Down;
  }
  //---------------------------------------------------------------------------
  
  
  
  
  
  //---------------------------------------------------------------------------
  // tTVPContinuousHandlerCallLimitThread
  //---------------------------------------------------------------------------
  class tTVPContinuousHandlerCallLimitThread : public tTVPThread
  {
  	tjs_uint64 NextEventTick;
  	tjs_uint64 Interval;
  	tTVPThreadEvent Event;
  	tTJSCriticalSection CS;
  
  	bool Enabled;
  	HWND UtilWindow;
  
  public:
  	tTVPContinuousHandlerCallLimitThread();
  	~tTVPContinuousHandlerCallLimitThread();
  
  protected:
  	void Execute();
  
  	void __fastcall UtilWndProc(Messages::TMessage &Msg)
  	{
  		Msg.Result =  DefWindowProc(UtilWindow, Msg.Msg, Msg.WParam, Msg.LParam);
  	}
  
  public:
  	void SetEnabled(bool enabled);
  
  	void SetInterval(tjs_uint64 interval) { Interval = interval; }
  
  } static * TVPContinuousHandlerCallLimitThread = NULL;
  //---------------------------------------------------------------------------
  
  
  //---------------------------------------------------------------------------
  tTVPContinuousHandlerCallLimitThread::tTVPContinuousHandlerCallLimitThread()
  	 : tTVPThread(true)
  {
  	NextEventTick = 0;
  	Interval = (1<<TVP_SUBMILLI_FRAC_BITS)*1000/60; // default 60Hz
  	Enabled = false;
  #ifdef __BORLANDC__
  	UtilWindow = AllocateHWnd(UtilWndProc);
  #else
  	UtilWindow = AllocateHWnd( EVENT_FUNC1(tTVPContinuousHandlerCallLimitThread, UtilWndProc) );
  #endif
  	Resume();
  }
  //---------------------------------------------------------------------------
  
  
  //---------------------------------------------------------------------------
  tTVPContinuousHandlerCallLimitThread::~tTVPContinuousHandlerCallLimitThread()
  {
  	Terminate();
  	Resume();
  	Event.Set();
  	WaitFor();
  	DeallocateHWnd(UtilWindow);
  }
  //---------------------------------------------------------------------------
  
  
  //---------------------------------------------------------------------------
  void tTVPContinuousHandlerCallLimitThread::Execute()
  {
  	while(!GetTerminated())
  	{
  		tjs_uint64 curtick = TVPGetTickCount() << TVP_SUBMILLI_FRAC_BITS;
  		DWORD sleeptime;
  
  		{	// thread-protected
  			tTJSCriticalSectionHolder holder(CS);
  
  			if(Enabled)
  			{
  				if(NextEventTick <= curtick)
  				{
  					TVPProcessContinuousHandlerEventFlag = true; // set flag
  					::PostMessage(UtilWindow, WM_USER+1, 0, 0);
  						// this will activate main thread' message pump
  					while(NextEventTick <= curtick) NextEventTick += Interval;
  				}
  				tjs_uint64 sleeptime_64 = NextEventTick - curtick;
  				sleeptime = (DWORD)(sleeptime_64 >> TVP_SUBMILLI_FRAC_BITS) +
  						((sleeptime_64 & ((1<<TVP_SUBMILLI_FRAC_BITS)-1))?1:0);
  							// add 1 if fraction exists
  			}
  			else
  			{
  				sleeptime = 10000; // how long to sleep when disabled does not matter
  			}
  
  
  		}	// end-of-thread-protected
  
  		if(sleeptime == 0) sleeptime = 1; // 0 will let thread sleeping forever ...
  		Event.WaitFor(sleeptime);
  	}
  }
  //---------------------------------------------------------------------------
  
  
  //---------------------------------------------------------------------------
  void tTVPContinuousHandlerCallLimitThread::SetEnabled(bool enabled)
  {
  	tTJSCriticalSectionHolder holder(CS);
  
  	Enabled = enabled;
  	if(enabled)
  	{
  		tjs_uint64 curtick = TVPGetTickCount() << TVP_SUBMILLI_FRAC_BITS;
  		NextEventTick = ((curtick + 1) / Interval) * Interval;
  		Event.Set();
  	}
  }
  //---------------------------------------------------------------------------
  
  
  
  //---------------------------------------------------------------------------
  void TVPBeginContinuousEvent()
  {
  	TVPInitOptions();
  	if(TVPContinousHandlerLimitFrequency == 0)
  	{
  		// no limit
  		// this notifies continuous calling of TVPDeliverAllEvents.
  		if(TVPMainForm) TVPMainForm->BeginContinuousEvent();
  	}
  	else
  	{
  		// has limit
  		if(!TVPContinuousHandlerCallLimitThread)
  			TVPContinuousHandlerCallLimitThread = new tTVPContinuousHandlerCallLimitThread();
  		TVPContinuousHandlerCallLimitThread->SetInterval(
  			 (1<<TVP_SUBMILLI_FRAC_BITS)*1000/TVPContinousHandlerLimitFrequency);
  		TVPContinuousHandlerCallLimitThread->SetEnabled(true);
  	}
  }
  //---------------------------------------------------------------------------
  void TVPEndContinuousEvent()
  {
  	if(TVPContinousHandlerLimitFrequency != 0)
  	{
  		// has limit
  		if(TVPContinuousHandlerCallLimitThread)
  			TVPContinuousHandlerCallLimitThread->SetEnabled(false);
  	}
  
  	// anyway
  	if(TVPMainForm) TVPMainForm->EndContinuousEvent();
  }
  //---------------------------------------------------------------------------
  
  
  
  //---------------------------------------------------------------------------
  static void TVPReleaseContinuousHandlerCallLimitThread()
  {
  	if(TVPContinuousHandlerCallLimitThread)
  		delete TVPContinuousHandlerCallLimitThread,
  			TVPContinuousHandlerCallLimitThread = NULL;
  }
  // to release TVPContinuousHandlerCallLimitThread at exit
  static tTVPAtExit TVPTimerThreadUninitAtExit(TVP_ATEXIT_PRI_SHUTDOWN,
  	TVPReleaseContinuousHandlerCallLimitThread);
  //---------------------------------------------------------------------------
  
  
  
  
  