nana/source/gui/screen.cpp
2015-02-04 10:26:08 +08:00

194 lines
4.9 KiB
C++

/*
* Screen Informations
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/screen.cpp
*/
#include <nana/gui/screen.hpp>
#include <vector>
#include <memory>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/programming_interface.hpp>
#if defined(NANA_WINDOWS)
#include <windows.h>
#endif
namespace nana
{
//class display
class real_display
: public display
{
public:
real_display(std::size_t number)
: index_(number)
{
#if defined(NANA_WINDOWS)
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
if (::EnumDisplayDevices(nullptr, static_cast<DWORD>(index_), &disp, 0))
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
area_.x = mode.dmPosition.x;
area_.y = mode.dmPosition.y;
area_.width = mode.dmPelsWidth;
area_.height = mode.dmPelsHeight;
return;
}
}
#else
if (0 == index_)
{
area_ = detail::native_interface::primary_monitor_size();
return;
}
#endif
throw std::invalid_argument("Nana.Screen: Invalid monitor index.");
}
real_display(std::size_t number, const ::nana::rectangle& r)
: index_(number), area_(r)
{
}
public:
//Implementation of display
std::size_t get_index() const override
{
return index_;
}
const ::nana::rectangle& area() const override
{
return area_;
}
private:
const std::size_t index_;
::nana::rectangle area_;
};
//class screen
::nana::size screen::desktop_size()
{
#if defined(NANA_WINDOWS)
auto w = static_cast<size::value_type>(::GetSystemMetrics(SM_CXVIRTUALSCREEN));
auto h = static_cast<size::value_type>(::GetSystemMetrics(SM_CYVIRTUALSCREEN));
return{w, h};
#else
return ::nana::detail::native_interface::primary_monitor_size();
#endif
}
::nana::size screen::primary_monitor_size()
{
return ::nana::detail::native_interface::primary_monitor_size();
}
std::shared_ptr<display> screen::from_point(const point& pos)
{
#if defined(NANA_WINDOWS)
typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD);
MonitorFromPointT mfp = reinterpret_cast<MonitorFromPointT>(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "MonitorFromPoint"));
if (mfp)
{
POINT native_pos = { pos.x, pos.y };
HMONITOR monitor = mfp(native_pos, 2 /*MONITOR_DEFAULTTONEAREST*/);
MONITORINFO mi;
mi.cbSize = sizeof mi;
if (::GetMonitorInfo(monitor, &mi))
{
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top &&
(static_cast<int>(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) &&
(static_cast<int>(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top))
{
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
}
}
}
#endif
return screen().get_primary();
}
std::shared_ptr<display> screen::from_window(window wd)
{
::nana::point pos;
API::calc_screen_point(wd, pos);
return from_point(pos);
}
std::size_t screen::count() const
{
#if defined(NANA_WINDOWS)
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0));
return static_cast<std::size_t>(index - 1);
#else
return 1;
#endif
}
std::shared_ptr<display> screen::get_display(std::size_t index) const
{
return std::make_shared<real_display>(index);
}
std::shared_ptr<display> screen::get_primary() const
{
#if defined(NANA_WINDOWS)
//return rectangle(mi.rcWork.left, mi.rcWork.top,
// mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top);
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0)
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
#endif
return std::make_shared<real_display>(0);
}
void screen::for_each(std::function<void(display&)> fn) const
{
auto n = count();
for (decltype(n) i = 0; i < n; ++i)
{
real_display disp(i);
fn(disp);
}
}
//end class screen
}