mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
better resolution detection
This commit is contained in:
@@ -101,8 +101,6 @@ set(SRCS
|
||||
src/modules/packages.c
|
||||
src/modules/shell.c
|
||||
src/modules/resolution.c
|
||||
src/modules/resolution_x11.c
|
||||
src/modules/resolution_wayland.c
|
||||
src/modules/de.c
|
||||
src/modules/wm.c
|
||||
src/modules/wmtheme.c
|
||||
|
||||
+413
-11
@@ -1,6 +1,25 @@
|
||||
#include "resolution.h"
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffPrintResolutionValue(FFinstance* instance, uint8_t moduleIndex, FFcache* cache, int width, int height, int refreshRate)
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#define FF_RESOLUTION_MODULE_NAME "Resolution"
|
||||
#define FF_RESOLUTION_NUM_FORMAT_ARGS 3
|
||||
|
||||
#define FF_LIBRARY_LOAD(libraryNameUser, libraryNameDefault) dlopen(libraryNameUser.length == 0 ? libraryNameDefault : libraryNameUser.chars, RTLD_LAZY); \
|
||||
if(dlerror() != NULL) \
|
||||
return false;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName) dlsym(library, symbolName); \
|
||||
if(dlerror() != NULL) { \
|
||||
dlclose(library); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
static void printResolution(FFinstance* instance, uint8_t moduleIndex, FFcache* cache, int width, int height, int refreshRate)
|
||||
{
|
||||
FFstrbuf value;
|
||||
ffStrbufInitA(&value, 32);
|
||||
@@ -16,16 +35,399 @@ void ffPrintResolutionValue(FFinstance* instance, uint8_t moduleIndex, FFcache*
|
||||
});
|
||||
}
|
||||
|
||||
typedef struct DRMData
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} DRMData;
|
||||
|
||||
static void printResolutionDRMBackend(FFinstance* instance)
|
||||
{
|
||||
const char* drmDirPath = "/sys/class/drm/";
|
||||
|
||||
DIR* dirp = opendir(drmDirPath);
|
||||
if(dirp == NULL)
|
||||
{
|
||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "Couldn't connect to a display server or open %s", drmDirPath);
|
||||
return;
|
||||
}
|
||||
|
||||
FFstrbuf drmDir;
|
||||
ffStrbufInitA(&drmDir, 64);
|
||||
ffStrbufAppendS(&drmDir, drmDirPath);
|
||||
|
||||
uint32_t drmDirLength = drmDir.length;
|
||||
|
||||
FFlist modes;
|
||||
ffListInitA(&modes, sizeof(DRMData), 4);
|
||||
|
||||
struct dirent* entry;
|
||||
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
ffStrbufAppendS(&drmDir, entry->d_name);
|
||||
ffStrbufAppendS(&drmDir, "/modes");
|
||||
|
||||
FILE* modeFile = fopen(drmDir.chars, "r");
|
||||
if(modeFile == NULL)
|
||||
{
|
||||
ffStrbufSubstrBefore(&drmDir, drmDirLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
DRMData* data = ffListAdd(&modes);
|
||||
data->width = 0;
|
||||
data->height = 0;
|
||||
fscanf(modeFile, "%ix%i", &data->width, &data->height);
|
||||
|
||||
if(data->width == 0 || data->height == 0)
|
||||
--modes.length;
|
||||
|
||||
fclose(modeFile);
|
||||
ffStrbufSubstrBefore(&drmDir, drmDirLength);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
ffStrbufDestroy(&drmDir);
|
||||
|
||||
if(modes.length == 0)
|
||||
{
|
||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "Couldn't connect to a display server or find a resolution in %s", drmDirPath);
|
||||
ffListDestroy(&modes);
|
||||
return;
|
||||
}
|
||||
|
||||
FFcache cache;
|
||||
ffCacheOpenWrite(instance, FF_RESOLUTION_MODULE_NAME, &cache);
|
||||
|
||||
for(uint32_t i = 0; i < modes.length; i++)
|
||||
{
|
||||
DRMData* data = ffListGet(&modes, i);
|
||||
printResolution(instance, modes.length == 1 ? 0 : i + 1, &cache, data->width, data->height, 0);
|
||||
}
|
||||
|
||||
ffCacheClose(&cache);
|
||||
|
||||
ffListDestroy(&modes);
|
||||
}
|
||||
|
||||
static Display* xOpenDisplay(void* library)
|
||||
{
|
||||
Display*(*ffXOpenDisplay)(const char*) = dlsym(library, "XOpenDisplay");
|
||||
if(dlerror() != NULL)
|
||||
return NULL;
|
||||
|
||||
Display* display = ffXOpenDisplay(NULL);
|
||||
if(display == NULL)
|
||||
return NULL;
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
static void xCloseDisplay(void* library, Display* display)
|
||||
{
|
||||
int(*ffXCloseDisplay)(Display*) = dlsym(library, "XCloseDisplay");
|
||||
if(dlerror() != NULL)
|
||||
ffXCloseDisplay(display);
|
||||
}
|
||||
|
||||
static bool printResolutionX11Backend(FFinstance* instance)
|
||||
{
|
||||
void* x11 = FF_LIBRARY_LOAD(instance->config.libX11, "libX11.so");
|
||||
|
||||
Display* display = xOpenDisplay(instance);
|
||||
if(display == NULL)
|
||||
{
|
||||
dlclose(x11);
|
||||
return false;
|
||||
}
|
||||
|
||||
int screenCount = ScreenCount(display);
|
||||
if(screenCount < 1)
|
||||
{
|
||||
xCloseDisplay(x11, display);
|
||||
dlclose(x11);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
printResolution(instance, moduleIndex, &cache, WidthOfScreen(screen), HeightOfScreen(screen), 0);
|
||||
}
|
||||
|
||||
ffCacheClose(&cache);
|
||||
|
||||
xCloseDisplay(x11, display);
|
||||
dlclose(x11);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int xrandrGetCurrentRate(void* xrandr, Display* display)
|
||||
{
|
||||
XRRScreenConfiguration*(*ffXRRGetScreenInfo)(Display*, Window) = dlsym(xrandr, "XRRGetScreenInfo");
|
||||
if(dlerror() != NULL)
|
||||
return 0;
|
||||
|
||||
short(*ffXRRConfigCurrentRate)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRConfigCurrentRate");
|
||||
if(dlerror() != NULL)
|
||||
return 0;
|
||||
|
||||
|
||||
XRRScreenConfiguration* xrrscreenconf = ffXRRGetScreenInfo(display, DefaultRootWindow(display));
|
||||
if(dlerror() != NULL)
|
||||
return 0;
|
||||
|
||||
short currentRate = ffXRRConfigCurrentRate(xrrscreenconf);
|
||||
|
||||
void(*ffXRRFreeScreenConfigInfo)(XRRScreenConfiguration*) = dlsym(xrandr, "XRRFreeScreenConfigInfo");
|
||||
if(dlerror() != NULL)
|
||||
ffXRRFreeScreenConfigInfo(xrrscreenconf);
|
||||
|
||||
return (int) currentRate;
|
||||
}
|
||||
|
||||
static bool printResolutionXrandrBackend(FFinstance* instance)
|
||||
{
|
||||
void* xrandr = FF_LIBRARY_LOAD(instance->config.libXrandr, "libXrandr.so");
|
||||
|
||||
XRRMonitorInfo*(*ffXRRGetMonitors)(Display*, Window, Bool, int*) = FF_LIBRARY_LOAD_SYMBOL(xrandr, "XRRGetMonitors");
|
||||
|
||||
Display* display = xOpenDisplay(instance);
|
||||
if(display == NULL)
|
||||
{
|
||||
dlclose(xrandr);
|
||||
return false;
|
||||
}
|
||||
|
||||
int numberOfMonitors;
|
||||
XRRMonitorInfo* monitors = ffXRRGetMonitors(display, DefaultRootWindow(display), 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;
|
||||
printResolution(instance, moduleIndex, &cache, monitors[i].width, monitors[i].height, refreshRate);
|
||||
}
|
||||
|
||||
ffCacheClose(&cache);
|
||||
|
||||
void(*ffXRRFreeMonitors)(XRRMonitorInfo*) = dlsym(xrandr, "XRRFreeMonitors");
|
||||
if(dlerror() != NULL)
|
||||
ffXRRFreeMonitors(monitors);
|
||||
|
||||
xCloseDisplay(xrandr, display);
|
||||
dlclose(xrandr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//All other typicall refresh rates are dividable by 5
|
||||
if(refreshRate == 145)
|
||||
refreshRate = 144;
|
||||
|
||||
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;
|
||||
printResolution(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(dlerror() != NULL)
|
||||
ffwl_display_disconnect(display);
|
||||
}
|
||||
|
||||
static bool printResolutionWaylandBackend(FFinstance* instance)
|
||||
{
|
||||
const char* sessionType = getenv("XDG_SESSION_TYPE");
|
||||
if(sessionType != NULL && strcasecmp(sessionType, "wayland") != 0)
|
||||
return false;
|
||||
|
||||
void* wayland = FF_LIBRARY_LOAD(instance->config.libWayland, "libwayland-client.so");
|
||||
|
||||
WaylandData data;
|
||||
data.instance = instance;
|
||||
data.wayland = wayland;
|
||||
data.moduleCounter = 0;
|
||||
data.numModules = 0;
|
||||
|
||||
struct wl_display*(*ffwl_display_connect)(const char*) = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_display_connect");
|
||||
int(*ffwl_display_dispatch)(struct wl_display*) = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_display_dispatch");
|
||||
void(*ffwl_display_roundtrip)(struct wl_display*) = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_display_roundtrip");
|
||||
struct wl_proxy*(*ffwl_proxy_marshal_constructor)(struct wl_proxy*, uint32_t, const struct wl_interface*, ...) = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_proxy_marshal_constructor");
|
||||
data.ffwl_proxy_marshal_constructor_versioned = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_proxy_marshal_constructor_versioned");
|
||||
data.ffwl_proxy_add_listener = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_proxy_add_listener");
|
||||
const struct wl_interface* ffwl_registry_interface = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_registry_interface");
|
||||
data.ffwl_output_interface = FF_LIBRARY_LOAD_SYMBOL(wayland, "wl_output_interface");
|
||||
|
||||
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
|
||||
if(dlerror() != NULL)
|
||||
data.ffwl_proxy_destroy = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void ffPrintResolution(FFinstance* instance)
|
||||
{
|
||||
if(ffPrintFromCache(instance, FF_RESOLUTION_MODULE_NAME, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS))
|
||||
return;
|
||||
if(
|
||||
ffPrintFromCache(instance, FF_RESOLUTION_MODULE_NAME, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS) ||
|
||||
printResolutionWaylandBackend(instance) ||
|
||||
printResolutionXrandrBackend(instance) ||
|
||||
printResolutionX11Backend(instance)
|
||||
) return;
|
||||
|
||||
if(ffPrintResolutionWaylandBackend(instance))
|
||||
return;
|
||||
|
||||
if(ffPrintResolutionXrandrBackend(instance))
|
||||
return;
|
||||
|
||||
ffPrintResolutionX11Backend(instance);
|
||||
printResolutionDRMBackend(instance);
|
||||
}
|
||||
|
||||
#undef FF_LIBRARY_LOAD
|
||||
#undef FF_LIBRARY_LOAD_SYMBOL
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#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);
|
||||
@@ -1,225 +0,0 @@
|
||||
#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;
|
||||
|
||||
//All other typicall refresh rates are dividable by 5
|
||||
if(refreshRate == 145)
|
||||
refreshRate = 144;
|
||||
|
||||
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 = dlopen(instance->config.libWayland.length == 0 ? "libwayland-client.so" : 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;
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
#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)
|
||||
{
|
||||
const char* libX11Name = instance->config.libX11.length == 0 ? "libX11.so" : instance->config.libX11.chars;
|
||||
void* x11 = dlopen(libX11Name, RTLD_LAZY);
|
||||
if(x11 == NULL)
|
||||
{
|
||||
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.resolutionKey, &instance->config.resolutionFormat, FF_RESOLUTION_NUM_FORMAT_ARGS, "dlopen(\"%s\", RTLD_LAZY) == NULL", libX11Name);
|
||||
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;
|
||||
|
||||
|
||||
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 = dlopen(instance->config.libXrandr.length == 0 ? "libXrandr.so" : 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, DefaultRootWindow(display), 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;
|
||||
}
|
||||
Reference in New Issue
Block a user