35#include <X11/extensions/Xrandr.h>
40#include <ShellScalingApi.h>
44#include <CoreGraphics/CoreGraphics.h>
47size_t g_num_monitors = 0;
48size_t g_current_monitor = 0;
49double g_current_monitor_dip_px_ratio = 1.0;
50std::vector<OCPN_MonitorInfo> g_monitor_info;
54BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
55 LPRECT lprcMonitor, LPARAM dwData) {
56 MONITORINFOEX monitorInfo;
57 monitorInfo.cbSize =
sizeof(MONITORINFOEX);
58 if (GetMonitorInfo(hMonitor, &monitorInfo)) {
59 UINT rawdpiX, rawdpiY;
60 UINT effectivedpiX, effectivedpiY;
63 HRESULT hr = GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &effectivedpiX,
66 WARNING_LOG <<
"GetDpiForMonitor MDT_EFFECTIVE_DPI failed, falling back "
71 hr = GetDpiForMonitor(hMonitor, MDT_RAW_DPI, &rawdpiX, &rawdpiY);
72 if (!SUCCEEDED(hr) || rawdpiX == 0 || rawdpiY == 0) {
73 WARNING_LOG <<
"GetDpiForMonitor MDT_RAW_DPI failed, falling back to "
76 rawdpiX = effectivedpiX;
77 rawdpiY = effectivedpiY;
79 DEBUG_LOG <<
"Raw DPI " << rawdpiX <<
"x" << rawdpiY;
80 DEBUG_LOG <<
"Effective DPI " << effectivedpiX <<
"x" << effectivedpiY;
81 DEVICE_SCALE_FACTOR scaleFactor;
82 hr = GetScaleFactorForMonitor(hMonitor, &scaleFactor);
83 if (!SUCCEEDED(hr) || scaleFactor == DEVICE_SCALE_FACTOR_INVALID) {
84 WARNING_LOG <<
"GetScaleFactorForMonitor failed, falling back to 100";
85 scaleFactor = SCALE_100_PERCENT;
88 auto width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
89 auto height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
90 auto mmx = width * 25.4 / rawdpiX;
91 auto mmy = height * 25.4 / rawdpiY;
92 std::wstring ws(monitorInfo.szDevice);
93 DEBUG_LOG <<
"Display " << hMonitor <<
":";
94 DEBUG_LOG <<
" Monitor Name: " << std::string(ws.begin(), ws.end());
95 DEBUG_LOG <<
" Resolution: " << width <<
"x" << height;
96 DEBUG_LOG <<
" Physical Size: " << mmx <<
" mm x " << mmy <<
" mm";
97 DEBUG_LOG <<
" Scale factor:" << scaleFactor;
98 g_monitor_info.push_back(
99 {std::string(ws.begin(), ws.end()),
static_cast<size_t>(mmx),
100 static_cast<size_t>(mmy),
static_cast<size_t>(width),
101 static_cast<size_t>(height),
static_cast<size_t>(width),
102 static_cast<size_t>(height),
static_cast<size_t>(scaleFactor)});
104 DEBUG_LOG <<
"GetMonitorInfo failed";
111void EnumerateMonitors() {
112 g_monitor_info.clear();
115 Display* display = XOpenDisplay(
nullptr);
117 std::cerr <<
"Error opening X display." << std::endl;
121 int screen = DefaultScreen(display);
122 Window root = RootWindow(display, screen);
124 XRRScreenResources* resources = XRRGetScreenResources(display, root);
126 ERROR_LOG <<
"Error getting screen resources.";
127 XCloseDisplay(display);
131 GdkDisplay* gdk_display = gdk_display_get_default();
132 int gdk_num_monitors = gdk_display_get_n_monitors(gdk_display);
133 DEBUG_LOG <<
"GDK Monitors: " << gdk_num_monitors;
135 for (
int i = 0; i < resources->noutput; ++i) {
136 XRROutputInfo* outputInfo =
137 XRRGetOutputInfo(display, resources, resources->outputs[i]);
138 XRRCrtcInfo* crtcInfo =
139 XRRGetCrtcInfo(display, resources, resources->crtcs[i]);
141 if (i < gdk_num_monitors) {
142 GdkMonitor* monitor = gdk_display_get_monitor(gdk_display, i);
143 scale = gdk_monitor_get_scale_factor(monitor) * 100;
145 if (outputInfo && crtcInfo) {
148 size_t mm_width = outputInfo->mm_width > 0
149 ? outputInfo->mm_width
150 : crtcInfo->width * 25.4 / 96.0;
151 size_t mm_height = outputInfo->mm_height > 0
152 ? outputInfo->mm_height
153 : crtcInfo->height * 25.4 / 96.0;
154 DEBUG_LOG <<
"Monitor " << i + 1 <<
":";
155 DEBUG_LOG <<
" Name: " << outputInfo->name;
156 DEBUG_LOG <<
" Connection: "
157 << (outputInfo->connection == RR_Connected
159 :
"Disconnected/Unknown");
160 DEBUG_LOG <<
" Physical Size (mm): " << mm_width <<
" x " << mm_height;
161 DEBUG_LOG <<
" Resolution: " << crtcInfo->width <<
" x "
163 DEBUG_LOG <<
" Scale: " <<
scale;
164 if (outputInfo->connection == RR_Connected && crtcInfo->width > 0 &&
165 crtcInfo->height > 0) {
166 g_monitor_info.push_back({outputInfo->name, mm_width, mm_height,
167 crtcInfo->width, crtcInfo->height,
168 crtcInfo->width, crtcInfo->height,
scale});
171 XRRFreeOutputInfo(outputInfo);
172 XRRFreeCrtcInfo(crtcInfo);
175 XRRFreeScreenResources(resources);
176 XCloseDisplay(display);
179 EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
181 std::vector<DISPLAYCONFIG_PATH_INFO> paths;
182 std::vector<DISPLAYCONFIG_MODE_INFO> modes;
183 UINT32 flags = QDC_ONLY_ACTIVE_PATHS;
184 LONG isError = ERROR_INSUFFICIENT_BUFFER;
186 UINT32 pathCount, modeCount;
187 isError = GetDisplayConfigBufferSizes(flags, &pathCount, &modeCount);
191 paths.resize(pathCount);
192 modes.resize(modeCount);
195 isError = QueryDisplayConfig(flags, &pathCount, paths.data(), &modeCount,
196 modes.data(),
nullptr);
199 paths.resize(pathCount);
200 modes.resize(modeCount);
204 for (
int i = 0; i < paths.size(); i++) {
206 DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
207 targetName.header.adapterId = paths[i].targetInfo.adapterId;
208 targetName.header.id = paths[i].targetInfo.id;
209 targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
210 targetName.header.size =
sizeof(targetName);
211 isError = DisplayConfigGetDeviceInfo(&targetName.header);
214 if (targetName.flags.friendlyNameFromEdid) {
215 std::wstring ws(targetName.monitorFriendlyDeviceName);
216 std::wstring ws1(targetName.monitorDevicePath);
217 DEBUG_LOG <<
"Monitor found: " << std::string(ws.begin(), ws.end())
218 <<
" - " << std::string(ws1.begin(), ws1.end());
219 if (i < g_monitor_info.size()) {
220 g_monitor_info[i].name = std::string(ws.begin(), ws.end());
228 CGDirectDisplayID displayArray[32];
229 uint32_t displayCount;
230 CGGetOnlineDisplayList(32, displayArray, &displayCount);
232 for (uint32_t i = 0; i < displayCount; ++i) {
233 CGDirectDisplayID displayID = displayArray[i];
234 CGSize displayPhysicalSize = CGDisplayScreenSize(displayID);
235 int width = CGDisplayModeGetWidth(CGDisplayCopyDisplayMode(displayID));
236 int height = CGDisplayModeGetHeight(CGDisplayCopyDisplayMode(displayID));
238 CGDisplayModeGetPixelWidth(CGDisplayCopyDisplayMode(displayID));
240 CGDisplayModeGetPixelHeight(CGDisplayCopyDisplayMode(displayID));
241 DEBUG_LOG <<
"Display " << i + 1 <<
":";
242 DEBUG_LOG <<
" Physical Size: " << displayPhysicalSize.width <<
"x"
243 << displayPhysicalSize.height <<
" mm";
244 DEBUG_LOG <<
" Resolution: " << width <<
"x" << height <<
" pixels";
245 DEBUG_LOG <<
" Pixel resolution: " << pixel_width <<
"x" << pixel_height
247 g_monitor_info.push_back(
248 {std::to_string(i + 1),
static_cast<size_t>(displayPhysicalSize.width),
249 static_cast<size_t>(displayPhysicalSize.height),
250 static_cast<size_t>(width),
static_cast<size_t>(height),
251 static_cast<size_t>(pixel_width),
static_cast<size_t>(pixel_height),
255 if (g_monitor_info.size() == 0) {
260 g_monitor_info.push_back(
261 {
"Dummy monitor", 340, 190, 1920, 1080, 1920, 1080, 100});
263 g_num_monitors = g_monitor_info.size();
264 DEBUG_LOG <<
"Number of monitors: " << g_num_monitors;
265 DEBUG_LOG <<
"Monitor info:";
266 for (
const auto& monitor : g_monitor_info) {
267 DEBUG_LOG <<
"Monitor: " << monitor.name <<
" " << monitor.width_mm <<
"x"
268 << monitor.height_mm <<
"mm " << monitor.width <<
"x"
269 << monitor.height <<
"DIP " << monitor.width_px <<
"x"
270 << monitor.height_px <<
"px " << monitor.scale <<
"%";
Enhanced logging interface on top of wx/log.h.