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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
#include "GEventLoop.h"
#include "GEvent.h"
#include "GObject.h"
#include "GWindow.h"
#include <LibC/unistd.h>
#include <LibC/stdio.h>
#include <LibC/fcntl.h>
#include <LibC/string.h>
#include <LibC/sys/select.h>
#include <LibC/gui.h>
//#define GEVENTLOOP_DEBUG
static GEventLoop* s_mainGEventLoop;
void GEventLoop::initialize()
{
s_mainGEventLoop = nullptr;
}
GEventLoop::GEventLoop()
{
if (!s_mainGEventLoop)
s_mainGEventLoop = this;
}
GEventLoop::~GEventLoop()
{
}
GEventLoop& GEventLoop::main()
{
ASSERT(s_mainGEventLoop);
return *s_mainGEventLoop;
}
int GEventLoop::exec()
{
m_event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (m_event_fd < 0) {
perror("GEventLoop::exec(): open");
exit(1);
}
m_running = true;
for (;;) {
if (m_queued_events.is_empty())
wait_for_event();
Vector<QueuedEvent> events = move(m_queued_events);
for (auto& queued_event : events) {
auto* receiver = queued_event.receiver;
auto& event = *queued_event.event;
#ifdef GEVENTLOOP_DEBUG
dbgprintf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
#endif
if (!receiver) {
switch (event.type()) {
case GEvent::Quit:
ASSERT_NOT_REACHED();
return 0;
default:
dbgprintf("event type %u with no receiver :(\n", event.type());
ASSERT_NOT_REACHED();
return 1;
}
} else {
receiver->event(event);
}
}
}
}
void GEventLoop::post_event(GObject* receiver, OwnPtr<GEvent>&& event)
{
#ifdef GEVENTLOOP_DEBUG
dbgprintf("GEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
#endif
m_queued_events.append({ receiver, move(event) });
}
void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window)
{
post_event(&window, make<GPaintEvent>(event.paint.rect));
}
void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
{
GMouseEvent::Type type;
switch (event.type) {
case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break;
case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break;
case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break;
default: ASSERT_NOT_REACHED(); break;
}
GMouseButton button { GMouseButton::None };
switch (event.mouse.button) {
case GUI_MouseButton::NoButton: button = GMouseButton::None; break;
case GUI_MouseButton::Left: button = GMouseButton::Left; break;
case GUI_MouseButton::Right: button = GMouseButton::Right; break;
case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
default: ASSERT_NOT_REACHED(); break;
}
post_event(&window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button));
}
void GEventLoop::wait_for_event()
{
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(m_event_fd, &rfds);
struct timeval timeout = { 0, 0 };
int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, m_queued_events.is_empty() ? nullptr : &timeout);
if (rc < 0) {
ASSERT_NOT_REACHED();
}
if (!FD_ISSET(m_event_fd, &rfds))
return;
for (;;) {
GUI_Event event;
ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event));
if (nread < 0) {
perror("read");
exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
}
if (nread == 0)
break;
assert(nread == sizeof(event));
auto* window = GWindow::from_window_id(event.window_id);
if (!window) {
dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
continue;
}
switch (event.type) {
case GUI_Event::Type::Paint:
dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
handle_paint_event(event, *window);
break;
case GUI_Event::Type::MouseDown:
case GUI_Event::Type::MouseUp:
case GUI_Event::Type::MouseMove:
dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
handle_mouse_event(event, *window);
break;
case GUI_Event::Type::WindowActivated:
dbgprintf("WID=%x WindowActivated\n", event.window_id);
break;
case GUI_Event::Type::WindowDeactivated:
dbgprintf("WID=%x WindowDeactivated\n", event.window_id);
break;
}
}
}
|