Rewrote X11 code

This commit is contained in:
Linus Dierheimer
2022-01-05 14:40:57 +01:00
parent bd3a5fde07
commit 7a3bf2f77d
12 changed files with 599 additions and 157 deletions
+32 -14
View File
@@ -68,12 +68,26 @@ else(VULKAN_FOUND)
message(WARNING "Package vulkan not found. Building without support.")
endif(VULKAN_FOUND)
pkg_check_modules (X11 x11)
if(X11_FOUND)
add_compile_definitions(FF_HAVE_X11=1)
else(X11_FOUND)
message(WARNING "Package x11 not found. Building without support.")
endif(X11_FOUND)
pkg_check_modules (WAYLAND wayland-client)
if(WAYLAND_FOUND)
add_compile_definitions(FF_HAVE_WAYLAND=1)
else(WAYLAND_FOUND)
message(WARNING "Package wayland-client not found. Building without support.")
endif(WAYLAND_FOUND)
pkg_check_modules (XCB_RANDR xcb-randr)
if(XCB_RANDR_FOUND)
add_compile_definitions(FF_HAVE_XCB_RANDR=1)
else(XCB_RANDR_FOUND)
message(WARNING "Package xcb-randr not found. Building without support.")
endif(XCB_RANDR_FOUND)
pkg_check_modules (XCB xcb)
if(XCB_FOUND)
add_compile_definitions(FF_HAVE_XCB=1)
else(XCB_FOUND)
message(WARNING "Package xcb not found. Building without support.")
endif(XCB_FOUND)
pkg_check_modules (XRANDR xrandr)
if(XRANDR_FOUND)
@@ -82,12 +96,12 @@ else(XRANDR_FOUND)
message(WARNING "Package xrandr not found. Building without support.")
endif(XRANDR_FOUND)
pkg_check_modules (WAYLAND wayland-client)
if(WAYLAND_FOUND)
add_compile_definitions(FF_HAVE_WAYLAND=1)
else(WAYLAND_FOUND)
message(WARNING "Package wayland-client not found. Building without support.")
endif(WAYLAND_FOUND)
pkg_check_modules (X11 x11)
if(X11_FOUND)
add_compile_definitions(FF_HAVE_X11=1)
else(X11_FOUND)
message(WARNING "Package x11 not found. Building without support.")
endif(X11_FOUND)
pkg_check_modules (GIO gio-2.0)
if(GIO_FOUND)
@@ -121,9 +135,12 @@ include_directories(
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/src
${LIBPCI_INCLUDE_DIRS}
${X11_INCLUDE_DIRS}
${XRANDR_INCLUDE_DIRS}
${VULKAN_INCLUDE_DIRS}
${WAYLAND_INCLUDE_DIRS}
${XCB_RANDR_INCLUDE_DIRS}
${XCB_INCLUDE_DIRS}
${XRANDR_INCLUDE_DIRS}
${X11_INCLUDE_DIRS}
${GIO_INCLUDE_DIRS}
${DCONF_INCLUDE_DIRS}
${XFCONF_INCLUDE_DIRS}
@@ -151,6 +168,7 @@ set(SRCS
src/detection/terminalShell.c
src/detection/displayserver/displayServer.c
src/detection/displayserver/wayland.c
src/detection/displayserver/xcb.c
src/detection/displayserver/xlib.c
src/detection/displayserver/wmde.c
src/modules/break.c
+5 -3
View File
@@ -20,9 +20,11 @@ In order to run properly on every machine, fastfetch dynamically loads needed li
The following libraries are used if present:
* [`libpci`](https://github.com/pciutils/pciutils): GPU output.
* [`libvulkan`](https://www.vulkan.org/): Fallback for GPU output.
* [`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): Needed for resolution output
* [`libXrandr`](https://gitlab.freedesktop.org/xorg/lib/libxrandr): Needed for appending refresh rate to resolution output.
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance in wayland sessions.
* [`libxcb-randr`](https://xcb.freedesktop.org/),
[`libXrandr`](https://gitlab.freedesktop.org/xorg/lib/libxrandr),
[`libxcb`](https://xcb.freedesktop.org/),
[`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): At least one of them sould be present in X11 sessions for better resolution detection and faster WM detection. The `*randr` ones provide multi monitor support. The `libxcb*` ones usually have better performance.
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance and output in wayland sessions. Supports different refresh rates per monitor.
* [`libGIO`](https://developer.gnome.org/gio/unstable/): Needed for values that are only stored GSettings.
* [`libDConf`](https://developer.gnome.org/dconf/unstable/): Needed for values that are only stored in DConf + Fallback for GSettings.
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
+4 -2
View File
@@ -196,11 +196,13 @@ __fastfetch_completion()
local FF_OPTIONS_PATH=(
"--lib-PCI"
"--lib-vulkan"
"--lib-X11"
"--lib-wayland"
"--lib-xcb-randr"
"--lib-xcb"
"--lib-Xrandr"
"--lib-X11"
"--lib-gio"
"--lib-DConf"
"--lib-wayland"
"--lib-XFConf"
"--lib-RPM"
"--battery-dir"
+4 -2
View File
@@ -174,11 +174,13 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.libPCI, 0);
ffStrbufInitA(&instance->config.libVulkan, 0);
ffStrbufInitA(&instance->config.libX11, 0);
ffStrbufInitA(&instance->config.libWayland, 0);
ffStrbufInitA(&instance->config.libXcbRandr, 0);
ffStrbufInitA(&instance->config.libXcb, 0);
ffStrbufInitA(&instance->config.libXrandr, 0);
ffStrbufInitA(&instance->config.libX11, 0);
ffStrbufInitA(&instance->config.libGIO, 0);
ffStrbufInitA(&instance->config.libDConf, 0);
ffStrbufInitA(&instance->config.libWayland, 0);
ffStrbufInitA(&instance->config.libXFConf, 0);
ffStrbufInitA(&instance->config.librpm, 0);
+4 -2
View File
@@ -185,10 +185,12 @@
# Must be a valid path to a library.
#--lib-PCI /usr/lib/libpci.so
#--lib-vulkan /usr/lib/libvulkan.so
#--lib-X11 /usr/lib/libX11.so
#--lib-wayland /usr/lib/libwayland-client.so
#--lib-xcb-randr /usr/lib/libxcb-randr.so
#--lib-xcb /usr/lib/libxcb.so
#--lib-Xrandr /usr/lib/libXrandr.so
#--lib-X11 /usr/lib/libX11.so
#--lib-gio /usr/lib/libgio-2.0.so
#--lib-DConf /usr/lib/libdconf.so
#--lib-wayland /usr/lib/libwayland-client.so
#--lib-XFConf /usr/lib/libxfconf-0.so
#--lib-rpm /usr/lib/librpm.so
+4 -2
View File
@@ -92,11 +92,13 @@ Key options: Provide a custom key for an output
Library options: Set the path of a library to load
--lib-PCI <path>
--lib-vulkan <path>
--lib-X11 <path>
--lib-wayland <path>
--lib-xcb-randr <path>
--lib-xcb <path>
--lib-Xrandr <path>
--lib-X11 <path>
--lib-gio <path>
--lib-DConf <path>
--lib-wayland <path>
--lib-XFConf <path>
--lib-RPM <path>
@@ -20,6 +20,19 @@ uint32_t ffdsParseRefreshRate(int32_t refreshRate)
return (uint32_t) refreshRate;
}
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate)
{
if(width == 0 || height == 0)
return false;
FFResolutionResult* resolution = ffListAdd(&result->resolutions);
resolution->width = width;
resolution->height = height;
resolution->refreshRate = refreshRate;
return true;
}
static void parseDRM(FFDisplayServerResult* result)
{
const char* drmDirPath = "/sys/class/drm/";
@@ -94,9 +107,15 @@ const FFDisplayServerResult* ffConnectDisplayServer(const FFinstance* instance)
//We use the resolution list to detect if a connection is needed.
//They respect wmProtocolName, and only detect resolution if it is set.
if(result.resolutions.length == 0)
ffdsConnectXcbRandr(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXrandr(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXcb(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXlib(instance, &result);
@@ -10,8 +10,13 @@
#define FF_DISPLAYSERVER_PROTOCOL_TTY "TTY"
uint32_t ffdsParseRefreshRate(int32_t refreshRate);
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate);
void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result);
+389
View File
@@ -0,0 +1,389 @@
#include "displayServer.h"
#ifdef FF_HAVE_XCB
#include <xcb/xcb.h>
#include <string.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)
} XcbPropertyData;
static bool xcbInitPropertyData(void* libraryHandle, XcbPropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_intern_atom, xcb_intern_atom, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_intern_atom_reply, xcb_intern_atom_reply, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property, xcb_get_property, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_reply, xcb_get_property_reply, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_value, xcb_get_property_value, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_value_length, xcb_get_property_value_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);
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, 64);
free(requestAtomReply);
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)
{
free(propertyReply);
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';
free(propertyReply);
return replyValue;
}
static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t rootWindow, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0)
return;
xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, connection, rootWindow, "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
char* wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "_NET_WM_NAME");
if(wmName == NULL)
wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "WM_NAME");
free(wmWindow);
if(wmName == NULL)
return;
if(*wmName == '\0')
{
free(wmName);
return;
}
ffStrbufSetS(&result->wmProcessName, wmName);
free(wmName);
}
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcb, "libxcb.so", instance->config.libXcb,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_connect,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_get_setup,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_setup_roots_iterator,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_screen_next,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_disconnect,)
XcbPropertyData propertyData;
bool propertyDataInitialized = xcbInitPropertyData(xcb, &propertyData);
xcb_connection_t* connection = ffxcb_connect(NULL, NULL);
if(connection == NULL)
{
dlclose(xcb);
return;
}
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(connection));
if(iterator.rem > 0 && propertyDataInitialized)
xcbDetectWMfromEWMH(&propertyData, connection, iterator.data->root, result);
while(iterator.rem > 0)
{
ffdsAppendResolution(
result,
(uint32_t) iterator.data->width_in_pixels,
(uint32_t) iterator.data->height_in_pixels,
0
);
ffxcb_screen_next(&iterator);
}
ffxcb_disconnect(connection);
dlclose(xcb);
}
#else
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing. There are other implementations coming
FF_UNUSED(instance, result)
}
#endif
#ifdef FF_HAVE_XCB_RANDR
#include <xcb/randr.h>
typedef struct XcbRandrData
{
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_modes_iterator)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_info_reply)
FF_LIBRARY_SYMBOL(xcb_randr_mode_info_next)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors_monitors_iterator)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_next)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_outputs_length)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_outputs)
FF_LIBRARY_SYMBOL(xcb_randr_output_next)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_info_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_crtc_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_crtc_info_reply)
//init once
xcb_connection_t* connection;
FFDisplayServerResult* result;
//init per screen
uint32_t defaultRefreshRate;
xcb_randr_get_screen_resources_reply_t* screenResources;
} XcbRandrData;
static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* modeInfo)
{
uint32_t refreshRate = ffdsParseRefreshRate((int32_t) (
modeInfo->dot_clock / (modeInfo->htotal * modeInfo->vtotal)
));
return ffdsAppendResolution(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
);
}
static bool xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode)
{
//We do the check here, because we want the best fallback resolution if this call failed
if(data->screenResources == NULL)
return false;
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_modes_iterator(data->screenResources);
while(modesIterator.rem > 0)
{
if(modesIterator.data->id == mode)
return xcbRandrHandleModeInfo(data, modesIterator.data);
data->ffxcb_randr_mode_info_next(&modesIterator);
}
return false;
}
static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc)
{
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME);
xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL);
if(crtcInfoReply == NULL)
return false;
bool res = xcbRandrHandleMode(data, crtcInfoReply->mode);
free(crtcInfoReply);
return res ? true : ffdsAppendResolution(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
data->defaultRefreshRate
);
}
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output)
{
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
if(outputInfoReply == NULL)
return false;
bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc);
free(outputInfoReply);
return res;
}
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor)
{
//for some reasons, we have to construct this our self
xcb_randr_output_iterator_t outputIterator = {
.index = 0,
.data = data->ffxcb_randr_monitor_info_outputs(monitor),
.rem = data->ffxcb_randr_monitor_info_outputs_length(monitor)
};
bool foundOutput = false;
while(outputIterator.rem > 0)
{
if(xcbRandrHandleOutput(data, *outputIterator.data))
foundOutput = true;
data->ffxcb_randr_output_next(&outputIterator);
};
return foundOutput ? true : ffdsAppendResolution(
data->result,
(uint32_t) monitor->width,
(uint32_t) monitor->height,
data->defaultRefreshRate
);
}
static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
{
xcb_randr_get_monitors_cookie_t monitorsCookie = data->ffxcb_randr_get_monitors(data->connection, screen->root, true);
xcb_randr_get_monitors_reply_t* monitorsReply = data->ffxcb_randr_get_monitors_reply(data->connection, monitorsCookie, NULL);
if(monitorsReply == NULL)
return false;
xcb_randr_monitor_info_iterator_t monitorInfoIterator = data->ffxcb_randr_get_monitors_monitors_iterator(monitorsReply);
bool foundMonitor = false;
while(monitorInfoIterator.rem > 0)
{
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data))
foundMonitor = true;
data->ffxcb_randr_monitor_info_next(&monitorInfoIterator);
}
free(monitorsReply);
return foundMonitor;
}
static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
{
//Init screen info. This is used to get the default refresh rate. If this fails, default refresh rate is simply 0.
xcb_randr_get_screen_info_cookie_t screenInfoCookie = data->ffxcb_randr_get_screen_info(data->connection, screen->root);
xcb_randr_get_screen_info_reply_t* screenInfoReply = data->ffxcb_randr_get_screen_info_reply(data->connection, screenInfoCookie, NULL);
if(screenInfoReply != NULL)
{
data->defaultRefreshRate = screenInfoReply->rate;
free(screenInfoReply);
}
else
data->defaultRefreshRate = 0;
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
xcb_randr_get_screen_resources_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources(data->connection, screen->root);
data->screenResources = data->ffxcb_randr_get_screen_resources_reply(data->connection, screenResourcesCookie, NULL);
//With all the initialisation done, start the detection
bool ret = xcbRandrHandleMonitors(data, screen);
free(data->screenResources);
if(ret)
return;
//If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation
ffdsAppendResolution(
data->result,
(uint32_t) screen->width_in_pixels,
(uint32_t) screen->height_in_pixels,
data->defaultRefreshRate
);
}
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcbRandr, "libxcb-randr.so", instance->config.libXcbRandr,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_connect,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_get_setup,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_setup_roots_iterator,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_screen_next,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_disconnect,)
XcbRandrData data;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources, xcb_randr_get_screen_resources,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources_reply, xcb_randr_get_screen_resources_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources_modes_iterator, xcb_randr_get_screen_resources_modes_iterator,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_info, xcb_randr_get_screen_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_info_reply, xcb_randr_get_screen_info_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_mode_info_next, xcb_randr_mode_info_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors, xcb_randr_get_monitors,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors_reply, xcb_randr_get_monitors_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors_monitors_iterator, xcb_randr_get_monitors_monitors_iterator,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_next, xcb_randr_monitor_info_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_outputs_length, xcb_randr_monitor_info_outputs_length,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_outputs, xcb_randr_monitor_info_outputs,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_output_next, xcb_randr_output_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_output_info, xcb_randr_get_output_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_output_info_reply, xcb_randr_get_output_info_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_crtc_info, xcb_randr_get_crtc_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_crtc_info_reply, xcb_randr_get_crtc_info_reply,)
XcbPropertyData propertyData;
bool propertyDataInitialized = xcbInitPropertyData(xcbRandr, &propertyData);
data.connection = ffxcb_connect(NULL, NULL);
if(data.connection == NULL)
{
dlclose(xcbRandr);
return;
}
data.result = result;
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(data.connection));
if(iterator.rem > 0 && propertyDataInitialized)
xcbDetectWMfromEWMH(&propertyData, data.connection, iterator.data->root, result);
while(iterator.rem > 0)
{
xcbRandrHandleScreen(&data, iterator.data);
ffxcb_screen_next(&iterator);
}
ffxcb_disconnect(data.connection);
dlclose(xcbRandr);
//If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland.
if(result->wmProtocolName.length == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
}
#else
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing. There are other implementations coming
FF_UNUSED(instance, result)
}
#endif
+111 -122
View File
@@ -9,6 +9,14 @@ typedef struct X11PropertyData
FF_LIBRARY_SYMBOL(XGetWindowProperty)
} X11PropertyData;
static bool x11InitPropertyData(void* libraryHandle, X11PropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffXInternAtom, XInternAtom, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffXGetWindowProperty, XGetWindowProperty, false)
return true;
}
static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Window window, const char* request)
{
Atom requestAtom = data->ffXInternAtom(display, request, False);
@@ -19,20 +27,7 @@ static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Wi
unsigned long unused;
unsigned char* result = NULL;
data->ffXGetWindowProperty(
display,
window,
requestAtom,
0,
64,
False,
AnyPropertyType,
&actualType,
(int*) &unused,
&unused,
&unused,
&result
);
data->ffXGetWindowProperty(display, window, requestAtom, 0, 64, False, AnyPropertyType, &actualType, (int*) &unused, &unused, &unused, &result);
return result;
}
@@ -42,40 +37,17 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
if(result->wmProcessName.length > 0)
return;
Window root = DefaultRootWindow(display);
if(root == None)
Window* wmWindow = (Window*) x11GetProperty(data, display, DefaultRootWindow(display), "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
unsigned char* wmWindowID = x11GetProperty(data, display, root, "_NET_SUPPORTING_WM_CHECK");
if(wmWindowID == NULL)
return;
Window wmWindow = *(Window*) wmWindowID;
if(wmWindow == None)
return;
unsigned char* wmName = x11GetProperty(data, display, wmWindow, "_NET_WM_NAME");
if(wmName == NULL)
wmName = x11GetProperty(data, display, wmWindow, "WM_NAME");
const char* wmName = (const char*) x11GetProperty(data, display, *wmWindow, "_NET_WM_NAME");
if(wmName == NULL)
wmName = (const char*) x11GetProperty(data, display, *wmWindow, "WM_NAME");
if(wmName == NULL || *wmName == '\0')
return;
const char* wmNameString = (const char*) wmName;
if(*wmNameString == '\0')
return;
ffStrbufSetS(&result->wmProcessName, wmNameString);
}
static void x11AddScreenAsResult(FFlist* results, Screen* screen, uint32_t refreshRate)
{
if(WidthOfScreen(screen) == 0 || HeightOfScreen(screen) == 0)
return;
FFResolutionResult* result = ffListAdd(results);
result->width = (uint32_t) WidthOfScreen(screen);
result->height = (uint32_t) HeightOfScreen(screen);
result->refreshRate = refreshRate;
ffStrbufSetS(&result->wmProcessName, wmName);
}
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
@@ -85,8 +57,7 @@ void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
FF_LIBRARY_LOAD_SYMBOL(x11, XCloseDisplay,)
X11PropertyData propertyData;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(x11, propertyData.ffXInternAtom, XInternAtom,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(x11, propertyData.ffXGetWindowProperty, XGetWindowProperty,)
bool propertyDataInitialized = x11InitPropertyData(x11, &propertyData);
Display* display = ffXOpenDisplay(x11);
if(display == NULL)
@@ -95,10 +66,19 @@ void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
return;
}
for(int i = 0; i < ScreenCount(display); i++)
x11AddScreenAsResult(&result->resolutions, ScreenOfDisplay(display, i), 0);
if(propertyDataInitialized && ScreenCount(display) > 0)
x11DetectWMFromEWMH(&propertyData, display, result);
x11DetectWMFromEWMH(&propertyData, display, result);
for(int i = 0; i < ScreenCount(display); i++)
{
Screen* screen = ScreenOfDisplay(display, i);
ffdsAppendResolution(
result,
(uint32_t) screen->width,
(uint32_t) screen->height,
0
);
}
ffXCloseDisplay(display);
dlclose(x11);
@@ -138,101 +118,115 @@ typedef struct XrandrData
//Init once
Display* display;
FFlist* results;
FFDisplayServerResult* result;
//Init per screen
uint32_t defaultRefreshRate;
XRRScreenResources* screenResources;
} XrandrData;
static XRRModeInfo* xrandrGetModeInfo(XRRScreenResources* screenResources, RRMode mode)
static bool xrandrHandleModeInfo(XrandrData* data, XRRModeInfo* modeInfo)
{
for(int i = 0; i < screenResources->nmode; i++)
{
if(screenResources->modes[i].id == mode)
return &screenResources->modes[i];
}
return NULL;
uint32_t refreshRate = ffdsParseRefreshRate((int32_t) (
modeInfo->dotClock / (modeInfo->hTotal * modeInfo->vTotal)
));
return ffdsAppendResolution(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
);
}
static bool xrandrHandleOutputInfo(XrandrData* data, XRROutputInfo* outputInfo)
static bool xrandrHandleMode(XrandrData* data, RRMode mode)
{
XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, outputInfo->crtc);
for(int i = 0; i < data->screenResources->nmode; i++)
{
if(data->screenResources->modes[i].id == mode)
return xrandrHandleModeInfo(data, &data->screenResources->modes[i]);
}
return false;
}
static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc)
{
//We do the check here, because we want the best fallback resolution if this call failed
if(data->screenResources == NULL)
return false;
XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, crtc);
if(crtcInfo == NULL)
return false;
XRRModeInfo* modeInfo = xrandrGetModeInfo(data->screenResources, crtcInfo->mode);
if(modeInfo == NULL || modeInfo->width == 0 || modeInfo->height == 0)
{
data->ffXRRFreeCrtcInfo(crtcInfo);
return false;
}
FFResolutionResult* result = ffListAdd(data->results);
result->width = modeInfo->width;
result->height = modeInfo->height;
result->refreshRate = ffdsParseRefreshRate((int32_t) (modeInfo->dotClock / (modeInfo->hTotal * modeInfo->vTotal)));
if(result->refreshRate == 0)
result->refreshRate = data->defaultRefreshRate;
bool res = xrandrHandleMode(data, crtcInfo->mode);
data->ffXRRFreeCrtcInfo(crtcInfo);
return true;
return res ? true : ffdsAppendResolution(
data->result,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
data->defaultRefreshRate
);
}
static bool xrandrHandleMonitorFallback(XrandrData* data, XRRMonitorInfo* monitorInfo)
static bool xrandrHandleOutput(XrandrData* data, RROutput output)
{
if(monitorInfo->width == 0 || monitorInfo->height == 0)
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, output);
if(outputInfo == NULL)
return false;
FFResolutionResult* result = ffListAdd(data->results);
result->width = (uint32_t) monitorInfo->width;
result->height = (uint32_t) monitorInfo->height;
result->refreshRate = (uint32_t) data->defaultRefreshRate;
return true;
bool res = xrandrHandleCrtc(data, outputInfo->crtc);
data->ffXRRFreeOutputInfo(outputInfo);
return res;
}
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
{
bool foundMode = false;
bool foundOutput = false;
for(int i = 0; i < monitorInfo->noutput; i++)
{
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, monitorInfo->outputs[i]);
if(outputInfo == NULL)
continue;
if(xrandrHandleOutputInfo(data, outputInfo))
foundMode = true;
data->ffXRRFreeOutputInfo(outputInfo);
if(xrandrHandleOutput(data, monitorInfo->outputs[i]))
foundOutput = true;
}
if(!foundMode)
return xrandrHandleMonitorFallback(data, monitorInfo);
return true;
return foundOutput ? true : ffdsAppendResolution(
data->result,
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
data->defaultRefreshRate
);
}
static inline bool xrandrLoopMonitors(XrandrData* data, XRRMonitorInfo* monitorInfos, int numberOfMonitors, bool(*monitorFunc)(XrandrData* data, XRRMonitorInfo* monitorInfo))
static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
{
bool foundAMonitor = false;
int numberOfMonitors;
XRRMonitorInfo* monitorInfos = data->ffXRRGetMonitors(data->display, RootWindowOfScreen(screen), True, &numberOfMonitors);
if(monitorInfos == NULL)
return false;
bool foundAMonitor;
for(int i = 0; i < numberOfMonitors; i++)
{
if(monitorFunc(data, &monitorInfos[i]))
if(xrandrHandleMonitor(data, &monitorInfos[i]))
foundAMonitor = true;
}
data->ffXRRFreeMonitors(monitorInfos);
return foundAMonitor;
}
static void xrandrHandleScreen(XrandrData* data, Screen* screen)
{
Window window = RootWindowOfScreen(screen);
//Init screen configuration. This is used to get the default refresh rate. If this fails, default refresh rate is simply 0.
XRRScreenConfiguration* screenConfiguration = data->ffXRRGetScreenInfo(data->display, RootWindowOfScreen(screen));
XRRScreenConfiguration* screenConfiguration = data->ffXRRGetScreenInfo(data->display, window);
if(screenConfiguration != NULL)
{
data->defaultRefreshRate = (uint32_t) data->ffXRRConfigCurrentRate(screenConfiguration);
@@ -241,28 +235,23 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
else
data->defaultRefreshRate = 0;
int numberOfMonitors;
XRRMonitorInfo* monitorInfos = data->ffXRRGetMonitors(data->display, window, True, &numberOfMonitors);
if(monitorInfos == NULL)
{
x11AddScreenAsResult(data->results, screen, data->defaultRefreshRate);
return;
}
//Init screen resources
data->screenResources = data->ffXRRGetScreenResources(data->display, RootWindowOfScreen(screen));
data->screenResources = data->ffXRRGetScreenResources(data->display, window);
bool foundAMonitor;
if(data->screenResources != NULL)
foundAMonitor = xrandrLoopMonitors(data, monitorInfos, numberOfMonitors, xrandrHandleMonitor);
else
foundAMonitor = xrandrLoopMonitors(data, monitorInfos, numberOfMonitors, xrandrHandleMonitorFallback);
if(!foundAMonitor)
x11AddScreenAsResult(data->results, screen, data->defaultRefreshRate);
bool ret = xrandrHandleMonitors(data, screen);
data->ffXRRFreeScreenResources(data->screenResources);
data->ffXRRFreeMonitors(monitorInfos);
if(ret)
return;
//Fallback to screen
ffdsAppendResolution(
data->result,
(uint32_t) WidthOfScreen(screen),
(uint32_t) HeightOfScreen(screen),
data->defaultRefreshRate
);
}
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result)
@@ -287,8 +276,7 @@ void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeScreenConfigInfo, XRRFreeScreenConfigInfo,);
X11PropertyData propertyData;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, propertyData.ffXInternAtom, XInternAtom,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, propertyData.ffXGetWindowProperty, XGetWindowProperty,)
bool propertyDataInitialized = x11InitPropertyData(xrandr, &propertyData);
data.display = ffXOpenDisplay(NULL);
if(data.display == NULL)
@@ -297,13 +285,14 @@ void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result
return;
}
data.results = &result->resolutions;
if(propertyDataInitialized && ScreenCount(data.display) > 0)
x11DetectWMFromEWMH(&propertyData, data.display, result);
data.result = result;
for(int i = 0; i < ScreenCount(data.display); i++)
xrandrHandleScreen(&data, ScreenOfDisplay(data.display, i));
x11DetectWMFromEWMH(&propertyData, data.display, result);
ffXCloseDisplay(data.display);
dlclose(xrandr);
+18 -8
View File
@@ -354,14 +354,20 @@ static inline void listSupportedFeatures()
#ifdef FF_HAVE_VULKAN
"vulkan\n"
#endif
#ifdef FF_HAVE_X11
"x11\n"
#ifdef FF_HAVE_WAYLAND
"wayland\n"
#endif
#ifdef FF_HAVE_XCB_RANDR
"xcb-randr\n"
#endif
#ifdef FF_HAVE_XCB
"xcb\n"
#endif
#ifdef FF_HAVE_XRANDR
"xrandr\n"
#endif
#ifdef FF_HAVE_WAYLAND
"wayland\n"
#ifdef FF_HAVE_X11
"x11\n"
#endif
#ifdef FF_HAVE_GIO
"gio\n"
@@ -826,16 +832,20 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.libPCI);
else if(strcasecmp(key, "--lib-vulkan") == 0)
optionParseString(key, value, &instance->config.libVulkan);
else if(strcasecmp(key, "--lib-X11") == 0)
optionParseString(key, value, &instance->config.libX11);
else if(strcasecmp(key, "--lib-wayland") == 0)
optionParseString(key, value, &instance->config.libWayland);
else if(strcasecmp(key, "--lib-xcb-randr") == 0)
optionCheckString(key, value, &instance->config.libXcbRandr);
else if(strcasecmp(key, "--lib-xcb") == 0)
optionParseString(key, value, &instance->config.libXcb);
else if(strcasecmp(key, "--lib-Xrandr") == 0)
optionParseString(key, value, &instance->config.libXrandr);
else if(strcasecmp(key, "--lib-X11") == 0)
optionParseString(key, value, &instance->config.libX11);
else if(strcasecmp(key, "--lib-gio") == 0)
optionParseString(key, value, &instance->config.libGIO);
else if(strcasecmp(key, "--lib-DConf") == 0)
optionParseString(key, value, &instance->config.libDConf);
else if(strcasecmp(key, "--lib-wayland") == 0)
optionParseString(key, value, &instance->config.libWayland);
else if(strcasecmp(key, "--lib-XFConf") == 0)
optionParseString(key, value, &instance->config.libXFConf);
else if(strcasecmp(key, "--lib-rpm") == 0)
+4 -2
View File
@@ -108,9 +108,11 @@ typedef struct FFconfig
FFstrbuf libPCI;
FFstrbuf libVulkan;
FFstrbuf libX11;
FFstrbuf libXrandr;
FFstrbuf libWayland;
FFstrbuf libXcbRandr;
FFstrbuf libXcb;
FFstrbuf libXrandr;
FFstrbuf libX11;
FFstrbuf libGIO;
FFstrbuf libDConf;
FFstrbuf libXFConf;