mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2025-02-20 11:43:27 +08:00
wayland support
This commit is contained in:
parent
f27f08a6e2
commit
a145700500
@ -78,6 +78,8 @@ set(SRCS
|
|||||||
src/modules/packages.c
|
src/modules/packages.c
|
||||||
src/modules/shell.c
|
src/modules/shell.c
|
||||||
src/modules/resolution.c
|
src/modules/resolution.c
|
||||||
|
src/modules/resolution_x11.c
|
||||||
|
src/modules/resolution_wayland.c
|
||||||
src/modules/de.c
|
src/modules/de.c
|
||||||
src/modules/wm.c
|
src/modules/wm.c
|
||||||
src/modules/wmtheme.c
|
src/modules/wmtheme.c
|
||||||
|
@ -30,6 +30,7 @@ Following libraries are used if present:
|
|||||||
* [`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): Needed for resolution 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.
|
* [`libXrandr`](https://gitlab.freedesktop.org/xorg/lib/libxrandr): Needed for appending refresh rate to resolution output.
|
||||||
* [`libDConf`](https://developer.gnome.org/dconf/unstable/DConfClient.html): GTK theme/font/icons output on DEs which dont use config files (e.g. Gnome).
|
* [`libDConf`](https://developer.gnome.org/dconf/unstable/DConfClient.html): GTK theme/font/icons output on DEs which dont use config files (e.g. Gnome).
|
||||||
|
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance + support for monitors with different refresh rates in wayland sessions.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
@ -178,6 +178,7 @@ __fastfetch_completion()
|
|||||||
"--lib-X11"
|
"--lib-X11"
|
||||||
"--lib-Xrandr"
|
"--lib-Xrandr"
|
||||||
"--lib-DConf"
|
"--lib-DConf"
|
||||||
|
"--lib-wayland"
|
||||||
)
|
)
|
||||||
|
|
||||||
local FF_OPTIONS_LOGO=(
|
local FF_OPTIONS_LOGO=(
|
||||||
|
@ -71,6 +71,7 @@ static void defaultConfig(FFconfig* config)
|
|||||||
ffStrbufInitA(&config->libX11, 1);
|
ffStrbufInitA(&config->libX11, 1);
|
||||||
ffStrbufInitA(&config->libXrandr, 1);
|
ffStrbufInitA(&config->libXrandr, 1);
|
||||||
ffStrbufInitA(&config->libDConf, 1);
|
ffStrbufInitA(&config->libDConf, 1);
|
||||||
|
ffStrbufInitA(&config->libWayland, 1);
|
||||||
|
|
||||||
ffStrbufInitA(&config->diskFolders, 1);
|
ffStrbufInitA(&config->diskFolders, 1);
|
||||||
}
|
}
|
||||||
|
@ -178,11 +178,13 @@ bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFstr
|
|||||||
ffStrbufInitA(&content, 512);
|
ffStrbufInitA(&content, 512);
|
||||||
ffAppendFileContent(cacheFilePath.chars, &content);
|
ffAppendFileContent(cacheFilePath.chars, &content);
|
||||||
|
|
||||||
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
|
|
||||||
|
|
||||||
if(content.length == 0)
|
if(content.length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
//Strbuf adds an extra nullbyte at chars[length]. We want this one to be the end of the last value to test for index == length
|
||||||
|
if(content.chars[content.length - 1] == '\0')
|
||||||
|
ffStrbufSubstrBefore(&content, content.length - 1);
|
||||||
|
|
||||||
uint8_t moduleCounter = 1;
|
uint8_t moduleCounter = 1;
|
||||||
|
|
||||||
FFformatarg arguments[numArgs];
|
FFformatarg arguments[numArgs];
|
||||||
@ -265,8 +267,6 @@ void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8
|
|||||||
|
|
||||||
fputc('\0', cache->split);
|
fputc('\0', cache->split);
|
||||||
}
|
}
|
||||||
|
|
||||||
fputc('\0', cache->split);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
||||||
|
@ -110,6 +110,7 @@ static inline void printHelp()
|
|||||||
" --lib-X11 <path>\n"
|
" --lib-X11 <path>\n"
|
||||||
" --lib-Xrandr <path>\n"
|
" --lib-Xrandr <path>\n"
|
||||||
" --lib-DConf <path>\n"
|
" --lib-DConf <path>\n"
|
||||||
|
" --lib-wayland <path>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Module specific options:\n"
|
"Module specific options:\n"
|
||||||
" --disk-folders <folders>: A colon seperated list of folder paths for the disk output. Default is \"/:/home\"\n"
|
" --disk-folders <folders>: A colon seperated list of folder paths for the disk output. Default is \"/:/home\"\n"
|
||||||
@ -654,6 +655,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
|||||||
optionParseString(key, value, &instance->config.libXrandr);
|
optionParseString(key, value, &instance->config.libXrandr);
|
||||||
else if(strcasecmp(key, "--lib-DConf") == 0)
|
else if(strcasecmp(key, "--lib-DConf") == 0)
|
||||||
optionParseString(key, value, &instance->config.libDConf);
|
optionParseString(key, value, &instance->config.libDConf);
|
||||||
|
else if(strcasecmp(key, "--lib-wayland") == 0)
|
||||||
|
optionParseString(key, value, &instance->config.libWayland);
|
||||||
else if(strcasecmp(key, "--disk-folders") == 0)
|
else if(strcasecmp(key, "--disk-folders") == 0)
|
||||||
optionParseString(key, value, &instance->config.diskFolders);
|
optionParseString(key, value, &instance->config.diskFolders);
|
||||||
else
|
else
|
||||||
|
@ -92,6 +92,7 @@ typedef struct FFconfig
|
|||||||
FFstrbuf libPCI;
|
FFstrbuf libPCI;
|
||||||
FFstrbuf libX11;
|
FFstrbuf libX11;
|
||||||
FFstrbuf libXrandr;
|
FFstrbuf libXrandr;
|
||||||
|
FFstrbuf libWayland;
|
||||||
FFstrbuf libDConf;
|
FFstrbuf libDConf;
|
||||||
|
|
||||||
FFstrbuf diskFolders;
|
FFstrbuf diskFolders;
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
#include "fastfetch.h"
|
#include "resolution.h"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
void ffPrintResolutionValue(FFinstance* instance, uint8_t moduleIndex, FFcache* cache, int width, int height, int refreshRate)
|
||||||
#include <X11/extensions/Xrandr.h>
|
|
||||||
|
|
||||||
#define FF_RESOLUTION_MODULE_NAME "Resolution"
|
|
||||||
#define FF_RESOLUTION_NUM_FORMAT_ARGS 3
|
|
||||||
|
|
||||||
static void printValue(FFinstance* instance, uint8_t moduleIndex, FFcache* cache, int width, int height, int refreshRate)
|
|
||||||
{
|
{
|
||||||
FFstrbuf value;
|
FFstrbuf value;
|
||||||
ffStrbufInitA(&value, 32);
|
ffStrbufInitA(&value, 32);
|
||||||
@ -22,177 +16,16 @@ static void printValue(FFinstance* instance, uint8_t moduleIndex, FFcache* cache
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Display* openDisplay(FFinstance* instance, void* library, bool printErrors)
|
|
||||||
{
|
|
||||||
Display*(*ffXOpenDisplay)(const char*) = dlsym(library, "XOpenDisplay");
|
|
||||||
if(ffXOpenDisplay == NULL)
|
|
||||||
{
|
|
||||||
dlclose(library);
|
|
||||||
if(printErrors)
|
|
||||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "dlsym(library, \"XOpenDisplay\") == NULL");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display* display = ffXOpenDisplay(NULL);
|
|
||||||
if(display == NULL)
|
|
||||||
{
|
|
||||||
dlclose(library);
|
|
||||||
if(printErrors)
|
|
||||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "ffXOpenDisplay(NULL) == NULL");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return display;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void closeDisplay(void* library, Display* display)
|
|
||||||
{
|
|
||||||
int(*ffXCloseDisplay)(Display*) = dlsym(library, "XCloseDisplay");
|
|
||||||
if(ffXCloseDisplay != NULL)
|
|
||||||
ffXCloseDisplay(display);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printResolutionX11Backend(FFinstance* instance)
|
|
||||||
{
|
|
||||||
void* x11;
|
|
||||||
if(instance->config.libX11.length == 0)
|
|
||||||
x11 = dlopen("libX11.so", RTLD_LAZY);
|
|
||||||
else
|
|
||||||
x11 = dlopen(instance->config.libX11.chars, RTLD_LAZY);
|
|
||||||
|
|
||||||
if(x11 == NULL)
|
|
||||||
{
|
|
||||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "dlopen(\"libX11.so\", RTLD_LAZY) == NULL");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display* display = openDisplay(instance, x11, true);
|
|
||||||
if(display == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int screenCount = ScreenCount(display);
|
|
||||||
if(screenCount < 1)
|
|
||||||
{
|
|
||||||
closeDisplay(x11, display);
|
|
||||||
dlclose(x11);
|
|
||||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "ScreenCount(display) < 1: %i", screenCount);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FFcache cache;
|
|
||||||
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &cache);
|
|
||||||
|
|
||||||
for(int i = 0; i < screenCount; i++)
|
|
||||||
{
|
|
||||||
Screen* screen = ScreenOfDisplay(display, i);
|
|
||||||
uint8_t moduleIndex = screenCount == 1 ? 0 : i + 1;
|
|
||||||
printValue(instance, moduleIndex, &cache, WidthOfScreen(screen), HeightOfScreen(screen), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ffCacheClose(&cache);
|
|
||||||
|
|
||||||
closeDisplay(x11, display);
|
|
||||||
dlclose(x11);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getCurrentRate(void* xrandr, Display* display)
|
|
||||||
{
|
|
||||||
XRRScreenConfiguration*(*ffXRRGetScreenInfo)(Display*, Window) = dlsym(xrandr, "XRRGetScreenInfo");
|
|
||||||
if(ffXRRGetScreenInfo == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
short(*ffXRRConfigCurrentRate)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRConfigCurrentRate");
|
|
||||||
if(ffXRRConfigCurrentRate == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
XRRMonitorInfo*(*ffXRRGetMonitors)(Display*, Window, Bool, int*) = dlsym(xrandr, "XRRGetMonitors");
|
|
||||||
if(ffXRRGetMonitors == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
void(*ffXRRFreeMonitors)(XRRMonitorInfo*) = dlsym(xrandr, "XRRFreeMonitors");
|
|
||||||
if(ffXRRFreeMonitors == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
XRRScreenConfiguration* xrrscreenconf = ffXRRGetScreenInfo(display, RootWindow(display, 0));
|
|
||||||
if(xrrscreenconf == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
short currentRate = ffXRRConfigCurrentRate(xrrscreenconf);
|
|
||||||
|
|
||||||
void(*ffXRRFreeScreenConfigInfo)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRFreeScreenConfigInfo");
|
|
||||||
if(ffXRRFreeScreenConfigInfo != NULL)
|
|
||||||
ffXRRFreeScreenConfigInfo(xrrscreenconf);
|
|
||||||
|
|
||||||
return (int) currentRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool printResolutionXrandrBackend(FFinstance* instance)
|
|
||||||
{
|
|
||||||
void* xrandr;
|
|
||||||
if(instance->config.libXrandr.length == 0)
|
|
||||||
xrandr = dlopen("libXrandr.so", RTLD_LAZY);
|
|
||||||
else
|
|
||||||
xrandr = dlopen(instance->config.libXrandr.chars, RTLD_LAZY);
|
|
||||||
|
|
||||||
if(xrandr == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
XRRMonitorInfo*(*ffXRRGetMonitors)(Display*, Window, Bool, int*) = dlsym(xrandr, "XRRGetMonitors");
|
|
||||||
if(ffXRRGetMonitors == NULL)
|
|
||||||
{
|
|
||||||
dlclose(xrandr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display* display = openDisplay(instance, xrandr, false);
|
|
||||||
if(display == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int numberOfMonitors;
|
|
||||||
XRRMonitorInfo* monitors = ffXRRGetMonitors(display, RootWindow(display, 0), False, &numberOfMonitors);
|
|
||||||
if(monitors == NULL)
|
|
||||||
{
|
|
||||||
closeDisplay(xrandr, display);
|
|
||||||
dlclose(xrandr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(numberOfMonitors < 1)
|
|
||||||
{
|
|
||||||
closeDisplay(xrandr, display);
|
|
||||||
dlclose(xrandr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int refreshRate = getCurrentRate(xrandr, display);
|
|
||||||
|
|
||||||
FFcache cache;
|
|
||||||
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &cache);
|
|
||||||
|
|
||||||
for(int i = 0; i < numberOfMonitors; i++)
|
|
||||||
{
|
|
||||||
uint8_t moduleIndex = numberOfMonitors == 1 ? 0 : i + 1;
|
|
||||||
printValue(instance, moduleIndex, &cache, monitors[i].width, monitors[i].height, refreshRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
ffCacheClose(&cache);
|
|
||||||
|
|
||||||
void(*ffXRRFreeMonitors)(XRRMonitorInfo*) = dlsym(xrandr, "XRRFreeMonitors");
|
|
||||||
if(ffXRRFreeMonitors != NULL)
|
|
||||||
ffXRRFreeMonitors(monitors);
|
|
||||||
|
|
||||||
dlclose(xrandr);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ffPrintResolution(FFinstance* instance)
|
void ffPrintResolution(FFinstance* instance)
|
||||||
{
|
{
|
||||||
if(ffPrintFromCache(instance, FF_RESOLUTION_MODULE_NAME, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS))
|
if(ffPrintFromCache(instance, FF_RESOLUTION_MODULE_NAME, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(printResolutionXrandrBackend(instance))
|
if(ffPrintResolutionWaylandBackend(instance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
printResolutionX11Backend(instance);
|
if(ffPrintResolutionXrandrBackend(instance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ffPrintResolutionX11Backend(instance);
|
||||||
}
|
}
|
||||||
|
14
src/modules/resolution.h
Normal file
14
src/modules/resolution.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "fastfetch.h"
|
||||||
|
|
||||||
|
#define FF_RESOLUTION_MODULE_NAME "Resolution"
|
||||||
|
#define FF_RESOLUTION_NUM_FORMAT_ARGS 3
|
||||||
|
|
||||||
|
//modules/resolution.c
|
||||||
|
void ffPrintResolutionValue(FFinstance* instance, uint8_t moduleIndex, FFcache* cache, int width, int height, int refreshRate);
|
||||||
|
|
||||||
|
//modules/resolution_wayland.c
|
||||||
|
bool ffPrintResolutionWaylandBackend(FFinstance* instance);
|
||||||
|
|
||||||
|
//modules/resolution_x11.c
|
||||||
|
bool ffPrintResolutionXrandrBackend(FFinstance* instance);
|
||||||
|
void ffPrintResolutionX11Backend(FFinstance* instance);
|
226
src/modules/resolution_wayland.c
Normal file
226
src/modules/resolution_wayland.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#include "resolution.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
typedef struct WaylandData
|
||||||
|
{
|
||||||
|
FFinstance* instance;
|
||||||
|
void* wayland;
|
||||||
|
FFcache cache;
|
||||||
|
struct wl_proxy*(*ffwl_proxy_marshal_constructor_versioned)(struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, ...);
|
||||||
|
int(*ffwl_proxy_add_listener)(struct wl_proxy*, void (**)(void), void *data);
|
||||||
|
void(*ffwl_proxy_destroy)(struct wl_proxy*);
|
||||||
|
const struct wl_interface* ffwl_output_interface;
|
||||||
|
struct wl_output_listener output_listener;
|
||||||
|
int8_t moduleCounter;
|
||||||
|
int8_t numModules;
|
||||||
|
} WaylandData;
|
||||||
|
|
||||||
|
static void waylandGlobalRemoveListener(void* data, struct wl_registry* wl_registry, uint32_t name){
|
||||||
|
UNUSED(data);
|
||||||
|
UNUSED(wl_registry);
|
||||||
|
UNUSED(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waylandOutputGeometryListener(void* data, struct wl_output* wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform)
|
||||||
|
{
|
||||||
|
UNUSED(data);
|
||||||
|
UNUSED(wl_output);
|
||||||
|
UNUSED(x);
|
||||||
|
UNUSED(y);
|
||||||
|
UNUSED(physical_width);
|
||||||
|
UNUSED(physical_height);
|
||||||
|
UNUSED(subpixel);
|
||||||
|
UNUSED(make);
|
||||||
|
UNUSED(model);
|
||||||
|
UNUSED(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waylandOutputDoneListener(void* data, struct wl_output* wl_output)
|
||||||
|
{
|
||||||
|
UNUSED(data);
|
||||||
|
UNUSED(wl_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waylandOutputScaleListener(void* data, struct wl_output* wl_output, int32_t factor)
|
||||||
|
{
|
||||||
|
UNUSED(data);
|
||||||
|
UNUSED(wl_output);
|
||||||
|
UNUSED(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseRefreshRate(int32_t refreshRate)
|
||||||
|
{
|
||||||
|
if(refreshRate <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
refreshRate /= 1000; //to Hz
|
||||||
|
|
||||||
|
int remainder = refreshRate % 5;
|
||||||
|
if(remainder >= 3)
|
||||||
|
refreshRate += (5 - remainder);
|
||||||
|
else
|
||||||
|
refreshRate -= remainder;
|
||||||
|
|
||||||
|
return refreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waylandOutputModeListener(void* data, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
|
||||||
|
{
|
||||||
|
if(!(flags & WL_OUTPUT_MODE_CURRENT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WaylandData* wldata = (WaylandData*) data;
|
||||||
|
|
||||||
|
++wldata->moduleCounter;
|
||||||
|
ffPrintResolutionValue(wldata->instance, wldata->numModules == 1 ? 0 : wldata->moduleCounter, &wldata->cache, width, height, parseRefreshRate(refreshRate));
|
||||||
|
|
||||||
|
if(wldata->ffwl_proxy_destroy != NULL)
|
||||||
|
wldata->ffwl_proxy_destroy((struct wl_proxy*) output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
|
||||||
|
{
|
||||||
|
if(strcmp(interface, "wl_output") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
WaylandData* wldata = (WaylandData*) data;
|
||||||
|
|
||||||
|
struct wl_output* output = (struct wl_output*) wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy *) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
|
||||||
|
if(output == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
++wldata->numModules;
|
||||||
|
wldata->ffwl_proxy_add_listener((struct wl_proxy*) output, (void(**)(void)) &wldata->output_listener, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void waylandDisplayDisconnect(void* wayland, struct wl_display* display)
|
||||||
|
{
|
||||||
|
void(*ffwl_display_disconnect)(struct wl_display*) = dlsym(wayland, "wl_display_disconnect");
|
||||||
|
if(ffwl_display_disconnect != NULL)
|
||||||
|
ffwl_display_disconnect(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ffPrintResolutionWaylandBackend(FFinstance* instance)
|
||||||
|
{
|
||||||
|
const char* sessionType = getenv("XDG_SESSION_TYPE");
|
||||||
|
if(sessionType != NULL && strcasecmp(sessionType, "wayland") != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
void* wayland;
|
||||||
|
if(instance->config.libWayland.length == 0)
|
||||||
|
wayland = dlopen("libwayland-client.so", RTLD_LAZY);
|
||||||
|
else
|
||||||
|
wayland = dlopen(instance->config.libWayland.chars, RTLD_LAZY);
|
||||||
|
|
||||||
|
if(wayland == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
WaylandData data;
|
||||||
|
data.instance = instance;
|
||||||
|
data.wayland = wayland;
|
||||||
|
data.moduleCounter = 0;
|
||||||
|
data.numModules = 0;
|
||||||
|
|
||||||
|
struct wl_display*(*ffwl_display_connect)(const char*) = dlsym(wayland, "wl_display_connect");
|
||||||
|
if(ffwl_display_connect == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int(*ffwl_display_dispatch)(struct wl_display*) = dlsym(wayland, "wl_display_dispatch");
|
||||||
|
if(ffwl_display_dispatch == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void(*ffwl_display_roundtrip)(struct wl_display*) = dlsym(wayland, "wl_display_roundtrip");
|
||||||
|
if(ffwl_display_roundtrip == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_proxy*(*ffwl_proxy_marshal_constructor)(struct wl_proxy*, uint32_t, const struct wl_interface*, ...) = dlsym(wayland, "wl_proxy_marshal_constructor");
|
||||||
|
if(ffwl_proxy_marshal_constructor == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.ffwl_proxy_marshal_constructor_versioned = dlsym(wayland, "wl_proxy_marshal_constructor_versioned");
|
||||||
|
if(data.ffwl_proxy_marshal_constructor_versioned == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.ffwl_proxy_add_listener = dlsym(wayland, "wl_proxy_add_listener");
|
||||||
|
if(data.ffwl_proxy_add_listener == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wl_interface* ffwl_registry_interface = dlsym(wayland, "wl_registry_interface");
|
||||||
|
if(ffwl_registry_interface == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.ffwl_output_interface = dlsym(wayland, "wl_output_interface");
|
||||||
|
if(data.ffwl_output_interface == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.ffwl_proxy_destroy = dlsym(wayland, "wl_proxy_destroy");
|
||||||
|
//We check for NULL before each call because this is just used for cleanup and not actually needed
|
||||||
|
|
||||||
|
struct wl_display* display = ffwl_display_connect(NULL);
|
||||||
|
if(display == NULL)
|
||||||
|
{
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_registry* registry = (struct wl_registry*) ffwl_proxy_marshal_constructor((struct wl_proxy*) display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL);
|
||||||
|
if(registry == NULL)
|
||||||
|
{
|
||||||
|
waylandDisplayDisconnect(wayland, display);
|
||||||
|
dlclose(wayland);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_registry_listener regestry_listener;
|
||||||
|
regestry_listener.global = waylandGlobalAddListener;
|
||||||
|
regestry_listener.global_remove = waylandGlobalRemoveListener;
|
||||||
|
|
||||||
|
data.output_listener.geometry = waylandOutputGeometryListener;
|
||||||
|
data.output_listener.mode = waylandOutputModeListener;
|
||||||
|
data.output_listener.done = waylandOutputDoneListener;
|
||||||
|
data.output_listener.scale = waylandOutputScaleListener;
|
||||||
|
|
||||||
|
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &data.cache);
|
||||||
|
|
||||||
|
data.ffwl_proxy_add_listener((struct wl_proxy*) registry, (void(**)(void)) ®estry_listener, &data);
|
||||||
|
ffwl_display_dispatch(display);
|
||||||
|
ffwl_display_roundtrip(display);
|
||||||
|
|
||||||
|
ffCacheClose(&data.cache);
|
||||||
|
|
||||||
|
if(data.ffwl_proxy_destroy != NULL)
|
||||||
|
data.ffwl_proxy_destroy((struct wl_proxy*) registry);
|
||||||
|
|
||||||
|
waylandDisplayDisconnect(wayland, display);
|
||||||
|
dlclose(wayland);
|
||||||
|
|
||||||
|
return data.numModules > 0;
|
||||||
|
}
|
169
src/modules/resolution_x11.c
Normal file
169
src/modules/resolution_x11.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "resolution.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
|
||||||
|
static Display* xOpenDisplay(FFinstance* instance, void* library, bool printErrors)
|
||||||
|
{
|
||||||
|
Display*(*ffXOpenDisplay)(const char*) = dlsym(library, "XOpenDisplay");
|
||||||
|
if(ffXOpenDisplay == NULL)
|
||||||
|
{
|
||||||
|
dlclose(library);
|
||||||
|
if(printErrors)
|
||||||
|
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "dlsym(library, \"XOpenDisplay\") == NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Display* display = ffXOpenDisplay(NULL);
|
||||||
|
if(display == NULL)
|
||||||
|
{
|
||||||
|
dlclose(library);
|
||||||
|
if(printErrors)
|
||||||
|
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "ffXOpenDisplay(NULL) == NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xCloseDisplay(void* library, Display* display)
|
||||||
|
{
|
||||||
|
int(*ffXCloseDisplay)(Display*) = dlsym(library, "XCloseDisplay");
|
||||||
|
if(ffXCloseDisplay != NULL)
|
||||||
|
ffXCloseDisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ffPrintResolutionX11Backend(FFinstance* instance)
|
||||||
|
{
|
||||||
|
void* x11;
|
||||||
|
if(instance->config.libX11.length == 0)
|
||||||
|
x11 = dlopen("libX11.so", RTLD_LAZY);
|
||||||
|
else
|
||||||
|
x11 = dlopen(instance->config.libX11.chars, RTLD_LAZY);
|
||||||
|
|
||||||
|
if(x11 == NULL)
|
||||||
|
{
|
||||||
|
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "dlopen(\"libX11.so\", RTLD_LAZY) == NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Display* display = xOpenDisplay(instance, x11, true);
|
||||||
|
if(display == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int screenCount = ScreenCount(display);
|
||||||
|
if(screenCount < 1)
|
||||||
|
{
|
||||||
|
xCloseDisplay(x11, display);
|
||||||
|
dlclose(x11);
|
||||||
|
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "ScreenCount(display) < 1: %i", screenCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FFcache cache;
|
||||||
|
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &cache);
|
||||||
|
|
||||||
|
for(int i = 0; i < screenCount; i++)
|
||||||
|
{
|
||||||
|
Screen* screen = ScreenOfDisplay(display, i);
|
||||||
|
uint8_t moduleIndex = screenCount == 1 ? 0 : i + 1;
|
||||||
|
ffPrintResolutionValue(instance, moduleIndex, &cache, WidthOfScreen(screen), HeightOfScreen(screen), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ffCacheClose(&cache);
|
||||||
|
|
||||||
|
xCloseDisplay(x11, display);
|
||||||
|
dlclose(x11);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xrandrGetCurrentRate(void* xrandr, Display* display)
|
||||||
|
{
|
||||||
|
XRRScreenConfiguration*(*ffXRRGetScreenInfo)(Display*, Window) = dlsym(xrandr, "XRRGetScreenInfo");
|
||||||
|
if(ffXRRGetScreenInfo == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
short(*ffXRRConfigCurrentRate)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRConfigCurrentRate");
|
||||||
|
if(ffXRRConfigCurrentRate == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
XRRMonitorInfo*(*ffXRRGetMonitors)(Display*, Window, Bool, int*) = dlsym(xrandr, "XRRGetMonitors");
|
||||||
|
if(ffXRRGetMonitors == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
void(*ffXRRFreeMonitors)(XRRMonitorInfo*) = dlsym(xrandr, "XRRFreeMonitors");
|
||||||
|
if(ffXRRFreeMonitors == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
XRRScreenConfiguration* xrrscreenconf = ffXRRGetScreenInfo(display, DefaultRootWindow(display));
|
||||||
|
if(xrrscreenconf == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
short currentRate = ffXRRConfigCurrentRate(xrrscreenconf);
|
||||||
|
|
||||||
|
void(*ffXRRFreeScreenConfigInfo)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRFreeScreenConfigInfo");
|
||||||
|
if(ffXRRFreeScreenConfigInfo != NULL)
|
||||||
|
ffXRRFreeScreenConfigInfo(xrrscreenconf);
|
||||||
|
|
||||||
|
return (int) currentRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ffPrintResolutionXrandrBackend(FFinstance* instance)
|
||||||
|
{
|
||||||
|
void* xrandr;
|
||||||
|
if(instance->config.libXrandr.length == 0)
|
||||||
|
xrandr = dlopen("libXrandr.so", RTLD_LAZY);
|
||||||
|
else
|
||||||
|
xrandr = dlopen(instance->config.libXrandr.chars, RTLD_LAZY);
|
||||||
|
|
||||||
|
if(xrandr == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
XRRMonitorInfo*(*ffXRRGetMonitors)(Display*, Window, Bool, int*) = dlsym(xrandr, "XRRGetMonitors");
|
||||||
|
if(ffXRRGetMonitors == NULL)
|
||||||
|
{
|
||||||
|
dlclose(xrandr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Display* display = xOpenDisplay(instance, xrandr, false);
|
||||||
|
if(display == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int numberOfMonitors;
|
||||||
|
XRRMonitorInfo* monitors = ffXRRGetMonitors(display, RootWindow(display, 0), False, &numberOfMonitors);
|
||||||
|
if(monitors == NULL)
|
||||||
|
{
|
||||||
|
xCloseDisplay(xrandr, display);
|
||||||
|
dlclose(xrandr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(numberOfMonitors < 1)
|
||||||
|
{
|
||||||
|
xCloseDisplay(xrandr, display);
|
||||||
|
dlclose(xrandr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int refreshRate = xrandrGetCurrentRate(xrandr, display);
|
||||||
|
|
||||||
|
FFcache cache;
|
||||||
|
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &cache);
|
||||||
|
|
||||||
|
for(int i = 0; i < numberOfMonitors; i++)
|
||||||
|
{
|
||||||
|
uint8_t moduleIndex = numberOfMonitors == 1 ? 0 : i + 1;
|
||||||
|
ffPrintResolutionValue(instance, moduleIndex, &cache, monitors[i].width, monitors[i].height, refreshRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
ffCacheClose(&cache);
|
||||||
|
|
||||||
|
void(*ffXRRFreeMonitors)(XRRMonitorInfo*) = dlsym(xrandr, "XRRFreeMonitors");
|
||||||
|
if(ffXRRFreeMonitors != NULL)
|
||||||
|
ffXRRFreeMonitors(monitors);
|
||||||
|
|
||||||
|
xCloseDisplay(xrandr, display);
|
||||||
|
dlclose(xrandr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user