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, >k->cursor);
28 ffStrbufAppend(&result->size, >k->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}