Skip to content

Commit e3d6a85

Browse files
committed
Display (Linux): detect scale factor for X11
1 parent 7d92da8 commit e3d6a85

File tree

2 files changed

+115
-106
lines changed

2 files changed

+115
-106
lines changed

src/detection/displayserver/linux/xcb.c

Lines changed: 66 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#ifdef FF_HAVE_XCB_RANDR
44

55
#include "common/library.h"
6-
#include "common/time.h"
6+
#include "common/properties.h"
77
#include "util/edidHelper.h"
88
#include "util/mallocHelper.h"
99
#include "util/stringUtils.h"
@@ -56,7 +56,7 @@ static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection,
5656
if(requestAtomReply == NULL)
5757
return NULL;
5858

59-
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 64);
59+
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 8 * 1024);
6060

6161
FF_AUTO_FREE xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(connection, propertyCookie, NULL);
6262
if(propertyReply == NULL)
@@ -138,14 +138,38 @@ typedef struct XcbRandrData
138138
xcb_connection_t* connection;
139139
FFDisplayServerResult* result;
140140
XcbPropertyData propData;
141-
142-
//init per screen
143-
xcb_randr_get_screen_resources_current_reply_t* screenResources;
144141
} XcbRandrData;
145142

146-
static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength)
143+
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
147144
{
148-
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME);
145+
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
146+
FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
147+
if(outputInfoReply == NULL)
148+
return false;
149+
150+
xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen("EDID"), "EDID");
151+
FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL);
152+
FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = NULL;
153+
uint8_t* edidData = NULL;
154+
uint32_t edidLength = 0;
155+
if(requestAtomReply)
156+
{
157+
xcb_randr_get_output_property_cookie_t outputPropertyCookie = data->ffxcb_randr_get_output_property(data->connection, output, requestAtomReply->atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 100, false, false);
158+
outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL);
159+
if(outputPropertyReply)
160+
{
161+
int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply);
162+
if(len >= 128)
163+
{
164+
ffStrbufClear(name);
165+
edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply);
166+
ffEdidGetName(edidData, name);
167+
edidLength = (uint32_t) len;
168+
}
169+
}
170+
}
171+
172+
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, outputInfoReply->crtc, XCB_CURRENT_TIME);
149173
FF_AUTO_FREE xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL);
150174
if(crtcInfoReply == NULL)
151175
return false;
@@ -170,11 +194,11 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb
170194
xcb_randr_mode_info_t* currentMode = NULL;
171195
xcb_randr_mode_info_t* preferredMode = NULL;
172196

173-
if(data->screenResources)
197+
if(screenResources)
174198
{
175-
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources);
199+
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(screenResources);
176200

177-
if (output->num_preferred > 0)
201+
if (outputInfoReply->num_preferred > 0)
178202
preferredMode = modesIterator.data;
179203

180204
while (modesIterator.rem > 0)
@@ -194,8 +218,8 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb
194218
(uint32_t) crtcInfoReply->width,
195219
(uint32_t) crtcInfoReply->height,
196220
currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0,
197-
(uint32_t) crtcInfoReply->width,
198-
(uint32_t) crtcInfoReply->height,
221+
(uint32_t) (crtcInfoReply->width / scaleFactor + .5),
222+
(uint32_t) (crtcInfoReply->height / scaleFactor + .5),
199223
preferredMode ? (uint32_t) preferredMode->width : 0,
200224
preferredMode ? (uint32_t) preferredMode->height : 0,
201225
preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0,
@@ -204,54 +228,21 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb
204228
displayType,
205229
primary,
206230
0,
207-
(uint32_t) output->mm_width,
208-
(uint32_t) output->mm_height,
231+
(uint32_t) outputInfoReply->mm_width,
232+
(uint32_t) outputInfoReply->mm_height,
209233
"xcb-randr-crtc"
210234
);
211235
if (item && edidLength)
212236
{
213237
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
214238
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
239+
item->bitDepth = bitDepth;
215240
}
216241

217242
return !!item;
218243
}
219244

