/** * @file XTPChartDrawThread.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "Common/XTPTypeId.h" #include "Common/Math/XTPMathUtils.h" #include "Common/XTPFramework.h" #include "Common/XTPSynchro.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPApplication.h" #include "Common/Base/XTPWinThread.h" #include "Common/XTPSingleton.h" #include "Common/XTPImageManager.h" #include "Common/XTPSystemHelpers.h" #include "Common/Base/Types/XTPPoint2.h" #include "Common/Base/Types/XTPPoint3.h" #include "Common/Base/Types/XTPSize.h" #include "Common/Base/Types/XTPRect.h" #include "Common/XTPTypeId.h" #include "Chart/Types/XTPChartTypes.h" #include "Chart/XTPChartElement.h" #include "Chart/XTPChartContent.h" #include "Chart/XTPChartControl.h" #include "Chart/Drawing/XTPChartDeviceCommand.h" #include "Chart/Drawing/XTPChartDeviceContext.h" #include "Chart/Drawing/XTPChartDrawThread.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////////////////// // CXTPChartDrawThreadDeviceCommand CXTPChartDrawThreadDeviceCommand::CXTPChartDrawThreadDeviceCommand(CXTPChartDeviceCommand* pCommand) { AddChildCommand(pCommand); m_dwRef = 1; } CXTPChartDrawThreadDeviceCommand::~CXTPChartDrawThreadDeviceCommand() { } void CXTPChartDrawThreadDeviceCommand::AddRef() { InterlockedIncrement(&m_dwRef); } void CXTPChartDrawThreadDeviceCommand::Release() { if (m_dwRef == 0) return; LONG lResult = InterlockedDecrement(&m_dwRef); if (lResult == 0) { delete this; } } ////////////////////////////////////////////////////////////////////////// // CXTPChartDrawThread IMPLEMENT_DYNCREATE(CXTPChartDrawThread, CXTPWinThread) CXTPChartDrawThread::CXTPChartDrawThread() { m_pCommand = NULL; m_pControl = NULL; m_szImage = CSize(0, 0); m_bImageReady = FALSE; ::InitializeCriticalSection(&m_cs); m_dwMonitorEvents[0] = CreateEvent(NULL, TRUE, FALSE, 0); // Path was changed event. m_dwMonitorEvents[1] = CreateEvent(NULL, TRUE, FALSE, 0); // Stop notifications event. } CXTPChartDrawThread::~CXTPChartDrawThread() { CloseHandle(m_dwMonitorEvents[0]); CloseHandle(m_dwMonitorEvents[1]); SAFE_RELEASE(m_pCommand); ::DeleteCriticalSection(&m_cs); } void CXTPChartDrawThread::StopNotifications() { SetEvent(m_dwMonitorEvents[1]); WaitForSingleObject(m_hThread, INFINITE); } void CXTPChartDrawThread::StartDraw(CSize sz, CXTPChartDrawThreadDeviceCommand* pCommand) { CXTPLockGuard lock(m_cs); _ASSERTE(pCommand); m_bImageReady = FALSE; m_szImage = sz; SAFE_RELEASE(m_pCommand); m_pCommand = pCommand; m_pCommand->AddRef(); SetEvent(m_dwMonitorEvents[0]); } BOOL CXTPChartDrawThread::MonitorNotifications() { BOOL bContinueThread = TRUE; BOOL bConinueNotifications = TRUE; while (bConinueNotifications) { // Wait for notification. DWORD dwWaitStatus = ::WaitForMultipleObjects(_countof(m_dwMonitorEvents), m_dwMonitorEvents, FALSE, INFINITE); switch (dwWaitStatus) { case WAIT_OBJECT_0: ::ResetEvent(m_dwMonitorEvents[0]); DrawContent(); break; case WAIT_OBJECT_0 + 1: bContinueThread = FALSE; bConinueNotifications = FALSE; break; } } return bContinueThread; } BOOL CXTPChartDrawThread::InitInstance() { return TRUE; } int CXTPChartDrawThread::Run() { BOOL bContinueThread = TRUE; while (bContinueThread) { bContinueThread = MonitorNotifications(); } return 0; } void CXTPChartDrawThread::DrawContent() { CXTPLockGuard lock(m_cs); CXTPChartDrawThreadDeviceCommand* pCommand = m_pCommand; m_pCommand = NULL; lock.UnLockThread(); CDC memDC; memDC.CreateCompatibleDC(NULL); m_bmpCache.DeleteObject(); m_bmpCache.Attach(CXTPImageManager::Create32BPPDIBSection(0, m_szImage.cx, m_szImage.cy, 0)); CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache); { CXTPChartDeviceContext* pDC = m_pControl->GetContent()->CreateDeviceContext( m_pControl, memDC, CRect(0, 0, m_szImage.cx, m_szImage.cy), FALSE); pDC->Execute(pCommand); delete pDC; } memDC.SelectObject(pOldBitmap); lock.LockThread(); pCommand->Release(); if (m_pCommand == NULL) { m_bImageReady = TRUE; if (m_pControl->GetSafeHwnd()) m_pControl->Invalidate(FALSE); } // Unlocked in destructor }