aboutsummaryrefslogtreecommitdiff
path: root/backend/drm/event.c
blob: db17b5b7f1bfe3327c814aee1c834fee35fc2cb5 (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
#include <stdbool.h>
#include <stdlib.h>
#include <poll.h>

#include "backend/drm/backend.h"
#include "backend/drm/event.h"
#include "backend/drm/drm.h"
#include "backend/drm/udev.h"

static inline void event_swap(struct wlr_drm_event *a, struct wlr_drm_event *b)
{
	struct wlr_drm_event tmp = *a;
	*a = *b;
	*b = tmp;
}

bool wlr_drm_get_event(struct wlr_drm_backend *backend,
		struct wlr_drm_event *restrict ret)
{
	struct pollfd fds[] = {
		{ .fd = backend->fd, .events = POLLIN },
		{ .fd = backend->udev.mon_fd, .events = POLLIN },
	};

	while (poll(fds, 2, 0) > 0) {
		if (fds[0].revents)
			wlr_drm_event(backend->fd);
		if (fds[1].revents)
			wlr_udev_event(backend);
	}

	if (backend->event_len == 0) {
		ret->type = DRM_EV_NONE;
		ret->display = NULL;
		return false;
	}

	struct wlr_drm_event *ev = backend->events;

	// Downheap
	*ret = ev[0];
	ev[0] = ev[--backend->event_len];

	size_t i = 0;
	while (i < backend->event_len / 2) {
		size_t left = i * 2 + 1;
		size_t right = i * 2 + 2;
		size_t max = (ev[left].type > ev[right].type) ? left : right;

		if (ev[i].type <= ev[max].type) {
			event_swap(&ev[i], &ev[max]);
			i = max;
		} else {
			break;
		}
	}

	return true;
}

bool wlr_drm_add_event(struct wlr_drm_backend *backend,
		struct wlr_drm_display *disp, enum wlr_drm_event_type type)
{
	if (type == DRM_EV_NONE)
		return true;

	if (backend->event_len == backend->event_cap) {
		size_t new_size = (backend->event_cap == 0) ? 8 : backend->event_cap * 2;

		struct wlr_drm_event *new = realloc(backend->events, sizeof *new * new_size);
		if (!new) {
			return false;
		}

		backend->event_cap = new_size;
		backend->events = new;
	}

	struct wlr_drm_event *ev = backend->events;

	// Upheap
	size_t i = backend->event_len++;
	ev[i].type = type;
	ev[i].display = disp;

	size_t j;
	while (i > 0 && ev[i].type > ev[(j = (i - 1) / 2)].type) {
		event_swap(&ev[i], &ev[j]);
		i = j;
	}

	return true;
}