220-
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType)
221-
{
222-
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
223-
FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
224-
if(outputInfoReply == NULL)
225-
return false;
226-
227-
xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen("EDID"), "EDID");
228-
FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL);
229-
FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = NULL;
230-
uint8_t* edidData = NULL;
231-
uint32_t edidLength = 0;
232-
if(requestAtomReply)
233-
{
234-
xcb_randr_get_output_property_cookie_t outputPropertyCookie = data->ffxcb_randr_get_output_property(data->connection, output, requestAtomReply->atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 100, false, false);
235-
outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL);
236-
if(outputPropertyReply)
237-
{
238-
int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply);
239-
if(len >= 128)
240-
{
241-
ffStrbufClear(name);
242-
edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply);
243-
ffEdidGetName(edidData, name);
244-
edidLength = (uint32_t) len;
245-
}
246-
}
247-
}
248-
249-
bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc, name, primary, outputInfoReply, displayType, edidData, edidLength);
250-
251-
return res;
252-
}
253-
254-
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor)
245+
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
255246
{
256247
//for some reasons, we have to construct this our self
257248
xcb_randr_output_iterator_t outputIterator = {
@@ -275,18 +266,20 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
275266

276267
while(outputIterator.rem > 0)
277268
{
278-
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType))
269+
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType, screenResources, bitDepth, scaleFactor))
279270
foundOutput = true;
280271
data->ffxcb_randr_output_next(&outputIterator);
281-
};
272+
}
282273

283-
return foundOutput ? true : !!ffdsAppendDisplay(
274+
if (foundOutput) return true;
275+
276+
FFDisplayResult* display = ffdsAppendDisplay(
284277
data->result,
285278
(uint32_t) monitor->width,
286279
(uint32_t) monitor->height,
287280
0,
288-
(uint32_t) monitor->width,
289-
(uint32_t) monitor->height,
281+
(uint32_t) (monitor->width / scaleFactor + .5),
282+
(uint32_t) (monitor->height / scaleFactor + .5),
290283
0, 0, 0,
291284
0,
292285
&name,
@@ -297,6 +290,8 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
297290
(uint32_t) monitor->height_in_millimeters,
298291
"xcb-randr-monitor"
299292
);
293+
if (display) display->bitDepth = bitDepth;
294+
return !!display;
300295
}
301296

302297
static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
@@ -306,13 +301,27 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
306301
if(monitorsReply == NULL)
307302
return false;
308303

304+
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
305+
xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root);
306+
FF_AUTO_FREE struct xcb_randr_get_screen_resources_current_reply_t* screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL);
307+
308+
double scaleFactor = 1;
309+
FF_AUTO_FREE const char* resourceManager = xcbGetProperty(&data->propData, data->connection, screen->root, "RESOURCE_MANAGER");
310+
if (resourceManager)
311+
{
312+
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
313+
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi))
314+
scaleFactor = ffStrbufToDouble(&dpi, 96) / 96;
315+
}
316+
uint8_t bitDepth = (uint8_t) (screen->root_depth / 3);
317+
309318
xcb_randr_monitor_info_iterator_t monitorInfoIterator = data->ffxcb_randr_get_monitors_monitors_iterator(monitorsReply);
310319

311320
bool foundMonitor = false;
312321

313322
while(monitorInfoIterator.rem > 0)
314323
{
315-
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data))
324+
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data, screenResources, bitDepth, scaleFactor))
316325
foundMonitor = true;
317326
data->ffxcb_randr_monitor_info_next(&monitorInfoIterator);
318327
}
@@ -322,17 +331,8 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
322331

323332
static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
324333
{
325-
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
326-
xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root);
327-
328-
data->screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL);
329-
330334
//With all the initialisation done, start the detection
331-
bool ret = xcbRandrHandleMonitors(data, screen);
332-
333-
free(data->screenResources);
334-
335-
if(ret)
335+
if(xcbRandrHandleMonitors(data, screen))
336336
return;
337337

338338
//If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation
@@ -348,7 +348,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
348348
NULL,
349349
FF_DISPLAY_TYPE_UNKNOWN,
350350
false,
351-
0,
351+
(uint64_t) screen->root,
352352
(uint32_t) screen->width_in_millimeters,
353353
(uint32_t) screen->height_in_millimeters,
354354
"xcb-randr-screen"

0 commit comments

Comments
 (0)