//======================================================================================================================
//=== Headers ===
//======================================================================================================================
#include "DNA/config_platform.h"
#if (DNA_OS != DNA_OS_WINDOWS)
# error Source file incompatible with target operating system.
#else
#include "DNA/Video/CDisplayMonitorManager.h"
#include "DNA/Geometry/Point.h"
#include "DNA/CStringUtils.h"
#include "DNA/Video/CDisplayMonitor.h"
namespace DNA {
namespace Video {
using std::vector;
using DNA::Geometry::Point;
using DNA::Geometry::Rect;
//======================================================================================================================
//=== Global Functions ===
//======================================================================================================================
//-------------------------------------------------------------------------------------------------- MonitorEnumProc ---
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
//--------------------------------------------------------------------------------------------------
// Store enumeration result in the MonitorEnumProcResult vector pointed to by the dwData parameter.
//--------------------------------------------------------------------------------------------------
MonitorEnumProcResult result;
result.Handle = hMonitor;
result.DeviceContext = hdcMonitor;
result.Rect = *lprcMonitor;
((vector<MonitorEnumProcResult>*)dwData)->push_back(result);
//-----------------------
// Continue enumerating.
//-----------------------
return TRUE;
}
//======================================================================================================================
//=== Static Fields CDisplayMonitorManager_Windows ===
//======================================================================================================================
CDisplayMonitorManager_Windows* CDisplayMonitorManager_Windows::_Instance = NULL;
//======================================================================================================================
//=== Construction & Destruction DisplayMonitorManager_Windows ===
//======================================================================================================================
//-------------------------------------------------------------------------------------------- (Default) Constructor ---
CDisplayMonitorManager_Windows::CDisplayMonitorManager_Windows()
{
//---------------------------
// Set the instance pointer.
//---------------------------
_Instance = this;
//---------------------------
// Set initial field values.
//---------------------------
_HasMultiMonitorSupport = FALSE;
_IsInitialized = FALSE;
}
//------------------------------------------------------------------------------------------------------- Destructor ---
CDisplayMonitorManager_Windows::~CDisplayMonitorManager_Windows()
{
//------------------------------------------------------
// Ensure the display monitor manager is uninitialized.
//------------------------------------------------------
if (_IsInitialized)
{
Uninitialize();
}
//-----------------------------
// Clear the instance pointer.
//-----------------------------
_Instance = NULL;
}
//======================================================================================================================
//=== Methods DisplayMonitorManager, CDisplayMonitorManager_Windows ===
//======================================================================================================================
//--------------------------------------------------------------------------------------------------- CreateInstance ---
CDisplayMonitorManager_Windows* CDisplayMonitorManager_Windows::CreateInstance()
{
if (NULL == _Instance)
{
new CDisplayMonitorManager_Windows();
}
return _Instance;
}
//-------------------------------------------------------------------------------------------------- DestroyInstance ---
void CDisplayMonitorManager_Windows::DestroyInstance()
{
if (NULL != _Instance)
{
delete _Instance;
}
}
//----------------------------------------------------------------------------------------------- GetMonitorByHandle ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByHandle(const void* handle) const
{
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_cur = _Monitors.begin();
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_end = _Monitors.end();
CDisplayMonitor_Windows* displayMonitor;
for (itr_cur; itr_cur != itr_end; itr_cur++)
{
displayMonitor = *itr_cur;
if (displayMonitor->GetHandle() == handle)
{
return displayMonitor;
}
}
return NULL;
}
//------------------------------------------------------------------------------------------------ GetMonitorByIndex ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByIndex(const int32 index) const
{
if ((0 <= index) || ((int32)_Monitors.size() > index))
{
return _Monitors[index];
}
DNA_THROW(Exception, "Index out of range.", "CDisplayMonitorManager_Windows");
}
//------------------------------------------------------------------------------------------------- GetMonitorByName ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByName(const String& name) const
{
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_cur = _Monitors.begin();
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_end = _Monitors.end();
CDisplayMonitor_Windows* displayMonitor;
for (itr_cur; itr_cur != itr_end; ++itr_cur)
{
displayMonitor = *itr_cur;
if (StringUtils::Equals(name, displayMonitor->GetName(), FALSE))
{
return displayMonitor;
}
}
return NULL;
}
//------------------------------------------------------------------------------------------------ GetMonitorByPoint ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByPoint(const DNA::Geometry::Point& point) const
{
if (_HasMultiMonitorSupport)
{
HMONITOR hMonitor = MonitorFromPoint(*(POINT*)&point, MONITOR_DEFAULTTONEAREST);
return GetMonitorByHandle((void*)hMonitor);
}
else
{
return GetPrimaryMonitor();
}
}
//------------------------------------------------------------------------------------------------- GetMonitorByRect ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByRect(const DNA::Geometry::Rect& rect) const
{
if (_HasMultiMonitorSupport)
{
RECT rc;
rc.left = rect.X;
rc.top = rect.Y;
rc.right = rect.X + rect.Width;
rc.bottom = rect.Y + rect.Height;
HMONITOR hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
return GetMonitorByHandle((void*)hMonitor);
}
else
{
return GetPrimaryMonitor();
}
}
//----------------------------------------------------------------------------------------------- GetMonitorByWindow ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetMonitorByWindow(const void* windowHandle) const
{
if (_HasMultiMonitorSupport)
{
HMONITOR hMonitor = MonitorFromWindow((HWND)windowHandle, MONITOR_DEFAULTTONEAREST);
return GetMonitorByHandle((void*)hMonitor);
}
else
{
return GetPrimaryMonitor();
}
}
//-------------------------------------------------------------------------------------------------- GetMonitorCount ---
int32 CDisplayMonitorManager_Windows::GetMonitorCount() const
{
return (int32)_Monitors.size();
}
//------------------------------------------------------------------------------------------------------ GetInstance ---
DisplayMonitorManager* DisplayMonitorManager::GetInstance()
{
return (DisplayMonitorManager*)CDisplayMonitorManager_Windows::_Instance;
}
//------------------------------------------------------------------------------------------- HasMultiMonitorSupport ---
bool CDisplayMonitorManager_Windows::HasMultiMonitorSupport() const
{
return _HasMultiMonitorSupport;
}
//------------------------------------------------------------------------------------------------ GetPrimaryMonitor ---
DisplayMonitor* CDisplayMonitorManager_Windows::GetPrimaryMonitor() const
{
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_cur = _Monitors.begin();
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_end = _Monitors.end();
CDisplayMonitor_Windows* displayMonitor;
for (itr_cur; itr_cur != itr_end; ++itr_cur)
{
displayMonitor = *itr_cur;
if (displayMonitor->IsPrimary())
{
return displayMonitor;
}
}
return NULL;
}
//------------------------------------------------------------------------------------------------------- Initialize ---
void CDisplayMonitorManager_Windows::Initialize()
{
//---------------------------------------
// Nothing to do if already initialized.
//---------------------------------------
if (_IsInitialized)
{
return;
}
//------------------------------------------------------
// Detect whether we have multi-monitor support or not.
//------------------------------------------------------
_HasMultiMonitorSupport = (0 != GetSystemMetrics(SM_CMONITORS));
//-----------------------------------------------------------------------------------------------------------------
// Get available display monitors. If we have multi-monitor support then we need to enumerate the display monitors
// that intersect the device context of the entire screen and add them all to our display monitor collection. If
// we have no multi-monitor support, or if enumeration didn't return anything, we just add the primary monitor.
//-----------------------------------------------------------------------------------------------------------------
if (_HasMultiMonitorSupport)
{
//--------------------------------------
// Get device context for entire sceen.
//--------------------------------------
HDC hdc = GetDC(NULL);
if (NULL == hdc)
{
Uninitialize();
DNA_THROW(Exception, "Could not get device context of entire screen.", "CDisplayMonitorManager_Windows");
}
//------------------------------------------------------------------------------------
// Enumerate display monitors that intersect the device context of the entire screen.
//------------------------------------------------------------------------------------
vector<MonitorEnumProcResult> results;
if (!EnumDisplayMonitors(hdc, NULL, MonitorEnumProc, (LPARAM)&results))
{
ReleaseDC(NULL, hdc);
Uninitialize();
DNA_THROW(Exception, "Could not enumerate the display monitors.", "CDisplayMonitorManager_Windows");
}
//----------------------------------------------------------------------------------------------
// Create and store a CDisplayMonitor_Windows object for each enumerated display monitor. If no
// display monitors were enumerated then we just create and store the primary display monitor.
//----------------------------------------------------------------------------------------------
if (0 < results.size())
{
vector<MonitorEnumProcResult>::const_iterator itr_cur = results.begin();
vector<MonitorEnumProcResult>::const_iterator itr_end = results.end();
const MonitorEnumProcResult* result;
CDisplayMonitor_Windows* displayMonitor;
try
{
for (itr_cur; itr_cur != itr_end; ++itr_cur)
{
result = &(*itr_cur);
displayMonitor = new CDisplayMonitor_Windows(result->Handle, result->DeviceContext);
_Monitors.push_back(displayMonitor);
}
}
catch (const Exception&)
{
ReleaseDC(NULL, hdc);
Uninitialize();
throw;
}
}
//----------------------------------------------
// Release device context of the entire screen.
//----------------------------------------------
ReleaseDC(NULL, hdc);
}
//---------------------------------------------------------------------------------------------------------------
// We have no multi-monitor support or the enumeration didn't return anything. Just add primary display monitor.
//---------------------------------------------------------------------------------------------------------------
if (0 == _Monitors.size())
{
try
{
CDisplayMonitor_Windows* displayMonitor = new CDisplayMonitor_Windows(DNA_PRIMARY_DISPLAYMONITOR, NULL);
_Monitors.push_back(displayMonitor);
}
catch (const Exception&)
{
Uninitialize();
throw;
}
}
//-------------------------------------------------
// The display monitor manager is now initialized.
//-------------------------------------------------
_IsInitialized = TRUE;
}
//---------------------------------------------------------------------------------------------------- IsInitialized ---
bool CDisplayMonitorManager_Windows::IsInitialized() const
{
return _IsInitialized;
}
//----------------------------------------------------------------------------------------------------- Uninitialize ---
void CDisplayMonitorManager_Windows::Uninitialize()
{
//---------------------------------------------------------------------------------------------------------------
// Destroy all display monitor objects. Luckily we're talking about C++ objects and not the physical devices ;).
// BOOM BOOM! "We cannot be held responsible for any damage caused to your system."
//---------------------------------------------------------------------------------------------------------------
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_cur = _Monitors.begin();
std::vector<CDisplayMonitor_Windows*>::const_iterator itr_end = _Monitors.end();
CDisplayMonitor_Windows* displayMonitor;
for (itr_cur; itr_cur != itr_end; ++itr_cur)
{
displayMonitor = *itr_cur;
if (NULL != displayMonitor)
{
delete displayMonitor;
}
}
//------------------
// Clear the lists.
//------------------
_Monitors.clear();
//---------------
// Reset fields.
//---------------
_HasMultiMonitorSupport = FALSE;
//---------------------------------------------------
// The display monitor manager is now uninitialized.
//---------------------------------------------------
_IsInitialized = FALSE;
}
} // namespace Video
} // namespace DNA
#endif // (DNA_OS == DNA_OS_WINDOWS)