Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Unified Diff: ui/ozone/platform/x11/x11_event_factory.cc

Issue 1602173005: Add PlatformWindow/Event related code for Ozone X11. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Small fixes. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..cfc22b963f6a6c0b33774177c85264d86f02e6a9
--- /dev/null
+++ b/ui/ozone/platform/x11/x11_event_factory.cc
@@ -0,0 +1,318 @@
+// 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/X.h>
+#include <X11/XKBlib.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.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/gfx/x/x11_types.h"
+#include "ui/ozone/platform/x11/x11_surface_factory.h"
+#include "ui/ozone/platform/x11/x11_window_host.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+namespace {
+
+using TimeDelta = base::TimeDelta;
+
+int g_xinput_opcode = -1;
+
+bool InitializeXInput2(XDisplay* display) {
spang 2016/01/20 19:53:31 These look really easy to share with the X11 build
kylechar 2016/01/20 21:46:16 Good idea! I'll move that into a different CL.
+ if (!display)
+ return false;
+
+ int event, err;
+
+ int xiopcode;
+ if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
+ DVLOG(1) << "X Input extension not available.";
+ return false;
+ }
+ g_xinput_opcode = xiopcode;
+
+ int major = 2, minor = 2;
+ if (XIQueryVersion(display, &major, &minor) == BadRequest) {
+ DVLOG(1) << "XInput2 not supported in the server.";
+ return false;
+ }
+ if (major < 2 || (major == 2 && minor < 2)) {
+ DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
+ << "But 2.2 is required.";
+ return false;
+ }
+
+ return true;
+}
+
+bool InitializeXkb(XDisplay* display) {
+ if (!display)
+ return false;
+
+ int opcode, event, error;
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
+ DVLOG(1) << "Xkb extension not available.";
+ return false;
+ }
+
+ // Ask the server not to send KeyRelease event when the user holds down a key.
+ // crbug.com/138092
+ Bool supported_return;
+ if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
+ DVLOG(1) << "XKB not supported in the server.";
+ return false;
+ }
+
+ return true;
+}
+
+// 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<X11WindowHostManager> window_manager)
+ : display_(display), window_manager_(window_manager) {
+ CHECK(display_);
spang 2016/01/20 19:53:31 DCHECK for non-security assertions per chrome styl
kylechar 2016/01/20 21:46:16 Done.
+ DeviceDataManagerX11::CreateInstance();
+ InitializeXInput2(display_);
+ InitializeXkb(display_);
+ AddEventWatcher();
+}
+
+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);
+ }
+ 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.
+ X11WindowHost* window = window_manager_->FindWindow(xev.xany.window);
+ if (window)
+ window->ProcessXEvent(xev);
+ }
+ }
+}
+
+} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698