示例#1
0
	void CControlUI::SetMaxHeight(int cy)
	{
		if( m_cxyMax.cy == cy ) return;

		if( cy < 0 ) return; 
		m_cxyMax.cy = cy;
		if( !m_bFloat ) NeedParentUpdate();
		else NeedUpdate();
	}
	void CContainerUI::RemoveAll()
	{
		for( int it = 0; m_bAutoDestroy && it < m_items.GetSize(); it++ ) {
			if( m_bDelayedDestroy && m_pManager ) m_pManager->AddDelayedCleanup(static_cast<CControlUI*>(m_items[it]));             
			else delete static_cast<CControlUI*>(m_items[it]);
		}
		m_items.Empty();
		NeedUpdate();
	}
示例#3
0
void CControlUI::NeedParentUpdate()
{
	if (!m_bInited)
		return;
	if (GetParent())
		GetParent()->NeedUpdate();
	else
		NeedUpdate(); // root only
}
	bool CContainerUI::AddAt(CControlUI* pControl, int iIndex)
	{
		if( pControl == NULL) return false;

		if( m_pManager != NULL ) m_pManager->InitControls(pControl, this);
		if( IsVisible() ) NeedUpdate();
		else pControl->SetInternVisible(false);
		return m_items.InsertAt(iIndex, pControl);
	}
示例#5
0
	void CControlUI::SetMaxWidth(int cx)
	{
		if( m_cxyMax.cx == cx ) return;

		if( cx < 0 ) return; 
		m_cxyMax.cx = cx;
		if( !m_bFloat ) NeedParentUpdate();
		else NeedUpdate();
	}
	bool CContainerUI::SetItemIndex(CControlUI* pControl, int iIndex)
	{
		for( int it = 0; it < m_items.GetSize(); it++ ) {
			if( static_cast<CControlUI*>(m_items[it]) == pControl ) {
				NeedUpdate();            
				m_items.Remove(it);
				return m_items.InsertAt(iIndex, pControl);
			}
		}

		return false;
	}
示例#7
0
	void CControlUI::NeedParentUpdate()
	{
		if( GetParent() ) {
			GetParent()->NeedUpdate();
			GetParent()->Invalidate();
		}
		else {
			NeedUpdate();
		}

		if( m_pManager != NULL ) m_pManager->NeedUpdate();
	}
示例#8
0
    void DiCullNode::DetachAllObjects( void )
    {
        for ( auto itr = mObjects.begin();
            itr != mObjects.end(); ++itr )
        {
            if ((*itr)->GetParentNode() == this)
            {
                (*itr)->NotifyAttached(nullptr);
            }
        }
        mObjects.clear();

        NeedUpdate();
    }
示例#9
0
    void DiCullNode::AttachObject(DiTransUnitPtr obj)
    {
        if (obj->IsAttached())
        {
            DI_WARNING("The object has been attached");
            return;
        }

        obj->NotifyAttached(this);

        mObjects.push_back(obj);

        NeedUpdate();
    }
示例#10
0
    void DiCullNode::AttachObject(DiTransUnitPtr obj)
    {
        if (obj->IsAttached())
        {
            DI_ERROR("The object has been attached");
        }

        obj->NotifyAttached(this);

        DI_ASSERT(!mObjectsByName.contains(obj->GetName()));
        mObjectsByName.insert(ObjectMap::value_type(obj->GetName(), obj));

        NeedUpdate();
    }
示例#11
0
	void CVideoUI::DoRenderSample(DWORD dwColor)
	{
		DWORD* pBits = (DWORD*)m_pBits;
#if _THREAD_SAFE
		::EnterCriticalSection(&m_csLock);
#endif
		for (DWORD i = 0; i < m_dwSize / sizeof(DWORD); i++)
		{
			*pBits++ = dwColor;
		}
#if _THREAD_SAFE
		::LeaveCriticalSection(&m_csLock);
#endif
		NeedUpdate();
	}
示例#12
0
	void CVideoUI::DoRenderSample(void* pData, int nWidth, int nHeight, int nBitCount)
	{
		ASSERT(pData);
		ASSERT(nBitCount == 24 || nBitCount == 32);
		
		if (pData == NULL) return;

		if (nWidth != m_nWidth || nHeight != m_nHeight)
		{
			Init(nWidth, nHeight, nBitCount);
			ASSERT(m_hBitmap);
		}

		if (m_hBitmap == NULL) return;

#if _THREAD_SAFE
		::EnterCriticalSection(&m_csLock);
#endif
		if (nBitCount == 24)
		{
			int nSrcLineByte = WIDTHBYTES(nWidth * 24);
			int nDstLineByte = WIDTHBYTES(nWidth * 32);

			for (int y = 0; y < nHeight; y++)
			{
				BYTE* pSrc = (BYTE*)pData + nSrcLineByte * y;
				BYTE* pDst = m_pBits + nDstLineByte * y;
				for (int x = 0; x < nWidth; x++)
				{
					pDst[0] = pSrc[0];
					pDst[1] = pSrc[1];
					pDst[2] = pSrc[2];
					pDst[3] = 255;

					pSrc += 3;
					pDst += 4;
				}
			}
		}
		else if (nBitCount == 32)
		{
			memcpy(m_pBits, pData, nWidth * nHeight * 4);
		}
#if _THREAD_SAFE
		::LeaveCriticalSection(&m_csLock);
#endif
		NeedUpdate();
	}
	bool CContainerUI::Remove(CControlUI* pControl)
	{
		if( pControl == NULL) return false;

		for( int it = 0; it < m_items.GetSize(); it++ ) {
			if( static_cast<CControlUI*>(m_items[it]) == pControl ) {
				NeedUpdate();
				if( m_bAutoDestroy ) {
					if( m_bDelayedDestroy && m_pManager ) m_pManager->AddDelayedCleanup(pControl);             
					else delete pControl;
				}
				return m_items.Remove(it);
			}
		}
		return false;
	}
