aboutsummaryrefslogtreecommitdiff
path: root/rootston/xcursor.c
blob: 6aa74bc41a2326994a8dca2ccc1885edbd68a615 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include "rootston/xcursor.h"
#include "rootston/input.h"

struct roots_xcursor_theme *roots_xcursor_theme_create(const char *name) {
	struct roots_xcursor_theme *theme =
		calloc(1, sizeof(struct roots_xcursor_theme));
	if (theme == NULL) {
		return NULL;
	}
	theme->name = strdup(name);
	wl_list_init(&theme->scaled_themes);
	return theme;
}

void roots_xcursor_theme_destroy(struct roots_xcursor_theme *theme) {
	if (theme == NULL) {
		return;
	}
	struct roots_xcursor_scaled_theme *scaled_theme, *tmp;
	wl_list_for_each_safe(scaled_theme, tmp, &theme->scaled_themes, link) {
		wl_list_remove(&scaled_theme->link);
		wlr_xcursor_theme_destroy(scaled_theme->theme);
		free(scaled_theme);
	}
	free(theme->name);
	free(theme);
}

int roots_xcursor_theme_load(struct roots_xcursor_theme *theme,
		uint32_t scale) {
	struct roots_xcursor_scaled_theme *scaled_theme;
	wl_list_for_each(scaled_theme, &theme->scaled_themes, link) {
		if (scaled_theme->scale == scale) {
			return 0;
		}
	}

	scaled_theme = calloc(1, sizeof(struct roots_xcursor_scaled_theme));
	if (scaled_theme == NULL) {
		return 1;
	}
	scaled_theme->scale = scale;
	scaled_theme->theme = wlr_xcursor_theme_load(NULL,
		ROOTS_XCURSOR_SIZE * scale);
	if (scaled_theme->theme == NULL) {
		free(scaled_theme);
		return 1;
	}
	wl_list_insert(&theme->scaled_themes, &scaled_theme->link);
	return 0;
}

static void roots_xcursor_theme_set(struct roots_xcursor_theme *theme,
		struct wlr_cursor *cursor, const char *name) {
	struct roots_xcursor_scaled_theme *scaled_theme;
	wl_list_for_each(scaled_theme, &theme->scaled_themes, link) {
		struct wlr_xcursor *xcursor =
			wlr_xcursor_theme_get_cursor(scaled_theme->theme, name);
		if (xcursor == NULL) {
			continue;
		}

		struct wlr_xcursor_image *image = xcursor->images[0];
		wlr_cursor_set_image(cursor, image->buffer, image->width,
			image->width, image->height, image->hotspot_x, image->hotspot_y,
			scaled_theme->scale);
	}
}

void roots_xcursor_theme_set_default(struct roots_xcursor_theme *theme,
		struct wlr_cursor *cursor) {
	roots_xcursor_theme_set(theme, cursor, "left_ptr");
}

void roots_xcursor_theme_set_move(struct roots_xcursor_theme *theme,
		struct wlr_cursor *cursor) {
	roots_xcursor_theme_set(theme, cursor, "grabbing");
}

static const char *get_resize_xcursor_name(uint32_t edges) {
	if (edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) {
		if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
			return "ne-resize";
		} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
			return "nw-resize";
		}
		return "n-resize";
	} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) {
		if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
			return "se-resize";
		} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
			return "sw-resize";
		}
		return "s-resize";
	} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
		return "e-resize";
	} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
		return "w-resize";
	}
	return "se-resize"; // fallback
}

void roots_xcursor_theme_set_resize(struct roots_xcursor_theme *theme,
		struct wlr_cursor *cursor, uint32_t edges) {
	roots_xcursor_theme_set(theme, cursor, get_resize_xcursor_name(edges));
}

void roots_xcursor_theme_set_rotate(struct roots_xcursor_theme *theme,
	struct wlr_cursor *cursor) {
	roots_xcursor_theme_set(theme, cursor, "grabbing");
}

void roots_xcursor_theme_xwayland_set_default(struct roots_xcursor_theme *theme,
		struct wlr_xwayland *xwayland) {
	struct roots_xcursor_scaled_theme *scaled_theme;
	wl_list_for_each(scaled_theme, &theme->scaled_themes, link) {
		if (scaled_theme->scale == 1) {
			struct wlr_xcursor *xcursor =
				wlr_xcursor_theme_get_cursor(scaled_theme->theme, "left_ptr");
			if (xcursor == NULL) {
				continue;
			}

			struct wlr_xcursor_image *image = xcursor->images[0];
			wlr_xwayland_set_cursor(xwayland, image->buffer, image->width,
				image->width, image->height, image->hotspot_x,
				image->hotspot_y);
			break;
		}
	}
}