Index: ui/ozone/platform/x11/x11_event_factory.cc |
diff --git a/ui/ozone/platform/x11/x11_event_factory.cc b/ui/ozone/platform/x11/x11_event_factory.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..acf38ffed454d80f0eccc99740c34a284752beb4 |
--- /dev/null |
+++ b/ui/ozone/platform/x11/x11_event_factory.cc |
@@ -0,0 +1,264 @@ |
+// Copyright 2016 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/ozone/platform/x11/x11_event_factory.h" |
+ |
+#include <X11/Xlib.h> |
+ |
+#include "base/logging.h" |
+#include "base/macros.h" |
+#include "ui/events/devices/x11/device_data_manager_x11.h" |
+#include "ui/events/event.h" |
+#include "ui/events/event_utils.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" |
+#include "ui/events/x/input_x.h" |
+#include "ui/gfx/x/x11_types.h" |
+#include "ui/ozone/platform/x11/x11_surface_factory.h" |
+#include "ui/ozone/platform/x11/x11_window_ozone.h" |
+#include "ui/ozone/public/ozone_platform.h" |
+#include "ui/ozone/public/surface_factory_ozone.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+using TimeDelta = base::TimeDelta; |
+ |
+// 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); |
+ 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, TimeDelta(), |
+ flags, GetChangedMouseButtonFlagsFromXEvent(xev)); |
+ case ET_MOUSEWHEEL: |
+ return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), location, |
+ root_location, TimeDelta(), 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; |
+} |
+ |
+// 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), TimeDelta(), |
+ 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, TimeDelta(), |
+ flags, 0); |
+ case ET_MOUSE_PRESSED: |
+ case ET_MOUSE_RELEASED: |
+ return new MouseEvent(EventTypeFromXEvent(xev), location, |
+ root_location, TimeDelta(), 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); |
+ } |
+ return nullptr; |
+} |
+ |
+} // namespace |
+ |
+X11EventFactory::X11EventFactory( |
+ XDisplay* display, |
+ scoped_refptr<X11WindowManagerOzone> window_manager) |
+ : display_(display), window_manager_(window_manager) { |
+ DCHECK(display_); |
+ DeviceDataManagerX11::CreateInstance(); |
+ InitializeXInput2(display_); |
+ InitializeXkb(display_); |
+ AddEventWatcher(); |
spang
2016/01/20 22:32:53
Does it need to be called here since it's called i
kylechar
2016/01/21 14:14:52
I'm not sure. It seems like it shouldn't need to b
sadrul
2016/01/21 14:53:01
I think in some tests, the message-loop is created
|
+} |
+ |
+X11EventFactory::~X11EventFactory() {} |
+ |
+// static |
+X11EventFactory* X11EventFactory::GetInstance() { |
+ return static_cast<X11EventFactory*>(PlatformEventSource::GetInstance()); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// X11EventFactory, public |
+ |
+void X11EventFactory::DispatchXEvents() { |
+ DCHECK(display_); |
+ // Handle all pending events. |
+ // It may be useful to eventually align this event dispatch with vsync, but |
+ // not yet. |
+ continue_stream_ = true; |
+ while (XPending(display_) && continue_stream_) { |
+ XEvent xevent; |
+ XNextEvent(display_, &xevent); |
+ ExtractCookieDataDispatchEvent(&xevent); |
+ } |
+} |
+ |
+void X11EventFactory::BlockUntilWindowMapped(XID window) { |
+ XEvent event; |
+ do { |
+ // Block until there's a message of |event_mask| type on |w|. Then remove |
+ // it from the queue and stuff it in |event|. |
+ XWindowEvent(display_, window, StructureNotifyMask, &event); |
+ ExtractCookieDataDispatchEvent(&event); |
+ } while (event.type != MapNotify); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// X11EventFactory, private |
+ |
+void X11EventFactory::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; |
+} |
+ |
+uint32_t X11EventFactory::ExtractCookieDataDispatchEvent(XEvent* xevent) { |
+ bool have_cookie = false; |
+ if (xevent->type == GenericEvent && |
+ XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { |
+ have_cookie = true; |
+ } |
+ uint32_t action = DispatchEvent(xevent); |
+ if (have_cookie) |
+ XFreeEventData(xevent->xgeneric.display, &xevent->xcookie); |
+ return action; |
+} |
+ |
+uint32_t X11EventFactory::DispatchEvent(base::NativeEvent event) { |
+ XEvent* xevent = static_cast<XEvent*>(event); |
+ uint32_t action = POST_DISPATCH_STOP_PROPAGATION; |
+ base::NativeEvent translated_event = TranslateXEventToEvent(*xevent); |
+ if (translated_event) { |
+ action = PlatformEventSource::DispatchEvent(translated_event); |
+ } else { |
+ DispatchXEventToXWindow(*xevent); |
spang
2016/01/20 22:32:53
Someday I hope we will be able to take this branch
|
+ } |
+ if (xevent->type == GenericEvent && |
+ xevent->xgeneric.evtype == XI_HierarchyChanged) { |
+ // TODO(kylechar): UpdateDeviceList() isn't calling X11 functions. |
+ ui::UpdateDeviceList(); |
+ } |
+ |
+ if (xevent->type == EnterNotify && |
+ xevent->xcrossing.detail != NotifyInferior && |
+ xevent->xcrossing.mode != NotifyUngrab) { |
+ // Clear stored scroll data |
+ DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses(); |
+ } |
+ return action; |
+} |
+ |
+void X11EventFactory::StopCurrentEventStream() { |
+ continue_stream_ = false; |
+} |
+ |
+void X11EventFactory::OnDispatcherListChanged() { |
+ AddEventWatcher(); |
+} |
+ |
+void X11EventFactory::OnFileCanReadWithoutBlocking(int fd) { |
+ DispatchXEvents(); |
+} |
+ |
+void X11EventFactory::OnFileCanWriteWithoutBlocking(int fd) { |
+ NOTREACHED(); |
+} |
+ |
+void X11EventFactory::DispatchXEventToXWindow(const XEvent& xev) { |
+ switch (xev.type) { |
+ case FocusOut: |
+ case Expose: |
+ case ConfigureNotify: |
+ case ClientMessage: { |
+ // This is a windowing message that needs to be passed to the platform |
+ // window directly. |
+ X11WindowOzone* window = window_manager_->FindWindow(xev.xany.window); |
+ if (window) |
+ window->ProcessXEvent(xev); |
+ } |
+ } |
+} |
+ |
+} // namespace ui |