blob: 5f6f995424f6515c2a52315365216fd9e6eb0efb [file] [log] [blame]
// 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);
}
}
_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);
ReadEvent(this, connection, reinterpret_cast<uint8_t*>(xcb_event));
}
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