DisplayServer (Linux): refactors property handling in xcb and xlib

This commit is contained in:
Carter Li
2026-01-13 09:24:27 +08:00
parent 1c066bc69a
commit 6496dcd7d0
2 changed files with 122 additions and 158 deletions
+92 -108
View File
@@ -13,103 +13,6 @@
#include <xcb/randr.h>
#include <xcb/xcb.h>
typedef struct XcbPropertyData
{
FF_LIBRARY_SYMBOL(xcb_intern_atom)
FF_LIBRARY_SYMBOL(xcb_intern_atom_reply)
FF_LIBRARY_SYMBOL(xcb_get_property)
FF_LIBRARY_SYMBOL(xcb_get_property_reply)
FF_LIBRARY_SYMBOL(xcb_get_property_value)
FF_LIBRARY_SYMBOL(xcb_get_property_value_length)
FF_LIBRARY_SYMBOL(xcb_get_atom_name)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name_length)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_reply)
FF_LIBRARY_SYMBOL(xcb_get_setup)
FF_LIBRARY_SYMBOL(xcb_setup_vendor)
FF_LIBRARY_SYMBOL(xcb_setup_vendor_length)
} XcbPropertyData;
static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbPropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_intern_atom, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_intern_atom_reply, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_property, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_property_reply, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_property_value, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_property_value_length, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name_length, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_reply, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_setup, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor_length, false)
return true;
}
static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t window, const char* request)
{
xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(connection, true, (uint16_t) strlen(request), request);
FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(connection, requestAtomCookie, NULL);
if(requestAtomReply == NULL)
return NULL;
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 8 * 1024);
FF_AUTO_FREE xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(connection, propertyCookie, NULL);
if(propertyReply == NULL)
return NULL;
int length = data->ffxcb_get_property_value_length(propertyReply);
if(length <= 0)
return NULL;
//Why are xcb property strings not null terminated???
void* replyValue = malloc((size_t)length + 1);
memcpy(replyValue, data->ffxcb_get_property_value(propertyReply), (size_t) length);
((char*) replyValue)[length] = '\0';
return replyValue;
}
static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t rootWindow, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0)
return;
FF_AUTO_FREE xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, connection, rootWindow, "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
FF_AUTO_FREE char* wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "WM_NAME");
if(!ffStrSet(wmName))
wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "_NET_WM_NAME");
if(!ffStrSet(wmName))
return;
ffStrbufSetS(&result->wmProcessName, wmName);
}
static void xcbFetchServerVendor(XcbPropertyData* data, xcb_connection_t* connection, FFDisplayServerResult* result)
{
const xcb_setup_t* setup = data->ffxcb_get_setup(connection);
int length = data->ffxcb_setup_vendor_length(setup);
if(length <= 0)
return;
FF_STRBUF_AUTO_DESTROY serverVendor = ffStrbufCreateNS((uint32_t) length, data->ffxcb_setup_vendor(setup));
if (!ffStrbufEqualS(&serverVendor, "The X.Org Foundation")) // Original
{
ffStrbufDestroy(&result->wmProtocolName);
ffStrbufInitMove(&result->wmProtocolName, &serverVendor);
}
}
typedef struct XcbRandrData
{
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_current)
@@ -131,15 +34,86 @@ typedef struct XcbRandrData
FF_LIBRARY_SYMBOL(xcb_randr_get_output_property_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_property_data)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_property_data_length)
FF_LIBRARY_SYMBOL(xcb_intern_atom)
FF_LIBRARY_SYMBOL(xcb_intern_atom_reply)
FF_LIBRARY_SYMBOL(xcb_get_property)
FF_LIBRARY_SYMBOL(xcb_get_property_reply)
FF_LIBRARY_SYMBOL(xcb_get_property_value)
FF_LIBRARY_SYMBOL(xcb_get_property_value_length)
FF_LIBRARY_SYMBOL(xcb_get_atom_name)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name_length)
FF_LIBRARY_SYMBOL(xcb_get_atom_name_reply)
FF_LIBRARY_SYMBOL(xcb_get_setup)
FF_LIBRARY_SYMBOL(xcb_setup_vendor)
FF_LIBRARY_SYMBOL(xcb_setup_vendor_length)
//init once
xcb_connection_t* connection;
FFDisplayServerResult* result;
XcbPropertyData propData;
} XcbRandrData;
static void* xcbGetProperty(XcbRandrData* data, xcb_window_t window, const char* request)
{
xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen(request), request);
FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL);
if(requestAtomReply == NULL)
return NULL;
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(data->connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 8 * 1024);
FF_AUTO_FREE xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(data->connection, propertyCookie, NULL);
if(propertyReply == NULL)
return NULL;
int length = data->ffxcb_get_property_value_length(propertyReply);
if(length <= 0)
return NULL;
//Why are xcb property strings not null terminated???
void* replyValue = malloc((size_t)length + 1);
memcpy(replyValue, data->ffxcb_get_property_value(propertyReply), (size_t) length);
((char*) replyValue)[length] = '\0';
return replyValue;
}
static void xcbDetectWMfromEWMH(XcbRandrData* data, xcb_window_t rootWindow, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0)
return;
FF_AUTO_FREE xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, rootWindow, "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
FF_AUTO_FREE char* wmName = (char*) xcbGetProperty(data, *wmWindow, "WM_NAME");
if(!ffStrSet(wmName))
wmName = (char*) xcbGetProperty(data, *wmWindow, "_NET_WM_NAME");
if(!ffStrSet(wmName))
return;
ffStrbufSetS(&result->wmProcessName, wmName);
}
static void xcbFetchServerVendor(XcbRandrData* data, FFDisplayServerResult* result)
{
const xcb_setup_t* setup = data->ffxcb_get_setup(data->connection);
int length = data->ffxcb_setup_vendor_length(setup);
if(length <= 0)
return;
FF_STRBUF_AUTO_DESTROY serverVendor = ffStrbufCreateNS((uint32_t) length, data->ffxcb_setup_vendor(setup));
if (!ffStrbufEqualS(&serverVendor, "The X.Org Foundation")) // Original
{
ffStrbufDestroy(&result->wmProtocolName);
ffStrbufInitMove(&result->wmProtocolName, &serverVendor);
}
}
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)
{
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
@@ -251,14 +225,14 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
.rem = data->ffxcb_randr_monitor_info_outputs_length(monitor)
};
FF_AUTO_FREE xcb_get_atom_name_reply_t* nameReply = data->propData.ffxcb_get_atom_name_reply(
FF_AUTO_FREE xcb_get_atom_name_reply_t* nameReply = data->ffxcb_get_atom_name_reply(
data->connection,
data->propData.ffxcb_get_atom_name(data->connection, monitor->name),
data->ffxcb_get_atom_name(data->connection, monitor->name),
NULL
);
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateNS(
(uint32_t) data->propData.ffxcb_get_atom_name_name_length(nameReply),
data->propData.ffxcb_get_atom_name_name(nameReply)
(uint32_t) data->ffxcb_get_atom_name_name_length(nameReply),
data->ffxcb_get_atom_name_name(nameReply)
);
const FFDisplayType displayType = ffdsGetDisplayType(name.chars);
@@ -306,7 +280,7 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
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);
double scaleFactor = 1;
FF_AUTO_FREE const char* resourceManager = xcbGetProperty(&data->propData, data->connection, screen->root, "RESOURCE_MANAGER");
FF_AUTO_FREE const char* resourceManager = xcbGetProperty(data, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
@@ -369,6 +343,18 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_intern_atom)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_intern_atom_reply)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_property)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_property_reply)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_property_value)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_property_value_length)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_atom_name)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_atom_name_name)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_atom_name_name_length)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_atom_name_reply)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_get_setup)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_setup_vendor)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_setup_vendor_length)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_randr_get_screen_resources_current)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_randr_get_screen_resources_current_reply)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_randr_get_screen_resources_current_modes_iterator)
@@ -389,8 +375,6 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_randr_get_crtc_info)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xcbRandr, data, xcb_randr_get_crtc_info_reply)
bool propertyDataInitialized = xcbInitPropertyData(xcbRandr, &data.propData);
data.connection = ffxcb_connect(NULL, NULL);
if(ffxcb_connection_has_error(data.connection) > 0)
@@ -405,9 +389,9 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(data.connection));
if(iterator.rem > 0 && propertyDataInitialized) {
xcbDetectWMfromEWMH(&data.propData, data.connection, iterator.data->root, result);
xcbFetchServerVendor(&data.propData, data.connection, result);
if(iterator.rem > 0) {
xcbDetectWMfromEWMH(&data, iterator.data->root, result);
xcbFetchServerVendor(&data, result);
}
+30 -50
View File
@@ -10,25 +10,29 @@
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
typedef struct X11PropertyData
typedef struct XrandrData
{
FF_LIBRARY_SYMBOL(XInternAtom)
FF_LIBRARY_SYMBOL(XGetAtomName);
FF_LIBRARY_SYMBOL(XGetWindowProperty)
FF_LIBRARY_SYMBOL(XServerVendor)
FF_LIBRARY_SYMBOL(XFree)
} X11PropertyData;
FF_LIBRARY_SYMBOL(XFree);
FF_LIBRARY_SYMBOL(XRRGetMonitors)
FF_LIBRARY_SYMBOL(XRRGetScreenResourcesCurrent)
FF_LIBRARY_SYMBOL(XRRGetOutputInfo)
FF_LIBRARY_SYMBOL(XRRGetOutputProperty)
FF_LIBRARY_SYMBOL(XRRGetCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeOutputInfo)
FF_LIBRARY_SYMBOL(XRRFreeScreenResources)
FF_LIBRARY_SYMBOL(XRRFreeMonitors)
static bool x11InitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, X11PropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XInternAtom, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XGetWindowProperty, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XServerVendor, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XFree, false)
//Init once
Display* display;
FFDisplayServerResult* result;
} XrandrData;
return true;
}
static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Window window, const char* request)
static unsigned char* x11GetProperty(XrandrData* data, Display* display, Window window, const char* request)
{
Atom requestAtom = data->ffXInternAtom(display, request, False);
if(requestAtom == None)
@@ -44,18 +48,18 @@ static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Wi
return result;
}
static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDisplayServerResult* result)
static void x11DetectWMFromEWMH(XrandrData* data, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0)
return;
Window* wmWindow = (Window*) x11GetProperty(data, display, DefaultRootWindow(display), "_NET_SUPPORTING_WM_CHECK");
Window* wmWindow = (Window*) x11GetProperty(data, data->display, DefaultRootWindow(data->display), "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
char* wmName = (char*) x11GetProperty(data, display, *wmWindow, "WM_NAME");
char* wmName = (char*) x11GetProperty(data, data->display, *wmWindow, "WM_NAME");
if(!ffStrSet(wmName))
wmName = (char*) x11GetProperty(data, display, *wmWindow, "_NET_WM_NAME");
wmName = (char*) x11GetProperty(data, data->display, *wmWindow, "_NET_WM_NAME");
if(ffStrSet(wmName))
ffStrbufSetS(&result->wmProcessName, wmName);
@@ -64,35 +68,13 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
data->ffXFree(wmWindow);
}
static void x11FetchServerVendor(X11PropertyData* data, Display* display, FFDisplayServerResult* result)
static void x11FetchServerVendor(XrandrData* data, FFDisplayServerResult* result)
{
const char* serverVendor = data->ffXServerVendor(display);
if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation")) {
const char* serverVendor = data->ffXServerVendor(data->display);
if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation"))
ffStrbufSetS(&result->wmProtocolName, serverVendor);
}
}
typedef struct XrandrData
{
FF_LIBRARY_SYMBOL(XInternAtom)
FF_LIBRARY_SYMBOL(XGetAtomName);
FF_LIBRARY_SYMBOL(XFree);
FF_LIBRARY_SYMBOL(XRRGetMonitors)
FF_LIBRARY_SYMBOL(XRRGetScreenResourcesCurrent)
FF_LIBRARY_SYMBOL(XRRGetOutputInfo)
FF_LIBRARY_SYMBOL(XRRGetOutputProperty)
FF_LIBRARY_SYMBOL(XRRGetCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeOutputInfo)
FF_LIBRARY_SYMBOL(XRRFreeScreenResources)
FF_LIBRARY_SYMBOL(XRRFreeMonitors)
//Init once
Display* display;
FFDisplayServerResult* result;
X11PropertyData* propData;
} XrandrData;
static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
{
//We do the check here, because we want the best fallback display if this call failed
@@ -247,7 +229,7 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
XRRScreenResources* screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen));
double scaleFactor = 1;
char* resourceManager = (char*) x11GetProperty(data->propData, data->display, screen->root, "RESOURCE_MANAGER");
char* resourceManager = (char*) x11GetProperty(data, data->display, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
@@ -307,6 +289,8 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XInternAtom);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XGetAtomName);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XGetWindowProperty);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XServerVendor);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XFree);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRGetMonitors);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRGetScreenResourcesCurrent);
@@ -318,17 +302,13 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRFreeScreenResources);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRFreeMonitors);
X11PropertyData propertyData;
bool propertyDataInitialized = x11InitPropertyData(xrandr, &propertyData);
data.propData = &propertyData;
data.display = ffXOpenDisplay(NULL);
if(data.display == NULL)
return "XOpenDisplay() failed";
if(propertyDataInitialized && ScreenCount(data.display) > 0) {
x11DetectWMFromEWMH(&propertyData, data.display, result);
x11FetchServerVendor(&propertyData, data.display, result);
if(ScreenCount(data.display) > 0) {
x11DetectWMFromEWMH(&data, result);
x11FetchServerVendor(&data, result);
}
data.result = result;