summaryrefslogtreecommitdiff
path: root/WindowServer/WSMessageLoop.cpp
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-01-26 05:28:02 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-01-26 05:28:02 +0100
commitbba21adae377c2b1f1876adb0f877f62cdb075e9 (patch)
tree843ab0ef2d2c84956af7eebb60314983cd5b191e /WindowServer/WSMessageLoop.cpp
parent7cf3c7461c54ea6bdcfdbd47f1e2644ca5d0f35a (diff)
downloadserenity-bba21adae377c2b1f1876adb0f877f62cdb075e9.zip
WindowServer: Rename WSEvent to WSMessage.
Also do the same for WSMessageLoop and WSMessageReceiver. More to come.
Diffstat (limited to 'WindowServer/WSMessageLoop.cpp')
-rw-r--r--WindowServer/WSMessageLoop.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/WindowServer/WSMessageLoop.cpp b/WindowServer/WSMessageLoop.cpp
new file mode 100644
index 0000000000..16ebd8668d
--- /dev/null
+++ b/WindowServer/WSMessageLoop.cpp
@@ -0,0 +1,183 @@
+#include "WSMessageLoop.h"
+#include "WSMessage.h"
+#include "WSMessageReceiver.h"
+#include "WSWindowManager.h"
+#include "WSScreen.h"
+#include "PS2MouseDevice.h"
+#include <Kernel/Keyboard.h>
+#include <AK/Bitmap.h>
+#include "Process.h"
+
+//#define WSEVENTLOOP_DEBUG
+
+static WSMessageLoop* s_the;
+
+void WSMessageLoop::initialize()
+{
+ s_the = nullptr;
+}
+
+WSMessageLoop::WSMessageLoop()
+{
+ if (!s_the)
+ s_the = this;
+}
+
+WSMessageLoop::~WSMessageLoop()
+{
+}
+
+WSMessageLoop& WSMessageLoop::the()
+{
+ ASSERT(s_the);
+ return *s_the;
+}
+
+int WSMessageLoop::exec()
+{
+ m_server_process = current;
+
+ m_keyboard_fd = m_server_process->sys$open("/dev/keyboard", O_RDONLY);
+ m_mouse_fd = m_server_process->sys$open("/dev/psaux", O_RDONLY);
+
+ ASSERT(m_keyboard_fd >= 0);
+ ASSERT(m_mouse_fd >= 0);
+
+ m_running = true;
+ for (;;) {
+ wait_for_event();
+
+ Vector<QueuedEvent> events;
+ {
+ ASSERT_INTERRUPTS_ENABLED();
+ LOCKER(m_lock);
+ events = move(m_queued_events);
+ }
+
+ for (auto& queued_event : events) {
+ auto* receiver = queued_event.receiver;
+ auto& event = *queued_event.event;
+#ifdef WSEVENTLOOP_DEBUG
+ dbgprintf("WSMessageLoop: receiver{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
+#endif
+ if (!receiver) {
+ dbgprintf("WSMessage type %u with no receiver :(\n", event.type());
+ ASSERT_NOT_REACHED();
+ return 1;
+ } else {
+ receiver->event(event);
+ }
+ }
+ }
+}
+
+void WSMessageLoop::post_event(WSMessageReceiver* receiver, OwnPtr<WSMessage>&& event)
+{
+ ASSERT_INTERRUPTS_ENABLED();
+ LOCKER(m_lock);
+#ifdef WSEVENTLOOP_DEBUG
+ dbgprintf("WSMessageLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
+#endif
+
+ if (event->type() == WSMessage::WM_Invalidate) {
+ auto& invalidation_event = static_cast<WSWindowInvalidationEvent&>(*event);
+ for (auto& queued_event : m_queued_events) {
+ if (receiver == queued_event.receiver && queued_event.event->type() == WSMessage::WM_Invalidate) {
+ auto& queued_invalidation_event = static_cast<WSWindowInvalidationEvent&>(*queued_event.event);
+ if (queued_invalidation_event.rect().is_empty() || queued_invalidation_event.rect().contains(invalidation_event.rect())) {
+#ifdef WSEVENTLOOP_DEBUG
+ dbgprintf("Swallow WM_Invalidate\n");
+#endif
+ return;
+ }
+ }
+ }
+ }
+
+ if (event->type() == WSMessage::Paint) {
+ auto& invalidation_event = static_cast<WSPaintEvent&>(*event);
+ for (auto& queued_event : m_queued_events) {
+ if (receiver == queued_event.receiver && queued_event.event->type() == WSMessage::Paint) {
+ auto& queued_invalidation_event = static_cast<WSPaintEvent&>(*queued_event.event);
+ if (queued_invalidation_event.rect().is_empty() || queued_invalidation_event.rect().contains(invalidation_event.rect())) {
+#ifdef WSEVENTLOOP_DEBUG
+ dbgprintf("Swallow WM_Paint\n");
+#endif
+ return;
+ }
+ }
+ }
+ }
+
+ m_queued_events.append({ receiver, move(event) });
+
+ if (current != m_server_process)
+ m_server_process->request_wakeup();
+}
+
+void WSMessageLoop::wait_for_event()
+{
+ fd_set rfds;
+ memset(&rfds, 0, sizeof(rfds));
+ auto bitmap = Bitmap::wrap((byte*)&rfds, FD_SETSIZE);
+ bitmap.set(m_keyboard_fd, true);
+ bitmap.set(m_mouse_fd, true);
+ Syscall::SC_select_params params;
+ params.nfds = max(m_keyboard_fd, m_mouse_fd) + 1;
+ params.readfds = &rfds;
+ params.writefds = nullptr;
+ params.exceptfds = nullptr;
+ struct timeval timeout = { 0, 0 };
+ if (m_queued_events.is_empty())
+ params.timeout = nullptr;
+ else
+ params.timeout = &timeout;
+ int rc = m_server_process->sys$select(&params);
+ memory_barrier();
+ if (rc < 0) {
+ ASSERT_NOT_REACHED();
+ }
+
+ if (bitmap.get(m_keyboard_fd))
+ drain_keyboard();
+ if (bitmap.get(m_mouse_fd))
+ drain_mouse();
+}
+
+void WSMessageLoop::drain_mouse()
+{
+ auto& screen = WSScreen::the();
+ auto& mouse = PS2MouseDevice::the();
+ bool prev_left_button = screen.left_mouse_button_pressed();
+ bool prev_right_button = screen.right_mouse_button_pressed();
+ int dx = 0;
+ int dy = 0;
+ while (mouse.can_read(*m_server_process)) {
+ byte data[3];
+ ssize_t nread = mouse.read(*m_server_process, (byte*)data, sizeof(data));
+ ASSERT(nread == sizeof(data));
+ bool left_button = data[0] & 1;
+ bool right_button = data[0] & 2;
+ dx += data[1] ? (int)data[1] - (int)((data[0] << 4) & 0x100) : 0;
+ dy += data[2] ? (int)((data[0] << 3) & 0x100) - (int)data[2] : 0;
+ if (left_button != prev_left_button || right_button != prev_right_button || !mouse.can_read(*m_server_process)) {
+ prev_left_button = left_button;
+ prev_right_button = right_button;
+ screen.on_receive_mouse_data(dx, dy, left_button, right_button);
+ dx = 0;
+ dy = 0;
+ }
+ }
+}
+
+void WSMessageLoop::drain_keyboard()
+{
+ auto& screen = WSScreen::the();
+ auto& keyboard = Keyboard::the();
+ while (keyboard.can_read(*m_server_process)) {
+ Keyboard::Event event;
+ ssize_t nread = keyboard.read(*m_server_process, (byte*)&event, sizeof(Keyboard::Event));
+ ASSERT(nread == sizeof(Keyboard::Event));
+ screen.on_receive_keyboard_data(event);
+ }
+}