Chromium Code Reviews| Index: ui/events/platform/x11/x11_event_source_libevent.cc |
| diff --git a/ui/events/platform/x11/x11_event_source_libevent.cc b/ui/events/platform/x11/x11_event_source_libevent.cc |
| index a3ff7a50f94486676686ff6308f08c8938b7335a..41be11cca9abb23a231c495088b48f5bb976498b 100644 |
| --- a/ui/events/platform/x11/x11_event_source_libevent.cc |
| +++ b/ui/events/platform/x11/x11_event_source_libevent.cc |
| @@ -2,67 +2,200 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "ui/events/platform/x11/x11_event_source.h" |
| +#include "ui/events/platform/x11/x11_event_source_libevent.h" |
| #include <X11/Xlib.h> |
| +#include <X11/extensions/XInput2.h> |
| -#include "base/macros.h" |
| #include "base/message_loop/message_loop.h" |
| -#include "base/message_loop/message_pump_libevent.h" |
| +#include "ui/events/event.h" |
| +#include "ui/events/keycodes/keyboard_code_conversion_x.h" |
| +#include "ui/events/platform/platform_event_dispatcher.h" |
| +#include "ui/events/x/events_x_utils.h" |
| namespace ui { |
| namespace { |
| -class X11EventSourceLibevent : public X11EventSource, |
| - public base::MessagePumpLibevent::Watcher { |
| - public: |
| - explicit X11EventSourceLibevent(XDisplay* display) |
| - : X11EventSource(display), |
| - initialized_(false) { |
| - AddEventWatcher(); |
| +// Translates XI2 XEvent into a ui::Event. |
| +ui::Event* TranslateXI2EventToEvent(const XEvent& xev) { |
| + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); |
| + EventType event_type = EventTypeFromXEvent(xev); |
| + gfx::Point location = gfx::Point(xievent->event_x, xievent->event_y); |
| + 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
|
| + int flags = EventFlagsFromXEvent(xev); |
| + switch (event_type) { |
| + case ET_KEY_PRESSED: |
| + case ET_KEY_RELEASED: |
| + return new KeyEvent(event_type, KeyboardCodeFromXKeyEvent(&xev), flags); |
| + case ET_MOUSE_PRESSED: |
| + case ET_MOUSE_MOVED: |
| + case ET_MOUSE_DRAGGED: |
| + case ET_MOUSE_RELEASED: |
| + return new MouseEvent(event_type, location, root_location, |
| + EventTimeFromXEvent(xev), flags, |
| + GetChangedMouseButtonFlagsFromXEvent(xev)); |
| + case ET_MOUSEWHEEL: |
| + return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), location, |
| + root_location, EventTimeFromXEvent(xev), flags, |
| + GetChangedMouseButtonFlagsFromXEvent(xev)); |
| + case ET_SCROLL_FLING_START: |
| + case ET_SCROLL_FLING_CANCEL: { |
| + float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; |
| + GetFlingDataFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, |
| + &y_offset_ordinal, nullptr); |
| + return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), |
| + flags, x_offset, y_offset, x_offset_ordinal, |
| + y_offset_ordinal, 0); |
| + } |
| + case ET_SCROLL: { |
| + float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; |
| + int finger_count; |
| + GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, |
| + &y_offset_ordinal, &finger_count); |
| + return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), |
| + flags, x_offset, y_offset, x_offset_ordinal, |
| + y_offset_ordinal, finger_count); |
| + } |
| + case ET_TOUCH_MOVED: |
| + case ET_TOUCH_PRESSED: |
| + case ET_TOUCH_CANCELLED: |
| + case ET_TOUCH_RELEASED: |
| + return new TouchEvent(event_type, location, GetTouchIdFromXEvent(xev), |
| + EventTimeFromXEvent(xev)); |
| + case ET_UNKNOWN: |
| + return nullptr; |
| + default: |
| + break; |
| } |
| + return nullptr; |
| +} |
| - ~X11EventSourceLibevent() override { |
| +// Translates a XEvent into a ui::Event. |
| +ui::Event* TranslateXEventToEvent(const XEvent& xev) { |
| + int flags = EventFlagsFromXEvent(xev); |
| + switch (xev.type) { |
| + case LeaveNotify: |
| + case EnterNotify: |
| + // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is |
| + // not real mouse move event. |
| + // int flags = GetEventFlagsFromXState(xev.xcrossing.state); |
| + if (xev.type == EnterNotify) |
| + flags |= EF_IS_SYNTHESIZED; |
| + return new MouseEvent( |
| + ET_MOUSE_MOVED, gfx::Point(xev.xcrossing.x, xev.xcrossing.y), |
| + gfx::Point(xev.xcrossing.x_root, xev.xcrossing.y_root), |
| + EventTimeFromXEvent(xev), flags, 0); |
| + |
| + case KeyPress: |
| + case KeyRelease: |
| + return new KeyEvent(EventTypeFromXEvent(xev), |
| + KeyboardCodeFromXKeyEvent(&xev), flags); |
| + |
| + case ButtonPress: |
| + case ButtonRelease: { |
| + gfx::Point location = gfx::Point(xev.xbutton.x, xev.xbutton.y); |
| + gfx::Point root_location = |
| + gfx::Point(xev.xbutton.x_root, xev.xbutton.y_root); |
| + switch (EventTypeFromXEvent(xev)) { |
| + case ET_MOUSEWHEEL: |
| + return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), |
| + location, root_location, |
| + EventTimeFromXEvent(xev), flags, 0); |
| + case ET_MOUSE_PRESSED: |
| + case ET_MOUSE_RELEASED: |
| + return new MouseEvent(EventTypeFromXEvent(xev), location, |
| + root_location, EventTimeFromXEvent(xev), flags, |
| + GetChangedMouseButtonFlagsFromXEvent(xev)); |
| + case ET_UNKNOWN: |
| + // No event is created for X11-release events for mouse-wheel |
| + // buttons. |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + } |
| + |
| + case GenericEvent: |
| + return TranslateXI2EventToEvent(xev); |
| } |
|
sadrul
2016/02/08 17:28:32
Use Event[System]LocationFromXEvent in this functi
kylechar
2016/02/08 19:08:09
Done.
|
| + return nullptr; |
| +} |
| - private: |
| - void AddEventWatcher() { |
| - if (initialized_) |
| - return; |
| - if (!base::MessageLoop::current()) |
| - return; |
| - |
| - int fd = ConnectionNumber(display()); |
| - base::MessageLoopForUI::current()->WatchFileDescriptor(fd, true, |
| - base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, this); |
| - initialized_ = true; |
| - } |
| +} // namespace |
| - // PlatformEventSource: |
| - void OnDispatcherListChanged() override { |
| - AddEventWatcher(); |
| - } |
| +X11EventSourceLibevent::X11EventSourceLibevent(XDisplay* display) { |
| + event_source_.reset(new X11EventSource(this, display)); |
| + AddEventWatcher(); |
| +} |
| - // base::MessagePumpLibevent::Watcher: |
| - void OnFileCanReadWithoutBlocking(int fd) override { |
| - DispatchXEvents(); |
| - } |
| +X11EventSourceLibevent::~X11EventSourceLibevent() {} |
| + |
| +// static |
| +X11EventSourceLibevent* X11EventSourceLibevent::GetInstance() { |
| + return static_cast<X11EventSourceLibevent*>( |
| + PlatformEventSource::GetInstance()); |
| +} |
| - void OnFileCanWriteWithoutBlocking(int fd) override { |
| - NOTREACHED(); |
| +void X11EventSourceLibevent::ProcessXEvent(XEvent* xevent) { |
| + 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.
|
| + if (translated_event) { |
| + DispatchEvent(translated_event); |
| + } else { |
| + // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent |
| + // directly to XEventDispatchers. |
| + DispatchXEventToXEventDispatchers(xevent); |
| } |
| +} |
| - base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_; |
| - bool initialized_; |
| +void X11EventSourceLibevent::AddXEventDispatcher(XEventDispatcher* dispatcher) { |
| + dispatchers_xevent_.AddObserver(dispatcher); |
| +} |
| - DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent); |
| -}; |
| +void X11EventSourceLibevent::RemoveXEventDispatcher( |
| + XEventDispatcher* dispatcher) { |
| + dispatchers_xevent_.RemoveObserver(dispatcher); |
| +} |
| -} // namespace |
| +void X11EventSourceLibevent::StopCurrentEventStream() { |
| + event_source_->StopCurrentEventStream(); |
| +} |
| + |
| +void X11EventSourceLibevent::OnDispatcherListChanged() { |
| + AddEventWatcher(); |
| + event_source_->OnDispatcherListChanged(); |
| +} |
| + |
| +void X11EventSourceLibevent::AddEventWatcher() { |
| + if (initialized_) |
| + return; |
| + if (!base::MessageLoop::current()) |
| + return; |
| + |
| + int fd = ConnectionNumber(event_source_->display()); |
| + base::MessageLoopForUI::current()->WatchFileDescriptor( |
| + fd, true, base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, |
| + this); |
| + initialized_ = true; |
| +} |
| + |
| +void X11EventSourceLibevent::DispatchXEventToXEventDispatchers(XEvent* xevent) { |
| + if (dispatchers_xevent_.might_have_observers()) { |
| + base::ObserverList<XEventDispatcher>::Iterator iter(&dispatchers_xevent_); |
| + while (XEventDispatcher* dispatcher = iter.GetNext()) { |
| + if (dispatcher->DispatchXEvent(xevent)) |
| + break; |
| + } |
| + } |
| +} |
| + |
| +void X11EventSourceLibevent::OnFileCanReadWithoutBlocking(int fd) { |
| + event_source_->DispatchXEvents(); |
| +} |
| -scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() { |
| - return make_scoped_ptr(new X11EventSourceLibevent(gfx::GetXDisplay())); |
| +void X11EventSourceLibevent::OnFileCanWriteWithoutBlocking(int fd) { |
| + NOTREACHED(); |
| } |
| } // namespace ui |