summaryrefslogtreecommitdiff
path: root/chromium/ui/gfx/x/event.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/gfx/x/event.cc')
-rw-r--r--chromium/ui/gfx/x/event.cc103
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