diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-01-26 05:28:02 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-01-26 05:28:02 +0100 |
commit | bba21adae377c2b1f1876adb0f877f62cdb075e9 (patch) | |
tree | 843ab0ef2d2c84956af7eebb60314983cd5b191e /WindowServer/WSMessageLoop.cpp | |
parent | 7cf3c7461c54ea6bdcfdbd47f1e2644ca5d0f35a (diff) | |
download | serenity-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.cpp | 183 |
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(¶ms); + 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); + } +} |