29 #include "model/logger.h"
35 #include <X11/extensions/Xrandr.h>
40 #include <ShellScalingApi.h>
44 #include <CoreGraphics/CoreGraphics.h>
47 size_t g_num_monitors = 0;
48 size_t g_current_monitor = 0;
49 double g_current_monitor_dip_px_ratio = 1.0;
50 std::vector<OCPN_MonitorInfo> g_monitor_info;
54 BOOL 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, &effectivedpiY);
65 WARNING_LOG <<
"GetDpiForMonitor MDT_EFFECTIVE_DPI failed, falling back to 96 DPI";
69 hr = GetDpiForMonitor(hMonitor, MDT_RAW_DPI, &rawdpiX, &rawdpiY);
70 if (!SUCCEEDED(hr) || rawdpiX == 0 || rawdpiY == 0) {
71 WARNING_LOG <<
"GetDpiForMonitor MDT_RAW_DPI failed, falling back to " << effectivedpiX <<
" DPI";
72 rawdpiX = effectivedpiX;
73 rawdpiY = effectivedpiY;
75 DEBUG_LOG <<
"Raw DPI " << rawdpiX <<
"x" << rawdpiY;
76 DEBUG_LOG <<
"Effective DPI " << effectivedpiX <<
"x" << effectivedpiY;
77 DEVICE_SCALE_FACTOR scaleFactor;
78 hr = GetScaleFactorForMonitor(hMonitor, &scaleFactor);
79 if (!SUCCEEDED(hr) || scaleFactor == DEVICE_SCALE_FACTOR_INVALID) {
80 WARNING_LOG <<
"GetScaleFactorForMonitor failed, falling back to 100";
81 scaleFactor = SCALE_100_PERCENT;
84 auto width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
85 auto height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
86 auto mmx = width * 25.4 / rawdpiX;
87 auto mmy = height * 25.4 / rawdpiY;
88 std::wstring ws(monitorInfo.szDevice);
89 DEBUG_LOG <<
"Display " << hMonitor <<
":";
90 DEBUG_LOG <<
" Monitor Name: " << std::string(ws.begin(), ws.end());
91 DEBUG_LOG <<
" Resolution: " << width <<
"x" << height;
92 DEBUG_LOG <<
" Physical Size: " << mmx <<
" mm x " << mmy <<
" mm";
93 DEBUG_LOG <<
" Scale factor:" << scaleFactor;
94 g_monitor_info.push_back(
95 {std::string(ws.begin(), ws.end()),
static_cast<size_t>(mmx),
96 static_cast<size_t>(mmy),
static_cast<size_t>(width),
static_cast<size_t>(height),
97 static_cast<size_t>(width),
static_cast<size_t>(height),
98 static_cast<size_t>(scaleFactor)});
100 DEBUG_LOG <<
"GetMonitorInfo failed";
107 void EnumerateMonitors() {
108 g_monitor_info.clear();
111 Display* display = XOpenDisplay(
nullptr);
113 std::cerr <<
"Error opening X display." << std::endl;
117 int screen = DefaultScreen(display);
118 Window root = RootWindow(display, screen);
120 XRRScreenResources* resources = XRRGetScreenResources(display, root);
122 ERROR_LOG <<
"Error getting screen resources.";
123 XCloseDisplay(display);
127 GdkDisplay* gdk_display = gdk_display_get_default();
128 int gdk_num_monitors = gdk_display_get_n_monitors(gdk_display);
129 DEBUG_LOG <<
"GDK Monitors: " << gdk_num_monitors;
131 for (
int i = 0; i < resources->noutput; ++i) {
132 XRROutputInfo* outputInfo =
133 XRRGetOutputInfo(display, resources, resources->outputs[i]);
134 XRRCrtcInfo* crtcInfo =
135 XRRGetCrtcInfo(display, resources, resources->crtcs[i]);
137 if (i < gdk_num_monitors) {
138 GdkMonitor* monitor = gdk_display_get_monitor(gdk_display, i);
139 scale = gdk_monitor_get_scale_factor(monitor) * 100;
141 if (outputInfo && crtcInfo) {
143 size_t mm_width = outputInfo->mm_width > 0 ? outputInfo->mm_width : crtcInfo->width * 25.4 / 96.0;
144 size_t mm_height = outputInfo->mm_height > 0 ? outputInfo->mm_height : crtcInfo->height * 25.4 / 96.0;
145 DEBUG_LOG <<
"Monitor " << i + 1 <<
":";
146 DEBUG_LOG <<
" Name: " << outputInfo->name;
147 DEBUG_LOG <<
" Physical Size (mm): " << mm_width <<
" x "
149 DEBUG_LOG <<
" Resolution: " << crtcInfo->width <<
" x "
151 DEBUG_LOG <<
" Scale: " <<
scale;
152 g_monitor_info.push_back({outputInfo->name, mm_width,
153 mm_height, crtcInfo->width,
154 crtcInfo->height, crtcInfo->width,
155 crtcInfo->height,
scale});
157 XRRFreeOutputInfo(outputInfo);
158 XRRFreeCrtcInfo(crtcInfo);
161 XRRFreeScreenResources(resources);
162 XCloseDisplay(display);
165 EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
167 std::vector<DISPLAYCONFIG_PATH_INFO> paths;
168 std::vector<DISPLAYCONFIG_MODE_INFO> modes;
169 UINT32 flags = QDC_ONLY_ACTIVE_PATHS;
170 LONG isError = ERROR_INSUFFICIENT_BUFFER;
172 UINT32 pathCount, modeCount;
173 isError = GetDisplayConfigBufferSizes(flags, &pathCount, &modeCount);
177 paths.resize(pathCount);
178 modes.resize(modeCount);
181 isError = QueryDisplayConfig(flags, &pathCount, paths.data(), &modeCount,
182 modes.data(),
nullptr);
185 paths.resize(pathCount);
186 modes.resize(modeCount);
190 for (
int i = 0; i < paths.size(); i++) {
192 DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
193 targetName.header.adapterId = paths[i].targetInfo.adapterId;
194 targetName.header.id = paths[i].targetInfo.id;
195 targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
196 targetName.header.size =
sizeof(targetName);
197 isError = DisplayConfigGetDeviceInfo(&targetName.header);
200 if (targetName.flags.friendlyNameFromEdid) {
201 std::wstring ws(targetName.monitorFriendlyDeviceName);
202 std::wstring ws1(targetName.monitorDevicePath);
203 DEBUG_LOG <<
"Monitor found: " << std::string(ws.begin(), ws.end())
204 <<
" - " << std::string(ws1.begin(), ws1.end());
205 if (i < g_monitor_info.size()) {
206 g_monitor_info[i].name = std::string(ws.begin(), ws.end());
214 CGDirectDisplayID displayArray[32];
215 uint32_t displayCount;
216 CGGetOnlineDisplayList(32, displayArray, &displayCount);
218 for (uint32_t i = 0; i < displayCount; ++i) {
219 CGDirectDisplayID displayID = displayArray[i];
220 CGSize displayPhysicalSize = CGDisplayScreenSize(displayID);
221 int width = CGDisplayModeGetWidth(CGDisplayCopyDisplayMode(displayID));
222 int height = CGDisplayModeGetHeight(CGDisplayCopyDisplayMode(displayID));
223 int pixel_width = CGDisplayModeGetPixelWidth(CGDisplayCopyDisplayMode(displayID));
224 int pixel_height = CGDisplayModeGetPixelHeight(CGDisplayCopyDisplayMode(displayID));
225 DEBUG_LOG <<
"Display " << i + 1 <<
":";
226 DEBUG_LOG <<
" Physical Size: " << displayPhysicalSize.width <<
"x"
227 << displayPhysicalSize.height <<
" mm";
228 DEBUG_LOG <<
" Resolution: " << width <<
"x" << height <<
" pixels";
229 DEBUG_LOG <<
" Pixel resolution: " << pixel_width <<
"x" << pixel_height <<
" pixels";
230 g_monitor_info.push_back(
231 {std::to_string(i + 1),
static_cast<size_t>(displayPhysicalSize.width),
232 static_cast<size_t>(displayPhysicalSize.height),
233 static_cast<size_t>(width),
static_cast<size_t>(height),
static_cast<size_t>(pixel_width),
static_cast<size_t>(pixel_height), 100});
236 if (g_monitor_info.size() == 0) {
240 g_monitor_info.push_back({
"Dummy monitor", 340, 190, 1920, 1080, 1920, 1080, 100});
242 g_num_monitors = g_monitor_info.size();
243 DEBUG_LOG <<
"Number of monitors: " << g_num_monitors;
244 DEBUG_LOG <<
"Monitor info:";
245 for (
const auto &monitor : g_monitor_info) {
246 DEBUG_LOG <<
"Monitor: " << monitor.name <<
" " << monitor.width_mm <<
"x" << monitor.height_mm <<
"mm " << monitor.width <<
"x" << monitor.height <<
"DIP " << monitor.width_px <<
"x" << monitor.height_px <<
"px " << monitor.scale <<
"%";