master ohmu/fastfetch-openbsd / src / detection / cursor / cursor_linux.c
ohmu  ·  2026-10-15
  1#include "cursor.h"
  2
  3#include "detection/gtk_qt/gtk_qt.h"
  4#include "detection/displayserver/displayserver.h"
  5#include "common/properties.h"
  6#include "common/parsing.h"
  7#include "common/settings.h"
  8#include "common/strutil.h"
  9
 10#include <stdlib.h>
 11
 12static bool detectCursorGTK(FFCursorResult* result) {
 13    const FFGTKResult* gtk = ffDetectGTK4();
 14
 15    if (gtk->cursor.length == 0) {
 16        gtk = ffDetectGTK3();
 17    }
 18
 19    if (gtk->cursor.length == 0) {
 20        gtk = ffDetectGTK2();
 21    }
 22
 23    if (gtk->cursor.length == 0) {
 24        return false;
 25    }
 26
 27    ffStrbufAppend(&result->theme, &gtk->cursor);
 28    ffStrbufAppend(&result->size, &gtk->cursorSize);
 29    return true;
 30}
 31
 32static void detectCursorFromConfigFile(const char* relativeFilePath, const char* themeStart, const char* themeDefault, const char* sizeStart, const char* sizeDefault, FFCursorResult* result) {
 33    if (ffParsePropFileConfigValues(relativeFilePath, 2, (FFpropquery[]) { { themeStart, &result->theme }, { sizeStart, &result->size } })) {
 34        if (result->theme.length == 0) {
 35            ffStrbufAppendS(&result->theme, themeDefault);
 36        }
 37
 38        if (result->size.length == 0) {
 39            ffStrbufAppendS(&result->size, sizeDefault);
 40        }
 41    }
 42
 43    if (result->theme.length == 0) {
 44        ffStrbufAppendF(&result->error, "Couldn't find cursor in %s", relativeFilePath);
 45    }
 46}
 47
 48static bool detectCursorFromXResources(FFCursorResult* result) {
 49    ffParsePropFileHomeValues(".Xresources", 2, (FFpropquery[]) { { "Xcursor.theme :", &result->theme }, { "Xcursor.size :", &result->size } });
 50
 51    return result->theme.length > 0;
 52}
 53
 54static bool detectCursorFromEnv(FFCursorResult* result) {
 55    const char* xcursor_theme = getenv("XCURSOR_THEME");
 56
 57    if (!ffStrSet(xcursor_theme)) {
 58        return false;
 59    }
 60
 61    ffStrbufAppendS(&result->theme, xcursor_theme);
 62    ffStrbufAppendS(&result->size, getenv("XCURSOR_SIZE"));
 63
 64    return true;
 65}
 66
 67static bool detectCursorHyprcursor(FFCursorResult* result) {
 68    const char* hyprcursor_theme = getenv("HYPRCURSOR_THEME");
 69
 70    if (!ffStrSet(hyprcursor_theme)) {
 71        return false;
 72    }
 73
 74    ffStrbufAppendS(&result->theme, hyprcursor_theme);
 75    ffStrbufAppendS(&result->size, getenv("HYPRCURSOR_SIZE"));
 76
 77    return true;
 78}
 79
 80void ffDetectCursor(FFCursorResult* result) {
 81    const FFDisplayServerResult* wmde = ffConnectDisplayServer();
 82
 83    if (ffStrbufEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_WSLG)) {
 84        ffStrbufAppendS(&result->error, "WSLg uses native windows cursor");
 85    } else if (ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY)) {
 86        ffStrbufAppendS(&result->error, "Cursor isn't supported in TTY");
 87    } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA)) {
 88        detectCursorFromConfigFile("kcminputrc", "cursorTheme =", "Breeze", "cursorSize =", "24", result);
 89    } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT)) {
 90        detectCursorFromConfigFile("lxqt/session.conf", "cursor_theme =", "Adwaita", "cursor_size =", "24", result);
 91    } else if (ffStrbufIgnCaseEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_HYPRLAND) && detectCursorHyprcursor(result)) {
 92        return;
 93    } else if (
 94        !detectCursorGTK(result) &&
 95        !detectCursorFromEnv(result) &&
 96        !ffParsePropFileHome(".icons/default/index.theme", "Inherits =", &result->theme) &&
 97        !detectCursorFromXResources(result) &&
 98        !ffParsePropFileData("icons/default/index.theme", "Inherits =", &result->theme)) {
 99        ffStrbufAppendS(&result->error, "Couldn't find cursor");
100    }
101}