示例#14
0
    DiTransUnitPtr DiCullNode::DetachObject( const DiString& name )
    {
        ObjectMap::iterator it = mObjectsByName.find(name);
        if (it == mObjectsByName.end())
        {
            DI_ERROR("Cannot find the object : %s", name.c_str());
        }
        DiTransUnitPtr ret = it->second;
        mObjectsByName.erase(it);
        if (ret->GetParentNode() == this)
        {
            ret->NotifyAttached((DiCullNode*)0);
        }
        NeedUpdate();

        return ret;
    }
示例#15
0
    void DiCullNode::DetachAllObjects( void )
    {
        ObjectMap::iterator itr;
        DiTransUnitPtr ret;
        for ( itr = mObjectsByName.begin(); 
            itr != mObjectsByName.end(); ++itr )
        {
            ret = itr->second;
            if (ret->GetParentNode() == this)
            {
                ret->NotifyAttached((DiCullNode*)0);
            }
        }
        mObjectsByName.clear();

        NeedUpdate();
    }
// returns 0 if no desired settings needed, else returns 1
int ApplyDesiredSettings(CBaseEntity *pListMember)
{
	if (pListMember->m_iLFlags & LF_DODESIRED)
	{
		//ALERT(at_console, "Apply for %s\n", STRING(pListMember->pev->classname));
		pListMember->m_iLFlags &= ~LF_DODESIRED;
	}
	else
	{
		// don't need to apply any desired settings for this entity.
		//ALERT(at_console, "Not apply for %s\n", STRING(pListMember->pev->classname));
		return 0;
	}
	//	ALERT(at_console, "ApplyDesiredSettings for %s \"%s\", pevnt %f, ltime %f, mfnt %f, mpevnt %f, %f\n", STRING(pListMember->pev->classname), STRING(pListMember->pev->targetname), pListMember->pev->nextthink, pListMember->pev->ltime, pListMember->m_fNextThink, pListMember->m_fPevNextThink, pListMember->pev->origin.x);

	if (pListMember->m_iLFlags & LF_DESIRED_ACTION)
	{
		pListMember->m_iLFlags &= ~LF_DESIRED_ACTION;
		pListMember->DesiredAction();
		if (NeedUpdate(pListMember)) SetBits(pListMember->m_pChildMoveWith->m_iLFlags, LF_MERGEPOS);
	}
	if (pListMember->m_iLFlags & (LF_POSTORG | LF_MERGEPOS))
	{
		UTIL_MergePos(pListMember);
	}
	if (pListMember->m_iLFlags & LF_DESIRED_INFO)
	{
		pListMember->m_iLFlags &= ~LF_DESIRED_INFO;
		ALERT(at_debug, "DesiredInfo: pos %f %f %f, vel %f %f %f. Child pos %f %f %f, vel %f %f %f\n\n", pListMember->pev->origin.x, pListMember->pev->origin.y, pListMember->pev->origin.z, pListMember->pev->velocity.x, pListMember->pev->velocity.y, pListMember->pev->velocity.z, pListMember->m_pChildMoveWith->pev->origin.x, pListMember->m_pChildMoveWith->pev->origin.y, pListMember->m_pChildMoveWith->pev->origin.z, pListMember->m_pChildMoveWith->pev->velocity.x, pListMember->m_pChildMoveWith->pev->velocity.y, pListMember->m_pChildMoveWith->pev->velocity.z);
	}
	if (pListMember->m_iLFlags & LF_DESIRED_POSTASSIST)
	{
		pListMember->m_iLFlags &= ~LF_DESIRED_POSTASSIST;
		HandlePostAssist(pListMember);
	}
	if (pListMember->m_iLFlags & LF_DESIRED_THINK)
	{
		pListMember->m_iLFlags &= ~LF_DESIRED_THINK;
		//ALERT(at_console, "DesiredThink %s\n", STRING(pListMember->pev->targetname));
		pListMember->Think();
	}

	return 1;
}
示例#17
0
bool CheckForUpdates()
{
	ERROR_OUTPUT(__func__);
	int nu = NeedUpdate();

	if (nu != UPDATE_NONE)
	{
		if (nu == UPDATE_MCF)
		{
			ERROR_OUTPUT("Updating from MCF.");
			int ret = McfUpdate();	
			
			// desura_update.mcf
			if (FileExists(UPDATEFILE))
				DeleteFile(UPDATEFILE);
				
			if(ret != ERR_USERCANCELED)
				RestartBootloader();
				
			return false;
		}
		else
		{
			ERROR_OUTPUT("Doing FULL update.");
			int ret = FullUpdate();
			
			// desura_update.mcf
			if (FileExists(UPDATEFILE))
				DeleteFile(UPDATEFILE);

			if(ret != ERR_USERCANCELED) // if they didn't cancel
				RestartBootloader();
			return false;
		}
	} 
	else 
	{
		ERROR_OUTPUT("Not doing update.");
	}
	
	return false;
}
示例#18
0
    void DiCullNode::DetachObject(DiTransUnitPtr obj)
    {
        ObjectMap::iterator i, iend;
        iend = mObjectsByName.end();
        for (i = mObjectsByName.begin(); i != iend; ++i)
        {
            if (i->second == obj)
            {
                mObjectsByName.erase(i);
                break;
            }
        }

        if (obj->GetParentNode() == this)
        {
            obj->NotifyAttached((DiCullNode*)0);
        }

        NeedUpdate();
    }
	void CContainerUI::EnableScrollBar(bool bEnableVertical, bool bEnableHorizontal)
	{
		if( bEnableVertical && !m_pVerticalScrollBar ) {
			m_pVerticalScrollBar = new CScrollBarUI;
			m_pVerticalScrollBar->SetOwner(this);
			m_pVerticalScrollBar->SetManager(m_pManager, NULL, false);
			if ( m_pManager ) {
				LPCTSTR pDefaultAttributes = m_pManager->GetDefaultAttributeList(_T("VScrollBar"));
				if( pDefaultAttributes ) {
					m_pVerticalScrollBar->ApplyAttributeList(pDefaultAttributes);
				}
			}
		}
		else if( !bEnableVertical && m_pVerticalScrollBar ) {
			delete m_pVerticalScrollBar;
			m_pVerticalScrollBar = NULL;
		}

		if( bEnableHorizontal && !m_pHorizontalScrollBar ) {
			m_pHorizontalScrollBar = new CScrollBarUI;
			m_pHorizontalScrollBar->SetHorizontal(true);
			m_pHorizontalScrollBar->SetOwner(this);
			m_pHorizontalScrollBar->SetManager(m_pManager, NULL, false);

			if ( m_pManager ) {
				LPCTSTR pDefaultAttributes = m_pManager->GetDefaultAttributeList(_T("HScrollBar"));
				if( pDefaultAttributes ) {
					m_pHorizontalScrollBar->ApplyAttributeList(pDefaultAttributes);
				}
			}
		}
		else if( !bEnableHorizontal && m_pHorizontalScrollBar ) {
			delete m_pHorizontalScrollBar;
			m_pHorizontalScrollBar = NULL;
		}

		NeedUpdate();
	}
