1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/gfx/x/event.h"
6 
7 #include <xcb/xcb.h>
8 
9 #include <cstring>
10 
11 #include "base/check_op.h"
12 #include "base/memory/scoped_refptr.h"
13 #include "ui/gfx/x/connection.h"
14 #include "ui/gfx/x/xproto.h"
15 #include "ui/gfx/x/xproto_internal.h"
16 #include "ui/gfx/x/xproto_types.h"
17 
18 namespace x11 {
19 
20 Event::Event() = default;
21 
Event(scoped_refptr<base::RefCountedMemory> event_bytes,x11::Connection * connection,bool sequence_valid)22 Event::Event(scoped_refptr<base::RefCountedMemory> event_bytes,
23              x11::Connection* connection,
24              bool sequence_valid) {
25   auto* xcb_event = reinterpret_cast<xcb_generic_event_t*>(
26       const_cast<uint8_t*>(event_bytes->data()));
27   sequence_valid_ = sequence_valid;
28   sequence_ = xcb_event->full_sequence;
29   // KeymapNotify events are the only events that don't have a sequence.
30   if ((xcb_event->response_type & ~kSendEventMask) !=
31       x11::KeymapNotifyEvent::opcode) {
32     // On the wire, events are 32 bytes except for generic events which are
33     // trailed by additional data.  XCB inserts an extended 4-byte sequence
34     // between the 32-byte event and the additional data, so we need to shift
35     // the additional data over by 4 bytes so the event is back in its wire
36     // format, which is what Xlib and XProto are expecting.
37     if ((xcb_event->response_type & ~kSendEventMask) ==
38         x11::GeGenericEvent::opcode) {
39       auto* ge = reinterpret_cast<xcb_ge_event_t*>(xcb_event);
40       constexpr size_t ge_length = sizeof(xcb_raw_generic_event_t);
41       constexpr size_t offset = sizeof(ge->full_sequence);
42       size_t extended_length = ge->length * 4;
43       if (extended_length < ge_length) {
44         // If the additional data is smaller than the fixed size event, shift
45         // the additional data to the left.
46         memmove(&ge->full_sequence, &ge[1], extended_length);
47       } else {
48         // Otherwise shift the fixed size event to the right.
49         char* addr = reinterpret_cast<char*>(xcb_event);
50         memmove(addr + offset, addr, ge_length);
51         event_bytes = base::MakeRefCounted<OffsetRefCountedMemory>(
52             event_bytes, offset, ge_length + extended_length);
53         xcb_event = reinterpret_cast<xcb_generic_event_t*>(addr + offset);
54       }
55     }
56   }
57 
58   // Xlib sometimes modifies |xcb_event|, so let it handle the event after
59   // we parse it with ReadEvent().
60   ReadBuffer buf(event_bytes);
61   ReadEvent(this, connection, &buf);
62 }
63 
Event(Event && event)64 Event::Event(Event&& event) {
65   memcpy(this, &event, sizeof(Event));
66   memset(&event, 0, sizeof(Event));
67 }
68 
operator =(Event && event)69 Event& Event::operator=(Event&& event) {
70   Dealloc();
71   memcpy(this, &event, sizeof(Event));
72   memset(&event, 0, sizeof(Event));
73   return *this;
74 }
75 
~Event()76 Event::~Event() {
77   Dealloc();
78 }
79 
Dealloc()80 void Event::Dealloc() {
81   if (deleter_)
82     deleter_(event_);
83 }
84 
85 }  // namespace x11
86