diff options
Diffstat (limited to 'chromium/ui/gfx/x/event.cc')
-rw-r--r-- | chromium/ui/gfx/x/event.cc | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/chromium/ui/gfx/x/event.cc b/chromium/ui/gfx/x/event.cc new file mode 100644 index 00000000000..238e06bb656 --- /dev/null +++ b/chromium/ui/gfx/x/event.cc @@ -0,0 +1,103 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/x/event.h" + +#include <X11/Xlibint.h> +#include <X11/extensions/XInput2.h> + +// Xlibint.h defines those as macros, which breaks the C++ versions in +// the std namespace. +#undef max +#undef min + +#include <cstring> + +#include "ui/gfx/x/connection.h" + +namespace x11 { + +Event::Event() = default; + +Event::Event(xcb_generic_event_t* xcb_event, + x11::Connection* connection, + bool sequence_valid) { + XDisplay* display = connection->display(); + + sequence_valid_ = sequence_valid; + sequence_ = xcb_event->full_sequence; + // KeymapNotify events are the only events that don't have a sequence. + if ((xcb_event->response_type & ~kSendEventMask) != + x11::KeymapNotifyEvent::opcode) { + // Rewrite the sequence to the last seen sequence so that Xlib doesn't + // think the sequence wrapped around. + xcb_event->sequence = XLastKnownRequestProcessed(display); + + // On the wire, events are 32 bytes except for generic events which are + // trailed by additional data. XCB inserts an extended 4-byte sequence + // between the 32-byte event and the additional data, so we need to shift + // the additional data over by 4 bytes so the event is back in its wire + // format, which is what Xlib and XProto are expecting. + if ((xcb_event->response_type & ~kSendEventMask) == + x11::GeGenericEvent::opcode) { + auto* ge = reinterpret_cast<xcb_ge_event_t*>(xcb_event); + memmove(&ge->full_sequence, &ge[1], ge->length * 4); + } + } + + // Xlib sometimes modifies |xcb_event|, so let it handle the event after + // we parse it with ReadEvent(). + ReadEvent(this, connection, reinterpret_cast<uint8_t*>(xcb_event)); + + _XEnq(display, reinterpret_cast<xEvent*>(xcb_event)); + if (!XEventsQueued(display, QueuedAlready)) { + // If Xlib gets an event it doesn't recognize (eg. from an + // extension it doesn't know about), it won't add the event to the + // queue. In this case, zero-out the event data. This will set + // the event type to 0, which does not correspond to any event. + // This is safe because event handlers should always check the + // event type before downcasting to a concrete event. + memset(&xlib_event_, 0, sizeof(xlib_event_)); + return; + } + XNextEvent(display, &xlib_event_); + if (xlib_event_.type == x11::GeGenericEvent::opcode) + XGetEventData(display, &xlib_event_.xcookie); +} + +Event::Event(Event&& event) { + memcpy(this, &event, sizeof(Event)); + memset(&event, 0, sizeof(Event)); +} + +Event& Event::operator=(Event&& event) { + Dealloc(); + memcpy(this, &event, sizeof(Event)); + memset(&event, 0, sizeof(Event)); + return *this; +} + +Event::~Event() { + Dealloc(); +} + +void Event::Dealloc() { + if (xlib_event_.type == x11::GeGenericEvent::opcode && + xlib_event_.xcookie.data) { + if (custom_allocated_xlib_event_) { + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(xlib_event_.xcookie.data); + delete[] xiev->valuators.mask; + delete[] xiev->valuators.values; + delete[] xiev->buttons.mask; + delete xiev; + } else { + XFreeEventData(xlib_event_.xcookie.display, &xlib_event_.xcookie); + } + } + if (deleter_) + deleter_(event_); +} + +} // namespace x11 |