示例#20
0
    void DiCullNode::DetachObject(DiTransUnitPtr obj)
    {
        bool found = false;
        for (auto i = mObjects.begin(); i != mObjects.end(); ++i)
        {
            if (*i == obj)
            {
                mObjects.erase(i);
                found = true;
                break;
            }
        }
        
        if (!found)
            return;

        if (obj->GetParentNode() == this)
        {
            obj->NotifyAttached(nullptr);
        }

        NeedUpdate();
    }
示例#21
0
    DiTransUnitPtr DiCullNode::DetachObject( uint32 index )
    {
        if (index < mObjects.size())
        {
            DiTransUnitPtr ret = mObjects[index];
            if (ret->GetParentNode() == this)
            {
                ret->NotifyAttached((DiCullNode*)0);
            }
            
            ObjectMap::iterator i = mObjects.begin() + index;
            mObjects.erase(i);

            NeedUpdate();

            return ret;

        }
        else
        {
            DI_WARNING("Cannot detach object, invalid index");
            return nullptr;
        }
    }
示例#22
0
	void CTileLayoutUI::SetColumns(int nCols)
	{
		if( nCols <= 0 ) return;
		m_nColumns = nCols;
		NeedUpdate();
	}
示例#23
0
 void DiCullNode::AttachSilently(DiTransUnitPtr obj)
 {
     mObjects.push_back(obj);
     
     NeedUpdate();
 }
