diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/platform/gui/xcb/UiApplication.cpp | 26 | ||||
-rw-r--r-- | src/platform/gui/xcb/Window.cpp | 180 |
2 files changed, 199 insertions, 7 deletions
diff --git a/src/platform/gui/xcb/UiApplication.cpp b/src/platform/gui/xcb/UiApplication.cpp index 139a5422..619e71ef 100644 --- a/src/platform/gui/xcb/UiApplication.cpp +++ b/src/platform/gui/xcb/UiApplication.cpp @@ -1,8 +1,9 @@ -#include <cru/platform/gui/xcb/UiApplication.h> +#include "cru/platform/gui/xcb/UiApplication.h" + +#include "cru/platform/gui/xcb/Window.h" #include <poll.h> #include <xcb/xcb.h> -#include "cru/base/Base.h" namespace cru::platform::gui::xcb { XcbUiApplication::XcbUiApplication() { @@ -20,14 +21,20 @@ XcbUiApplication::XcbUiApplication() { this->screen_ = iter.data; } -XcbUiApplication::~XcbUiApplication() { xcb_disconnect(this->xcb_); } +XcbUiApplication::~XcbUiApplication() { xcb_disconnect(this->xcb_connection_); } void XcbUiApplication::CheckXcbConnectionError() { - if (xcb_connection_has_error(this->xcb_)) { + if (xcb_connection_has_error(this->xcb_connection_)) { throw XcbException("xcb_connection_has_error returned non-zero."); } } +xcb_connection_t *XcbUiApplication::GetXcbConnection() { + return xcb_connection_; +} + +xcb_screen_t *XcbUiApplication::GetFirstXcbScreen() { return screen_; } + int XcbUiApplication::Run() { auto exit_code = event_loop_.Run(); @@ -75,8 +82,15 @@ void XcbUiApplication::CancelTimer(long long id) { void XcbUiApplication::HandleXEvents() { xcb_generic_event_t *event; - while ((event = xcb_poll_for_event(xcb_))) { - NotImplemented(); + while ((event = xcb_poll_for_event(xcb_connection_))) { + auto event_xcb_window = XcbWindow::GetEventWindow(event); + for (auto window : windows_) { + if (window->GetXcbWindow() == event_xcb_window) { + window->HandleEvent(event); + break; + } + } + ::free(event); } } diff --git a/src/platform/gui/xcb/Window.cpp b/src/platform/gui/xcb/Window.cpp index cf4e059d..3494bc7d 100644 --- a/src/platform/gui/xcb/Window.cpp +++ b/src/platform/gui/xcb/Window.cpp @@ -1,11 +1,189 @@ #include "cru/platform/gui/xcb/Window.h" +#include "cru/platform/gui/Window.h" #include "cru/platform/gui/xcb/UiApplication.h" +#include <xcb/xcb.h> +#include <cinttypes> +#include <cstdint> + +namespace { +// TODO: Remove this demo function. +/* print names of modifiers present in mask */ +void print_modifiers(uint32_t mask) { + const char *MODIFIERS[] = { + "Shift", "Lock", "Ctrl", "Alt", "Mod2", "Mod3", "Mod4", + "Mod5", "Button1", "Button2", "Button3", "Button4", "Button5"}; + + printf("Modifier mask: "); + for (const char **modifier = MODIFIERS; mask; mask >>= 1, ++modifier) { + if (mask & 1) { + printf("%s", *modifier); + } + } + printf("\n"); +} + +} // namespace + namespace cru::platform::gui::xcb { -XcbWindow::XcbWindow(XcbUiApplication* application) +XcbWindow::XcbWindow(XcbUiApplication *application) : application_(application) { application->RegisterWindow(this); } XcbWindow::~XcbWindow() { application_->UnregisterWindow(this); } + +IEvent<MouseEnterLeaveType> *XcbWindow::MouseEnterLeaveEvent() { + return &mouse_enter_leave_event_; +} + +IEvent<Point> *XcbWindow::MouseMoveEvent() { return &mouse_move_event_; } + +std::optional<xcb_window_t> XcbWindow::GetXcbWindow() { return xcb_window_; } + +xcb_window_t XcbWindow::DoCreateWindow() { + auto connection = application_->GetXcbConnection(); + auto screen = application_->GetFirstXcbScreen(); + + auto xcb_window = xcb_generate_id(connection); + + uint32_t mask = XCB_CW_EVENT_MASK; + uint32_t values[1] = { + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE}; + + xcb_create_window(connection, XCB_COPY_FROM_PARENT, xcb_window, screen->root, + 100, 100, 400, 200, 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, + screen->root_visual, mask, values); + + return xcb_window; +} + +void XcbWindow::HandleEvent(xcb_generic_event_t *event) { + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: { + xcb_expose_event_t *expose = (xcb_expose_event_t *)event; + + printf("Window %" PRIu32 + " exposed. Region to be redrawn at location (%" PRIu16 ",%" PRIu16 + "), with dimension (%" PRIu16 ",%" PRIu16 ")\n", + expose->window, expose->x, expose->y, expose->width, + expose->height); + break; + } + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event; + print_modifiers(bp->state); + + switch (bp->detail) { + case 4: + printf("Wheel Button up in window %" PRIu32 + ", at coordinates (%" PRIi16 ",%" PRIi16 ")\n", + bp->event, bp->event_x, bp->event_y); + break; + case 5: + printf("Wheel Button down in window %" PRIu32 + ", at coordinates (%" PRIi16 ",%" PRIi16 ")\n", + bp->event, bp->event_x, bp->event_y); + break; + default: + printf("Button %" PRIu8 " pressed in window %" PRIu32 + ", at coordinates (%" PRIi16 ",%" PRIi16 ")\n", + bp->detail, bp->event, bp->event_x, bp->event_y); + break; + } + break; + } + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *br = (xcb_button_release_event_t *)event; + print_modifiers(br->state); + + printf("Button %" PRIu8 " released in window %" PRIu32 + ", at coordinates (%" PRIi16 ",%" PRIi16 ")\n", + br->detail, br->event, br->event_x, br->event_y); + break; + } + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event; + Point point(motion->event_x, motion->event_y); + mouse_move_event_.Raise(point); + break; + } + case XCB_ENTER_NOTIFY: { + xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event; + mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Enter); + Point point(enter->event_x, enter->event_y); + mouse_move_event_.Raise(point); + break; + } + case XCB_LEAVE_NOTIFY: { + xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)event; + // Should we do this? + // Point point(leave->event_x, leave->event_y); + // mouse_move_event_.Raise(point); + mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Leave); + break; + } + case XCB_KEY_PRESS: { + xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event; + print_modifiers(kp->state); + + printf("Key pressed in window %" PRIu32 "\n", kp->event); + break; + } + case XCB_KEY_RELEASE: { + xcb_key_release_event_t *kr = (xcb_key_release_event_t *)event; + print_modifiers(kr->state); + + printf("Key released in window %" PRIu32 "\n", kr->event); + break; + } + default: + /* Unknown event type, ignore it */ + printf("Unknown event: %" PRIu8 "\n", event->response_type); + break; + } +} + +std::optional<xcb_window_t> XcbWindow::GetEventWindow( + xcb_generic_event_t *event) { + switch (event->response_type & ~0x80) { + case XCB_EXPOSE: { + xcb_expose_event_t *expose = (xcb_expose_event_t *)event; + return expose->window; + } + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event; + return bp->event; + } + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *br = (xcb_button_release_event_t *)event; + return br->event; + } + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event; + return motion->event; + } + case XCB_ENTER_NOTIFY: { + xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event; + return enter->event; + } + case XCB_LEAVE_NOTIFY: { + xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)event; + return leave->event; + } + case XCB_KEY_PRESS: { + xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event; + return kp->event; + } + case XCB_KEY_RELEASE: { + xcb_key_release_event_t *kr = (xcb_key_release_event_t *)event; + return kr->event; + } + default: + return std::nullopt; + } +} } // namespace cru::platform::gui::xcb |