Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/events/platform/x11/x11_event_source.h" | 5 #include "ui/events/platform/x11/x11_event_source_libevent.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 | 8 #include <X11/extensions/XInput2.h> |
| 9 #include "base/macros.h" | 9 |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/message_loop/message_pump_libevent.h" | 11 #include "ui/events/event.h" |
| 12 #include "ui/events/keycodes/keyboard_code_conversion_x.h" | |
| 13 #include "ui/events/platform/platform_event_dispatcher.h" | |
| 14 #include "ui/events/x/events_x_utils.h" | |
| 12 | 15 |
| 13 namespace ui { | 16 namespace ui { |
| 14 | 17 |
| 15 namespace { | 18 namespace { |
| 16 | 19 |
| 17 class X11EventSourceLibevent : public X11EventSource, | 20 // Translates XI2 XEvent into a ui::Event. |
| 18 public base::MessagePumpLibevent::Watcher { | 21 ui::Event* TranslateXI2EventToEvent(const XEvent& xev) { |
| 19 public: | 22 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); |
| 20 explicit X11EventSourceLibevent(XDisplay* display) | 23 EventType event_type = EventTypeFromXEvent(xev); |
| 21 : X11EventSource(display), | 24 gfx::Point location = gfx::Point(xievent->event_x, xievent->event_y); |
| 22 initialized_(false) { | 25 gfx::Point root_location = gfx::Point(xievent->root_x, xievent->root_y); |
|
sadrul
2016/02/08 17:28:32
Can you use Event[System]LocationFromXEvent instea
kylechar
2016/02/08 19:08:09
Yep, Event[System]LocationFromXEvent works fine. A
| |
| 23 AddEventWatcher(); | 26 int flags = EventFlagsFromXEvent(xev); |
| 24 } | 27 switch (event_type) { |
| 25 | 28 case ET_KEY_PRESSED: |
| 26 ~X11EventSourceLibevent() override { | 29 case ET_KEY_RELEASED: |
| 27 } | 30 return new KeyEvent(event_type, KeyboardCodeFromXKeyEvent(&xev), flags); |
| 28 | 31 case ET_MOUSE_PRESSED: |
| 29 private: | 32 case ET_MOUSE_MOVED: |
| 30 void AddEventWatcher() { | 33 case ET_MOUSE_DRAGGED: |
| 31 if (initialized_) | 34 case ET_MOUSE_RELEASED: |
| 32 return; | 35 return new MouseEvent(event_type, location, root_location, |
| 33 if (!base::MessageLoop::current()) | 36 EventTimeFromXEvent(xev), flags, |
| 34 return; | 37 GetChangedMouseButtonFlagsFromXEvent(xev)); |
| 35 | 38 case ET_MOUSEWHEEL: |
| 36 int fd = ConnectionNumber(display()); | 39 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), location, |
| 37 base::MessageLoopForUI::current()->WatchFileDescriptor(fd, true, | 40 root_location, EventTimeFromXEvent(xev), flags, |
| 38 base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, this); | 41 GetChangedMouseButtonFlagsFromXEvent(xev)); |
| 39 initialized_ = true; | 42 case ET_SCROLL_FLING_START: |
| 40 } | 43 case ET_SCROLL_FLING_CANCEL: { |
| 41 | 44 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; |
| 42 // PlatformEventSource: | 45 GetFlingDataFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, |
| 43 void OnDispatcherListChanged() override { | 46 &y_offset_ordinal, nullptr); |
| 44 AddEventWatcher(); | 47 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), |
| 45 } | 48 flags, x_offset, y_offset, x_offset_ordinal, |
| 46 | 49 y_offset_ordinal, 0); |
| 47 // base::MessagePumpLibevent::Watcher: | 50 } |
| 48 void OnFileCanReadWithoutBlocking(int fd) override { | 51 case ET_SCROLL: { |
| 49 DispatchXEvents(); | 52 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; |
| 50 } | 53 int finger_count; |
| 51 | 54 GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, |
| 52 void OnFileCanWriteWithoutBlocking(int fd) override { | 55 &y_offset_ordinal, &finger_count); |
| 53 NOTREACHED(); | 56 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), |
| 54 } | 57 flags, x_offset, y_offset, x_offset_ordinal, |
| 55 | 58 y_offset_ordinal, finger_count); |
| 56 base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_; | 59 } |
| 57 bool initialized_; | 60 case ET_TOUCH_MOVED: |
| 58 | 61 case ET_TOUCH_PRESSED: |
| 59 DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent); | 62 case ET_TOUCH_CANCELLED: |
| 60 }; | 63 case ET_TOUCH_RELEASED: |
| 64 return new TouchEvent(event_type, location, GetTouchIdFromXEvent(xev), | |
| 65 EventTimeFromXEvent(xev)); | |
| 66 case ET_UNKNOWN: | |
| 67 return nullptr; | |
| 68 default: | |
| 69 break; | |
| 70 } | |
| 71 return nullptr; | |
| 72 } | |
| 73 | |
| 74 // Translates a XEvent into a ui::Event. | |
| 75 ui::Event* TranslateXEventToEvent(const XEvent& xev) { | |
| 76 int flags = EventFlagsFromXEvent(xev); | |
| 77 switch (xev.type) { | |
| 78 case LeaveNotify: | |
| 79 case EnterNotify: | |
| 80 // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is | |
| 81 // not real mouse move event. | |
| 82 // int flags = GetEventFlagsFromXState(xev.xcrossing.state); | |
| 83 if (xev.type == EnterNotify) | |
| 84 flags |= EF_IS_SYNTHESIZED; | |
| 85 return new MouseEvent( | |
| 86 ET_MOUSE_MOVED, gfx::Point(xev.xcrossing.x, xev.xcrossing.y), | |
| 87 gfx::Point(xev.xcrossing.x_root, xev.xcrossing.y_root), | |
| 88 EventTimeFromXEvent(xev), flags, 0); | |
| 89 | |
| 90 case KeyPress: | |
| 91 case KeyRelease: | |
| 92 return new KeyEvent(EventTypeFromXEvent(xev), | |
| 93 KeyboardCodeFromXKeyEvent(&xev), flags); | |
| 94 | |
| 95 case ButtonPress: | |
| 96 case ButtonRelease: { | |
| 97 gfx::Point location = gfx::Point(xev.xbutton.x, xev.xbutton.y); | |
| 98 gfx::Point root_location = | |
| 99 gfx::Point(xev.xbutton.x_root, xev.xbutton.y_root); | |
| 100 switch (EventTypeFromXEvent(xev)) { | |
| 101 case ET_MOUSEWHEEL: | |
| 102 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), | |
| 103 location, root_location, | |
| 104 EventTimeFromXEvent(xev), flags, 0); | |
| 105 case ET_MOUSE_PRESSED: | |
| 106 case ET_MOUSE_RELEASED: | |
| 107 return new MouseEvent(EventTypeFromXEvent(xev), location, | |
| 108 root_location, EventTimeFromXEvent(xev), flags, | |
| 109 GetChangedMouseButtonFlagsFromXEvent(xev)); | |
| 110 case ET_UNKNOWN: | |
| 111 // No event is created for X11-release events for mouse-wheel | |
| 112 // buttons. | |
| 113 break; | |
| 114 default: | |
| 115 NOTREACHED(); | |
| 116 } | |
| 117 break; | |
| 118 } | |
| 119 | |
| 120 case GenericEvent: | |
| 121 return TranslateXI2EventToEvent(xev); | |
| 122 } | |
|
sadrul
2016/02/08 17:28:32
Use Event[System]LocationFromXEvent in this functi
kylechar
2016/02/08 19:08:09
Done.
| |
| 123 return nullptr; | |
| 124 } | |
| 61 | 125 |
| 62 } // namespace | 126 } // namespace |
| 63 | 127 |
| 64 scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() { | 128 X11EventSourceLibevent::X11EventSourceLibevent(XDisplay* display) { |
| 65 return make_scoped_ptr(new X11EventSourceLibevent(gfx::GetXDisplay())); | 129 event_source_.reset(new X11EventSource(this, display)); |
| 130 AddEventWatcher(); | |
| 131 } | |
| 132 | |
| 133 X11EventSourceLibevent::~X11EventSourceLibevent() {} | |
| 134 | |
| 135 // static | |
| 136 X11EventSourceLibevent* X11EventSourceLibevent::GetInstance() { | |
| 137 return static_cast<X11EventSourceLibevent*>( | |
| 138 PlatformEventSource::GetInstance()); | |
| 139 } | |
| 140 | |
| 141 void X11EventSourceLibevent::ProcessXEvent(XEvent* xevent) { | |
| 142 base::NativeEvent translated_event = TranslateXEventToEvent(*xevent); | |
|
sadrul
2016/02/08 17:28:32
Looks like |translated_event| here is leaking? Upd
kylechar
2016/02/08 19:08:09
Yeah, good catch. Done.
| |
| 143 if (translated_event) { | |
| 144 DispatchEvent(translated_event); | |
| 145 } else { | |
| 146 // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent | |
| 147 // directly to XEventDispatchers. | |
| 148 DispatchXEventToXEventDispatchers(xevent); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void X11EventSourceLibevent::AddXEventDispatcher(XEventDispatcher* dispatcher) { | |
| 153 dispatchers_xevent_.AddObserver(dispatcher); | |
| 154 } | |
| 155 | |
| 156 void X11EventSourceLibevent::RemoveXEventDispatcher( | |
| 157 XEventDispatcher* dispatcher) { | |
| 158 dispatchers_xevent_.RemoveObserver(dispatcher); | |
| 159 } | |
| 160 | |
| 161 void X11EventSourceLibevent::StopCurrentEventStream() { | |
| 162 event_source_->StopCurrentEventStream(); | |
| 163 } | |
| 164 | |
| 165 void X11EventSourceLibevent::OnDispatcherListChanged() { | |
| 166 AddEventWatcher(); | |
| 167 event_source_->OnDispatcherListChanged(); | |
| 168 } | |
| 169 | |
| 170 void X11EventSourceLibevent::AddEventWatcher() { | |
| 171 if (initialized_) | |
| 172 return; | |
| 173 if (!base::MessageLoop::current()) | |
| 174 return; | |
| 175 | |
| 176 int fd = ConnectionNumber(event_source_->display()); | |
| 177 base::MessageLoopForUI::current()->WatchFileDescriptor( | |
| 178 fd, true, base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, | |
| 179 this); | |
| 180 initialized_ = true; | |
| 181 } | |
| 182 | |
| 183 void X11EventSourceLibevent::DispatchXEventToXEventDispatchers(XEvent* xevent) { | |
| 184 if (dispatchers_xevent_.might_have_observers()) { | |
| 185 base::ObserverList<XEventDispatcher>::Iterator iter(&dispatchers_xevent_); | |
| 186 while (XEventDispatcher* dispatcher = iter.GetNext()) { | |
| 187 if (dispatcher->DispatchXEvent(xevent)) | |
| 188 break; | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 void X11EventSourceLibevent::OnFileCanReadWithoutBlocking(int fd) { | |
| 194 event_source_->DispatchXEvents(); | |
| 195 } | |
| 196 | |
| 197 void X11EventSourceLibevent::OnFileCanWriteWithoutBlocking(int fd) { | |
| 198 NOTREACHED(); | |
| 66 } | 199 } |
| 67 | 200 |
| 68 } // namespace ui | 201 } // namespace ui |
| OLD | NEW |