示例#24
0
bool BootLoader::preLaunchCheck(UTIL::MISC::CMDArgs &args)
{
#ifdef DESURA_OFFICIAL_BUILD
	CheckForBadUninstaller();
#endif

	if (args.hasArg("urllink"))
	{
		std::string a(m_lpCmdLine);

		size_t pos = a.find("-urllink");
		a.replace(pos, 8, "");

		BootLoaderUtil::Restart(a.c_str(), false);
		return false;
	}

#ifdef DESURA_OFFICIAL_BUILD
	if (args.hasArg("testinstall"))
	{
		m_bRetCode = true;
		m_iRetCode = InstallFilesForTest();
		return false;
	}

	if (args.hasArg("testdownload"))
	{
		m_bRetCode = true;
		m_iRetCode = DownloadFilesForTest();
		return false;
	}
#endif

	if (args.hasArg("dumplevel"))
	{
		SetDumpLevel(args.getInt("dumplevel"));
		g_bLockDump = true;
	}

	if (args.hasArg("autostart"))
	{
		//need to wait for service to start
		Sleep(15 * 1000);
		BootLoaderUtil::RestartAsNormal("-wait");
		return false;
	}

#ifdef DESURA_OFFICIAL_BUILD
#ifdef DEBUG
	if (args.hasArg("debugupdater"))
	{
		INT_PTR nResponse = DisplayUpdateWindow(-1);
		return false;
	}

	if (args.hasArg("debuginstall"))
	{
		McfUpdate();
		return false;
	}

	if (args.hasArg("debugdownload"))
	{
		FullUpdate();
		return false;
	}

	if (args.hasArg("debugcheck"))
	{
		CheckInstall();
		return false;
	}
#endif
#endif

	if (args.hasArg("testcrash"))
	{
		BootLoader *ai = nullptr;
		//ai->gcAssertValid();
	}

	unsigned int osid = BootLoaderUtil::GetOSId();

	if (osid == WINDOWS_PRE2000)
	{
		::MessageBox(nullptr, PRODUCT_NAME " needs Windows XP or better to run.", PRODUCT_NAME " Error: Old Windows", MB_OK);
		return false;
	}
	else if (osid == WINDOWS_XP || osid == WINDOWS_XP64)
	{
		m_bHasAdminRights = true;
	}

	if (args.hasArg("admin"))
	{
		m_bHasAdminRights = true;
	}

	//if the wait command is parsed in then we need to wait for all other instances of desura to exit.
	if (args.hasArg("wait"))
	{
		BootLoaderUtil::WaitForOtherInstance(m_hInstance);
	}
	else
	{
		if (BootLoaderUtil::CheckForOtherInstances(m_hInstance))
		{
			sendArgs();
			return false;
		}
		else
		{
			//if windows uninstall software launches desura it will disable its window till it quits.
			//Work around for existing clients
			std::string a(m_lpCmdLine);
			size_t pos = a.find("desura://uninstall/");

			if (pos != std::string::npos)
			{
				a.replace(pos + 9, 9, "remove");
				BootLoaderUtil::RestartAsNormal(a.c_str());
				return false;
			}
		}
	}

#ifdef DESURA_OFFICIAL_BUILD
	if (args.hasArg("forceupdate"))
	{
		if (!m_bHasAdminRights)
		{
			restartAsAdmin(UPDATE_FORCED);
			return false;
		}
		else
		{
			FullUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return false;
		}
	}
#endif


#ifdef _DEBUG
	SetRegValues();
	InstallService();
#else
	int nu = NeedUpdate();

	if (nu != UPDATE_NONE)
	{
		if (nu == UPDATE_MCF)
		{
			Log("Updating from MCF.\n");
			McfUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return false;
		}
		else if (nu == UPDATE_SERVICE_PATH)
		{
			Log("Service update path [%s].\n", g_UpdateReasons[nu]);

			if (ServiceUpdate(true))
				nu = UPDATE_NONE;
		}
	}

	if (nu != UPDATE_NONE)
	{
		if (!m_bHasAdminRights)
		{
			restartAsAdmin(nu);
			return false;
		}
		else if (nu == UPDATE_SERVICE_LOCATION || nu == UPDATE_SERVICE_HASH)
		{
			Log("Service update location [%s].\n", g_UpdateReasons[nu]);
			ServiceUpdate(false);
		}
		else if (nu == UPDATE_SERVICE_DISABLED)
		{
			if (FixServiceDisabled())
				BootLoaderUtil::RestartAsNormal("-wait");

			return false;
		}
		else
		{
			Log("Full update [%s].\n", g_UpdateReasons[nu]);
			FullUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return false;
		}
	}

	if (m_bHasAdminRights && !(osid == WINDOWS_XP || osid == WINDOWS_XP64))
	{
		BootLoaderUtil::RestartAsNormal("-wait");
		return false;
	}
#endif

	return true;
}
	void Finish()
	{
		m_bFinished = true;
		NeedUpdate(false);
	}
示例#26
0
BOOL BootLoader::InitInstance()
{
	BootLoaderUtil::CMDArgs args(m_lpCmdLine);
	
	if (args.hasArg("waitfordebugger"))
		BootLoaderUtil::WaitForDebugger();

	BootLoaderUtil::SetCurrentDir();
	CWinApp::InitInstance();

#ifdef DESURA_NONGPL_BUILD
	CheckForBadUninstaller();
#endif

	if (args.hasArg("urllink"))
	{
		std::string a(m_lpCmdLine);

		size_t pos = a.find("-urllink");
		a.replace(pos, 8, "");

		BootLoaderUtil::Restart(a.c_str(), false);
		return FALSE;
	}

#ifdef DESURA_NONGPL_BUILD
	if (args.hasArg("testinstall"))
	{
		m_bRetCode = true;
		m_iRetCode = InstallFilesForTest();
		return FALSE;
	}

	if (args.hasArg("testdownload"))
	{
		m_bRetCode = true;
		m_iRetCode = DownloadFilesForTest();
		return FALSE;
	}
#endif
	
	if (args.hasArg("dumplevel"))
	{
		SetDumpLevel(args.getInt("dumplevel"));
		g_bLockDump = true;
	}

	if (args.hasArg("autostart"))
	{
		//need to wait for service to start
		Sleep(15*1000);
		BootLoaderUtil::RestartAsNormal("-wait");
		return FALSE;
	}

#ifdef DESURA_NONGPL_BUILD
#ifdef DEBUG
	if (args.hasArg("debugupdater"))
	{
		INT_PTR nResponse = DisplayUpdateWindow(-1);
		return FALSE;
	}

	if (args.hasArg("debuginstall"))
	{
		McfUpdate();
		return FALSE;
	}

	if (args.hasArg("debugdownload"))
	{
		FullUpdate();
		return FALSE;
	}

	if (args.hasArg("debugcheck"))
	{
		CheckInstall();
		return FALSE;
	}
#endif
#endif

	if (args.hasArg("testcrash"))
	{
		BootLoader *ai = NULL;
		ai->AssertValid();
	}

	unsigned int osid = BootLoaderUtil::GetOSId();

	if (osid == WINDOWS_PRE2000)
	{
		::MessageBox(NULL, "Desura needs Windows xp or better to run.", "Desura Error: Old Windows", MB_OK);
		return FALSE;
	}
	else if (osid == WINDOWS_XP || osid == WINDOWS_XP64)
	{
		hasAdminRights = true;
	}

	if (args.hasArg("admin"))
	{
		hasAdminRights = true;
	}

	//if the wait command is parsed in then we need to wait for all other instances of desura to exit.
	if (args.hasArg("wait"))
	{
		BootLoaderUtil::WaitForOtherInstance(m_hInstance);
	}
	else
	{
		if (BootLoaderUtil::CheckForOtherInstances(m_hInstance))
		{
			sendArgs();
			return FALSE;
		}
		else
		{
			//if windows uninstall software launches desura it will disable its window till it quits.
			//Work around for existing clients
			std::string a(m_lpCmdLine);
			size_t pos = a.find("desura://uninstall/");

			if (pos != std::string::npos)
			{
				a.replace(pos+9, 9, "remove");
				BootLoaderUtil::RestartAsNormal(a.c_str());
				return FALSE;
			}
		}
	}

#ifdef DESURA_NONGPL_BUILD
	if (args.hasArg("forceupdate"))
	{
		if (!hasAdminRights)
		{
			restartAsAdmin(UPDATE_FORCED);
			return FALSE;
		}
		else
		{
			FullUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return FALSE;
		}
	}
#endif
	

#ifdef _DEBUG
	SetRegValues();
	InstallService();
#else
	int nu = NeedUpdate();

	if (nu != UPDATE_NONE)
	{
		if (nu == UPDATE_MCF)
		{
			Log("Updating from MCF.\n");
			McfUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return FALSE;
		}
		else if (nu == UPDATE_SERVICE_PATH)
		{
			Log("Service update path [%s].\n", g_UpdateReasons[nu]);

			if (ServiceUpdate(true))
				nu = UPDATE_NONE;
		}
	}

	if (nu != UPDATE_NONE)
	{
		if (!hasAdminRights)
		{
			restartAsAdmin(nu);
			return FALSE;
		}
		else if (nu == UPDATE_SERVICE_LOCATION || nu == UPDATE_SERVICE_HASH)
		{
			Log("Service update location [%s].\n", g_UpdateReasons[nu]);
			ServiceUpdate(false);
		}
		else if (nu == UPDATE_SERVICE_DISABLED)
		{
			if (FixServiceDisabled())
				BootLoaderUtil::RestartAsNormal("-wait");

			return FALSE;
		}
		else
		{
			Log("Full update [%s].\n", g_UpdateReasons[nu]);
			FullUpdate();
			BootLoaderUtil::RestartAsNormal("-wait");
			return FALSE;
		}
	}

	if (hasAdminRights && !(osid == WINDOWS_XP || osid == WINDOWS_XP64))
	{
		BootLoaderUtil::RestartAsNormal("-wait");
		return FALSE;
	}
#endif

	loadUICore();

	if (!m_pUICore)
		return FALSE;

	bool res = m_pUICore->initWxWidgets(m_hInstance, m_nCmdShow, args.getArgc(), const_cast<char**>(args.getArgv()));

	if (res)
		m_pMainWnd = new BootLoaderUtil::CDummyWindow(m_pUICore->getHWND());

	return res?TRUE:FALSE;
}
void cSearchTimerThread::Action(void)
{
   if (EPGSearchConfig.useExternalSVDRP && !cSVDRPClient::SVDRPSendCmd)
   {
      LogFile.eSysLog("ERROR - SVDRPSend script not specified or does not exist (use -f option)");
      return;
   }
   SetPriority(SEARCHTIMER_NICE);

   m_Active = true;
   // let VDR do its startup
   if (!cPluginEpgsearch::VDR_readyafterStartup)
     LogFile.Log(2, "SearchTimerThread: waiting for VDR to become ready...");
   while(Running() && m_Active && !cPluginEpgsearch::VDR_readyafterStartup)
      Wait.Wait(1000);

   time_t nextUpdate = time(NULL);
   while (m_Active && Running())
   {
      time_t now = time(NULL);
      bool needUpdate = NeedUpdate();
      if (now >= nextUpdate || needUpdate)
      {
	 justRunning = true;

	 if (updateForced & UPDS_WITH_EPGSCAN)
	 {
  	    LogFile.Log(1,"starting EPG scan before search timer update");
	    EITScanner.ForceScan();
	    do
	    {
	       Wait.Wait(1000);
	    }
	    while(EITScanner.Active() && m_Active && Running());
  	    LogFile.Log(1,"EPG scan finished");
	 }
         if (Timers.BeingEdited())
         {
            Wait.Wait(1000);
            continue;
         }
         LogFile.iSysLog("search timer update started");

         UserVars.ResetCache(); // reset internal cache of user vars
         cTimerObjList* pOutdatedTimers = NULL;

         // for thread safeness we work with a copy of the current searches,
         // because SVDRP would not work if the main thread would be locked
         cSearchExts* localSearchExts = SearchExts.Clone();
	 localSearchExts->SortBy(CompareSearchExtPrioDescTerm);
         cSearchExt *searchExt = localSearchExts->First();
         // reset announcelist
         announceList.Clear();
         while (searchExt && m_Active && Running())
         {
	   if (!searchExt->IsActiveAt(now))
            {
               searchExt = localSearchExts->Next(searchExt);
               continue;
            }
            pOutdatedTimers = searchExt->GetTimerList(pOutdatedTimers);

            cSearchResults* pSearchResults = searchExt->Run(-1, true);
            if (!pSearchResults)
            {
               searchExt = localSearchExts->Next(searchExt);
               continue;
            }
            pSearchResults->SortBy(CompareEventTime);

            if (searchExt->pauseOnNrRecordings > 0)
               searchExt->CheckExistingRecordings(pSearchResults);

            for (cSearchResult* pResultObj = pSearchResults->First();
                 pResultObj;
                 pResultObj = pSearchResults->Next(pResultObj))
            {
               if (!Running()) break;
               const cEvent* pEvent = pResultObj->event;
               if (!pEvent)
                  continue;

               cChannel *channel = Channels.GetByChannelID(pEvent->ChannelID(), true, true);
               if (!channel)
                  continue;

               int index = 0;
               cTimer *timer = new cTimer(pEvent);

               // create the file
               char* file = NULL;
               if ((file = searchExt->BuildFile(pEvent)) != NULL)
               {
                  while(strstr(file, "!^pipe^!")) file = strreplace(file, "!^pipe^!", "|"); // revert the translation of '|' in BuildFile
                  if (strstr(file, "!^invalid^!") || strlen(file) == 0)
                  {
                     LogFile.eSysLog("Skipping timer due to invalid or empty filename");
                     if (time(NULL) <= timer->StopTime())
                        pOutdatedTimers->DelTimer(timer);
                     delete timer;
                     free(file);
                     continue;
                  }
                  timer->SetFile(file);
                  free(file);
               }
               int Priority = searchExt->Priority;
               int Lifetime = searchExt->Lifetime;

               // search for an already existing timer
               bool bTimesMatchExactly = false;
               cTimer *t = GetTimer(searchExt, pEvent, bTimesMatchExactly);

               char* Summary = NULL;
	       uint timerMod = tmNoChange;

               if (t)
               { // already exists
                  pOutdatedTimers->DelTimer(t);

                  if (!t->HasFlags(tfActive))
                  { // do not update inactive timers
                     LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) not active - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                     delete timer;
                     continue;
                  }

                  int triggerID = TriggeredFromSearchTimerID(t);
                  if (!pResultObj->needsTimer && !t->Recording()) // not needed
                  {
                     if (triggerID == searchExt->ID)
                     {
                        LogFile.Log(1,"delete timer for '%s~%s' (%s - %s, channel %d)", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                        RemoveTimer(t, pEvent);
                     }
                     else if (triggerID == -1) //manual timer
                     {
                        LogFile.Log(2,"keep obsolete timer for '%s~%s' (%s - %s, channel %d) - was manually created", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                     }
                     delete timer;
                     continue;
                  }
                  if (TimerWasModified(t)) // don't touch timer modified by user
                  {
                     LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) modified by user - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                     delete timer;
                     continue;
                  }
                  if (triggerID > -1 && triggerID != searchExt->ID)
                  {
                     LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) already created by search id %d - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), triggerID);
                     delete timer;
                     continue;
                  }

                  char* pFile = NULL; // File is prepared for svdrp, so prepare t->File for comparision too
                  msprintf(&pFile, "%s", t->File());
                  pFile = strreplace(pFile, ':', '|');
                  pFile = strreplace(pFile, " ~", "~");
                  pFile = strreplace(pFile, "~ ", "~");

                  Summary =  SummaryExtended(searchExt, t, pEvent);

                  if (bTimesMatchExactly && strcmp(pFile, timer->File()) == 0
                      && (t->Aux() != NULL && strcmp(t->Aux(), Summary) == 0)
                     )
                  { // dir, title, episode name and summary have not changed
                     if (Summary) free(Summary);
                     delete timer;
                     free(pFile);
                     continue;
                  }
                  else
                  {
		    if (!bTimesMatchExactly) timerMod = (uint)timerMod | tmStartStop;
		    if (strcmp(pFile, timer->File()) != 0) timerMod |= tmFile;
		    if (t->Aux() != NULL && strcmp(t->Aux(), Summary) != 0)
		      {
			char* oldEventID = GetAuxValue(t, "eventid");
			char* newEventID = GetAuxValue(Summary, "eventid");
			if (oldEventID && newEventID && strcmp(oldEventID, newEventID) != 0)
			  timerMod |= tmAuxEventID;
			free(oldEventID);
			free(newEventID);
		      }

		    if (LogFile.Level() >= 3) // output reasons for a timer modification
		      {
                        if (timerMod & tmStartStop)
			  LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : start/stop has changed", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                        if (timerMod & tmFile)
			  LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : title and/or episdode has changed (old: %s, new: %s", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), timer?timer->File():"", pFile);
                        if (timerMod & tmAuxEventID)
			  LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : aux info for event id has changed", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
		      }
		    index = t->Index()+1;
		    Priority = t->Priority();
		    Lifetime = t->Lifetime();
                  }
                  free(pFile);

                  if (t->Recording() && t->StopTime() == timer->StopTime())
                  {
                     // only update recording timers if stop time has changed, since all other settings can't be modified
                     LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) already recording - no changes possible", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
                     delete timer;
                     continue;
                  }
               }
               else
               {
                  if (!pResultObj->needsTimer)
                  {
                     delete timer;
                     continue;
                  }
               }

               if (searchExt->action == searchTimerActionAnnounceViaOSD)
               {
                  if (t || // timer already exists or
                      NoAnnounces.InList(pEvent) || // announcement not wanted anymore or
                      (EPGSearchConfig.noAnnounceWhileReplay &&
		       cDevice::PrimaryDevice()->Replaying() &&
		       !(updateForced & UPDS_WITH_OSD))  // no announce while replay within automatic updates
                     )
                  {
                     if (Summary) free(Summary);
                     delete timer;
                     continue;
                  }
		  if (!announceList.Lookup(pEvent))
		    announceList.Add(new cSearchResult(pEvent, searchExt->ID));

                  if (Summary) free(Summary);
                  delete timer;
                  continue;
               }

               if (searchExt->action == searchTimerActionAnnounceViaMail)
               {
                  if (t || // timer already exists or
                      NoAnnounces.InList(pEvent) ||
		      pEvent->StartTime() < time(NULL)) // already started?
                  {
                     if (Summary) free(Summary);
                     delete timer;
                     continue;
                  }
		  mailNotifier.AddAnnounceEventNotification(pEvent->EventID(), pEvent->ChannelID(), searchExt->ID);

                  if (Summary) free(Summary);
                  delete timer;
                  continue;
               }
               if (searchExt->action == searchTimerActionSwitchOnly ||
		   searchExt->action == searchTimerActionAnnounceAndSwitch) // add to switch list
               {
                  time_t now = time(NULL);
                  if (now < pEvent->StartTime())
                  {
                     if (!SwitchTimers.InSwitchList(pEvent))
                     {
                        cMutexLock SwitchTimersLock(&SwitchTimers);
			int mode = 0;
			if (searchExt->action == searchTimerActionAnnounceAndSwitch)
			  mode = 2;
			LogFile.Log(3,"adding switch timer event for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
                        SwitchTimers.Add(new cSwitchTimer(pEvent, searchExt->switchMinsBefore, mode,
							  searchExt->unmuteSoundOnSwitch));
                        SwitchTimers.Save();
                        cSwitchTimerThread::Init();
                     }
                  }
                  if (Summary) free(Summary);
                  delete timer;
                  continue;
               }

               if (AddModTimer(timer, index, searchExt, pEvent, Priority, Lifetime, Summary, timerMod))
               {
                  if (index == 0)
                     LogFile.Log(1,"added timer for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
                  else
                     LogFile.Log(1,"modified timer %d for '%s~%s' (%s - %s); search timer: '%s'", index, pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
               }
               if (Summary) free(Summary);
               delete timer;
            }
	    delete pSearchResults;
            searchExt = localSearchExts->Next(searchExt);
         }

         if (localSearchExts) delete localSearchExts;

         if (pOutdatedTimers)
         {
            if (pOutdatedTimers->Count() > 0)
            {
               LogFile.Log(1,"removing outdated timers");
               for(cTimerObj *tObj = pOutdatedTimers->First(); tObj; tObj = pOutdatedTimers->Next(tObj))
               {
                  cTimer* t = tObj->timer;
                  // timer could have been deleted meanwhile, so check if its still there
                  bool found = false;
                  for(cTimer* checkT = Timers.First(); checkT; checkT = Timers.Next(checkT))
                     if (checkT == t)
                     {
                        found = true;
                        break;
                     }
                  if (!found) continue;

                  if (TimerWasModified(t)) continue;
                  if (!t->Event()) continue; // if there is no event, we keep the timer, since EPG could have been cleared
                  if (time(NULL) > t->StopTime()) continue; // if this timer has (just) finished, let VDR do the cleanup
                  if (t->Recording()) continue; // do not remove recording timers
                  LogFile.Log(1,"delete timer for '%s' (%s, channel %s)", t->File(), DAYDATETIME(t->StartTime()), CHANNELNAME(t->Channel()));
                  RemoveTimer(t, t->Event());
               }
               LogFile.Log(1,"removing outdated timers - done");
            }
            delete pOutdatedTimers;
         }

         TimersDone.ClearOutdated();
         TimersDone.Save();

         if (announceList.Count() > 0)
         {
	   cString msgfmt = cString::sprintf(tr("%d new broadcast(s) found! Show them?"), announceList.Count());
	   if (SendMsg(msgfmt, true,7) == kOk)
	     {
	       m_plugin->showAnnounces = true;
	       cRemote::CallPlugin("epgsearch");
	     }
         }

	 CheckEPGHours();

         LogFile.iSysLog("search timer update finished");

         // check for conflicts
         if (EPGSearchConfig.checkTimerConflictsAfterUpdate && m_Active && Running())
         {
            LogFile.iSysLog("check for timer conflicts");
            cConflictCheck conflictCheck;
            conflictCheck.Check();

            if (conflictCheck.relevantConflicts > 0)
            {
               if (EPGSearchConfig.sendMailOnConflicts)
               {
                  cMailConflictNotifier mailNotifier;
                  mailNotifier.SendConflictNotifications(conflictCheck);
               }

 	       conflictCheck.EvaluateConflCheckCmd();

               cString msgfmt = cString::sprintf(tr("%d timer conflict(s)! First at %s. Show them?"),
						 conflictCheck.relevantConflicts,
						 *DateTime(conflictCheck.nextRelevantConflictDate));
               bool doMessage = EPGSearchConfig.noConflMsgWhileReplay == 0 ||
                  !cDevice::PrimaryDevice()->Replaying() ||
                  conflictCheck.nextRelevantConflictDate - now < 2*60*60 ||
		 (updateForced & UPDS_WITH_OSD);
               if (doMessage && SendMsg(msgfmt, true,7) == kOk)
               {
                  m_plugin->showConflicts = true;
                  cRemote::CallPlugin("epgsearch");
               }
            }

            LogFile.iSysLog("check for timer conflicts - done");
         }

         // delete expired recordings
         CheckExpiredRecs();

         // check for updates for manual timers
         CheckManualTimers();

	 if (m_Active)
	   mailNotifier.SendUpdateNotifications();

         if ((updateForced & UPDS_WITH_OSD) && m_Active)
            SendMsg(tr("Search timer update done!"));

         // reset service call flag
         updateForced = 0;

         m_lastUpdate = time(NULL);
         nextUpdate = long(m_lastUpdate/60)*60 + (EPGSearchConfig.UpdateIntervall * 60);
	 justRunning = false;
      }
      if (m_Active && Running())
	Wait.Wait(2000); // to avoid high system load if time%30==0
      while (Running() && m_Active && !NeedUpdate() && time(NULL)%30 != 0) // sync heart beat to a multiple of 5secs
         Wait.Wait(1000);
   };
   LogFile.iSysLog("Leaving search timer thread");
}
	void CContainerUI::SetInset(RECT rcInset)
	{
		m_rcInset = rcInset;
		NeedUpdate();
	}
	void CContainerUI::SetChildPadding(int iPadding)
	{
		m_iChildPadding = iPadding;
		NeedUpdate();
	}