diff options
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 4 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_views.cc | 116 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_views.h | 17 | ||||
-rw-r--r-- | chrome/browser/ui/browser_init.cc | 29 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 5 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 4 | ||||
-rw-r--r-- | views/event.h | 4 | ||||
-rw-r--r-- | views/event_x.cc | 49 | ||||
-rw-r--r-- | views/focus/accelerator_handler.h | 9 | ||||
-rw-r--r-- | views/focus/accelerator_handler_touch.cc | 58 | ||||
-rw-r--r-- | views/widget/root_view.cc | 6 |
13 files changed, 297 insertions, 13 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index cd1a472..7f84227 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -628,6 +628,13 @@ void RenderWidgetHost::ForwardEditCommandsForNextKeyEvent( // only handled by RenderView. } +#if defined(TOUCH_UI) +void RenderWidgetHost::ForwardTouchEvent( + const WebKit::WebTouchEvent& touch_event) { + ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false); +} +#endif + void RenderWidgetHost::RendererExited() { // Clearing this flag causes us to re-create the renderer when recovering // from a crashed renderer. diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 8514ce0..9f2225b 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -279,6 +279,10 @@ class RenderWidgetHost : public IPC::Channel::Listener, const std::string& value); virtual void ForwardEditCommandsForNextKeyEvent( const EditCommands& edit_commands); +#if defined(TOUCH_UI) + virtual void ForwardTouchEvent(const WebKit::WebTouchEvent& touch_event); +#endif + // Update the text direction of the focused input element and notify it to a // renderer process. diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.cc b/chrome/browser/renderer_host/render_widget_host_view_views.cc index 591e398..a9bc958 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_views.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_views.cc @@ -33,6 +33,7 @@ static const char* kRenderWidgetHostViewKey = "__RENDER_WIDGET_HOST_VIEW__"; using WebKit::WebInputEventFactory; using WebKit::WebMouseWheelEvent; +using WebKit::WebTouchEvent; namespace { @@ -51,6 +52,48 @@ int WebInputEventFlagsFromViewsEvent(const views::Event& event) { return modifiers; } +WebKit::WebTouchPoint::State TouchPointStateFromEvent( + const views::TouchEvent* event) { + switch (event->GetType()) { + case views::Event::ET_TOUCH_PRESSED: + return WebKit::WebTouchPoint::StatePressed; + case views::Event::ET_TOUCH_RELEASED: + return WebKit::WebTouchPoint::StateReleased; + case views::Event::ET_TOUCH_MOVED: + return WebKit::WebTouchPoint::StateMoved; + case views::Event::ET_TOUCH_CANCELLED: + return WebKit::WebTouchPoint::StateCancelled; + default: + return WebKit::WebTouchPoint::StateUndefined; + } +} + +WebKit::WebInputEvent::Type TouchEventTypeFromEvent( + const views::TouchEvent* event) { + switch (event->GetType()) { + case views::Event::ET_TOUCH_PRESSED: + return WebKit::WebInputEvent::TouchStart; + case views::Event::ET_TOUCH_RELEASED: + return WebKit::WebInputEvent::TouchEnd; + case views::Event::ET_TOUCH_MOVED: + return WebKit::WebInputEvent::TouchMove; + case views::Event::ET_TOUCH_CANCELLED: + return WebKit::WebInputEvent::TouchCancel; + default: + return WebKit::WebInputEvent::Undefined; + } +} + +void UpdateTouchPointPosition(const views::TouchEvent* event, + const gfx::Point& origin, + WebKit::WebTouchPoint* tpoint) { + tpoint->position.x = event->x(); + tpoint->position.y = event->y(); + + tpoint->screenPosition.x = tpoint->position.x + origin.x(); + tpoint->screenPosition.y = tpoint->position.y + origin.y(); +} + void InitializeWebMouseEventFromViewsEvent(const views::LocatedEvent& e, const gfx::Point& origin, WebKit::WebMouseEvent* wmevent) { @@ -78,7 +121,9 @@ RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host) is_loading_(false), native_cursor_(NULL), is_showing_context_menu_(false), - visually_deemphasized_(false) { + visually_deemphasized_(false), + touch_event_() + { SetFocusable(true); host_->set_view(this); } @@ -581,6 +626,75 @@ TODO(bryeung): key bindings host_->ForwardKeyboardEvent(event); } +bool RenderWidgetHostViewViews::OnTouchEvent(const views::TouchEvent& e) { + // Update the list of touch points first. + WebKit::WebTouchPoint* point = NULL; + + switch (e.GetType()) { + case views::Event::ET_TOUCH_PRESSED: + // Add a new touch point. + if (touch_event_.touchPointsLength < + WebTouchEvent::touchPointsLengthCap) { + point = &touch_event_.touchPoints[touch_event_.touchPointsLength++]; + point->id = e.identity(); + } + break; + case views::Event::ET_TOUCH_RELEASED: + case views::Event::ET_TOUCH_CANCELLED: + case views::Event::ET_TOUCH_MOVED: { + // The touch point should have been added to the event from an earlier + // _PRESSED event. So find that. + // At the moment, only a maximum of 4 touch-points are allowed. So a + // simple loop should be sufficient. + for (int i = 0; i < WebTouchEvent::touchPointsLengthCap; ++i) { + point = touch_event_.touchPoints + i; + if (point->id == e.identity()) { + break; + } + point = NULL; + } + DCHECK(point != NULL) << "Touchpoint not found for event " << e.GetType(); + break; + } + default: + DLOG(WARNING) << "Unknown touch event " << e.GetType(); + break; + } + + if (!point) + return false; + + // Update the location and state of the point. + UpdateTouchPointPosition(&e, GetPosition(), point); + point->state = TouchPointStateFromEvent(&e); + + // Mark the rest of the points as stationary. + for (int i = 0; i < touch_event_.touchPointsLength; ++i) { + WebKit::WebTouchPoint* iter = touch_event_.touchPoints + i; + if (iter != point) { + iter->state = WebKit::WebTouchPoint::StateStationary; + } + } + + // Update the type of the touch event. + touch_event_.type = TouchEventTypeFromEvent(&e); + + // The event and all the touches have been updated. Dispatch. + host_->ForwardTouchEvent(touch_event_); + + // If the touch was released, then remove it from the list of touch points. + if (e.GetType() == views::Event::ET_TOUCH_RELEASED) { + --touch_event_.touchPointsLength; + for (int i = point - touch_event_.touchPoints; + i < touch_event_.touchPointsLength; + ++i) { + touch_event_.touchPoints[i] = touch_event_.touchPoints[i + 1]; + } + } + + return true; +} + // static RenderWidgetHostView* RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView( diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.h b/chrome/browser/renderer_host/render_widget_host_view_views.h index 88a4746..0689fbe 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_views.h +++ b/chrome/browser/renderer_host/render_widget_host_view_views.h @@ -14,6 +14,7 @@ #include "base/time.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "gfx/native_widget_types.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" #include "views/controls/native/native_view_host.h" #include "views/event.h" #include "views/view.h" @@ -22,10 +23,6 @@ class RenderWidgetHost; struct NativeWebKeyboardEvent; -namespace WebKit { -class WebMouseEvent; -} - // ----------------------------------------------------------------------------- // See comments in render_widget_host_view.h about this class and its members. // ----------------------------------------------------------------------------- @@ -85,7 +82,7 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView, gfx::NativeCursor GetCursorForPoint(views::Event::EventType type, const gfx::Point& point); - // Views mouse events + // Views mouse events, overridden from views::View. virtual bool OnMousePressed(const views::MouseEvent& event); virtual bool OnMouseDragged(const views::MouseEvent& event); virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); @@ -94,7 +91,7 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView, virtual void OnMouseExited(const views::MouseEvent& event); virtual bool OnMouseWheel(const views::MouseWheelEvent& e); - // Views keyboard events + // Views keyboard events, overridden from views::View. virtual bool OnKeyPressed(const views::KeyEvent &e); virtual bool OnKeyReleased(const views::KeyEvent &e); @@ -104,6 +101,9 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView, // Forwards a keyboard event to renderer. void ForwardKeyboardEvent(const NativeWebKeyboardEvent& event); + // Views touch events, overridden from views::View. + virtual bool OnTouchEvent(const views::TouchEvent& e); + private: friend class RenderWidgetHostViewViewsWidget; @@ -162,6 +162,11 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView, // The size that we want the renderer to be. gfx::Size requested_size_; + // The touch-event. Its touch-points are updated as necessary. A new + // touch-point is added from an ET_TOUCH_PRESSED event, and a touch-point is + // removed from the list on an ET_TOUCH_RELEASED event. + WebKit::WebTouchEvent touch_event_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewViews); }; diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc index 9d1e89c..ac4932d 100644 --- a/chrome/browser/ui/browser_init.cc +++ b/chrome/browser/ui/browser_init.cc @@ -15,6 +15,7 @@ #include "base/path_service.h" #include "base/scoped_ptr.h" #include "base/string_number_conversions.h" +#include "base/string_split.h" #include "base/thread_restrictions.h" #include "base/utf_string_conversions.h" #include "chrome/browser/automation/automation_provider.h" @@ -96,6 +97,10 @@ #include "chrome/browser/dom_ui/mediaplayer_ui.h" #endif +#if defined(HAVE_XINPUT2) +#include "views/focus/accelerator_handler.h" +#endif + namespace { class SetAsDefaultBrowserTask : public Task { @@ -1017,6 +1022,30 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, } #endif +#if defined(HAVE_XINPUT2) + // Get a list of pointer-devices that should be treated as touch-devices. + // TODO(sad): Instead of/in addition to getting the list from the + // command-line, query X for a list of touch devices. + std::string touch_devices = + command_line.GetSwitchValueASCII(switches::kTouchDevices); + + if (!touch_devices.empty()) { + std::vector<std::string> devs; + std::vector<unsigned int> device_ids; + unsigned int devid; + base::SplitString(touch_devices, ',', &devs); + for (std::vector<std::string>::iterator iter = devs.begin(); + iter != devs.end(); ++iter) { + if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) { + device_ids.push_back(devid); + } else { + DLOG(WARNING) << "Invalid touch-device id: " << *iter; + } + } + views::SetTouchDeviceList(device_ids); + } +#endif + // If we don't want to launch a new browser window or tab (in the case // of an automation request), we are done here. if (!silent_launch) { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 62185c6..41123a0 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3472,6 +3472,7 @@ '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:gtkprint', '../build/linux/system.gyp:nss', + '../build/linux/system.gyp:x11', '../third_party/undoview/undoview.gyp:undoview', ], 'link_settings': { @@ -3545,6 +3546,7 @@ '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:gtkprint', '../build/linux/system.gyp:nss', + '../build/linux/system.gyp:x11', ], 'sources': [ 'browser/file_path_watcher_stub.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 34dbc28..8e99e8e 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -1313,6 +1313,11 @@ const char kSetToken[] = "set-token"; const char kWebSocketLiveExperimentHost[] = "websocket-live-experiment-host"; #endif +#if defined(HAVE_XINPUT2) +const char kTouchDevices[] = "touch-devices"; +#endif + + // USE_SECCOMP_SANDBOX controls whether the seccomp sandbox is opt-in or -out. // TODO(evan): unify all of these once we turn the seccomp sandbox always // on. Also remove the #include of command_line.h above. diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 422cb40..1154171 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -390,6 +390,10 @@ extern const char kWebSocketLiveExperimentHost[]; extern const char kRendererCheckFalseTest[]; #endif +#if defined(HAVE_XINPUT2) +extern const char kTouchDevices[]; +#endif + #if defined(USE_SECCOMP_SANDBOX) extern const char kDisableSeccompSandbox[]; #else diff --git a/views/event.h b/views/event.h index ab9abf3..1ec666d 100644 --- a/views/event.h +++ b/views/event.h @@ -297,6 +297,10 @@ class TouchEvent : public LocatedEvent { // from 'from' coordinate system to 'to' coordinate system. TouchEvent(const TouchEvent& model, View* from, View* to); +#if defined(HAVE_XINPUT2) + explicit TouchEvent(XEvent* xev); +#endif + // Return the touch point for this event. bool identity() const { return touch_id_; diff --git a/views/event_x.cc b/views/event_x.cc index 60b0d2f..774aa7f 100644 --- a/views/event_x.cc +++ b/views/event_x.cc @@ -71,6 +71,46 @@ int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { return buttonflags; } + +Event::EventType GetTouchEventType(XEvent* xev) { + XGenericEventCookie* cookie = &xev->xcookie; + switch (cookie->evtype) { + case XI_ButtonPress: + return Event::ET_TOUCH_PRESSED; + case XI_ButtonRelease: + return Event::ET_TOUCH_RELEASED; + case XI_Motion: + return Event::ET_TOUCH_MOVED; + + // Note: We will not generate a _STATIONARY event here. It will be created, + // when necessary, by a RWHVV. + + // TODO(sad): When do we trigger a _CANCELLED event? Maybe that will also be + // done by a RWHVV, e.g. when it gets destroyed in the middle of a + // touch-sequence? + } + + return Event::ET_UNKNOWN; +} + +gfx::Point GetTouchEventLocation(XEvent* xev) { + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); + return gfx::Point(xiev->event_x, xiev->event_y); +} + +int GetTouchEventFlags(XEvent* xev) { + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); + return GetButtonMaskForX2Event(xiev) | + GetEventFlagsFromXState(xiev->mods.effective); +} + +int GetTouchIDFromXEvent(XEvent* xev) { + // TODO(sad): How we determine the touch-id from the event is as yet + // undecided. + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); + return xiev->sourceid; +} + #endif // HAVE_XINPUT2 Event::EventType GetMouseEventType(XEvent* xev) { @@ -182,4 +222,13 @@ MouseWheelEvent::MouseWheelEvent(XEvent* xev) // used for GTK+. } +#if defined(HAVE_XINPUT2) +TouchEvent::TouchEvent(XEvent* xev) + : LocatedEvent(GetTouchEventType(xev), + GetTouchEventLocation(xev), + GetTouchEventFlags(xev)), + touch_id_(GetTouchIDFromXEvent(xev)) { +} +#endif + } // namespace views diff --git a/views/focus/accelerator_handler.h b/views/focus/accelerator_handler.h index 088f3f1..2d08e47 100644 --- a/views/focus/accelerator_handler.h +++ b/views/focus/accelerator_handler.h @@ -13,6 +13,7 @@ #endif #include <set> +#include <vector> #include "base/message_loop.h" @@ -22,7 +23,13 @@ namespace views { // Dispatch an XEvent to the RootView. Return true if the event was dispatched // and handled, false otherwise. bool DispatchXEvent(XEvent* xevent); -#endif + +#if defined(HAVE_XINPUT2) +// Keep a list of touch devices so that it is possible to determine if a pointer +// event is a touch-event or a mouse-event. +void SetTouchDeviceList(std::vector<unsigned int>& devices); +#endif // HAVE_XINPUT2 +#endif // TOUCH_UI // This class delegates the key messages to the associated FocusManager class // for the window that is receiving these messages for accelerator processing. diff --git a/views/focus/accelerator_handler_touch.cc b/views/focus/accelerator_handler_touch.cc index aa971d5..a35fc45 100644 --- a/views/focus/accelerator_handler_touch.cc +++ b/views/focus/accelerator_handler_touch.cc @@ -4,6 +4,7 @@ #include "views/focus/accelerator_handler.h" +#include <bitset> #include <gtk/gtk.h> #if defined(HAVE_XINPUT2) #include <X11/extensions/XInput2.h> @@ -19,6 +20,36 @@ namespace views { +#if defined(HAVE_XINPUT2) +// Functions related to determining touch devices. +class TouchFactory { + public: + // Keep a list of touch devices so that it is possible to determine if a + // pointer event is a touch-event or a mouse-event. + static void SetTouchDeviceListInternal( + const std::vector<unsigned int>& devices) { + for (std::vector<unsigned int>::const_iterator iter = devices.begin(); + iter != devices.end(); ++iter) { + DCHECK(*iter < touch_devices.size()); + touch_devices[*iter] = true; + } + } + + // Is the device a touch-device? + static bool IsTouchDevice(unsigned int deviceid) { + return deviceid < touch_devices.size() ? touch_devices[deviceid] : false; + } + + private: + // A quick lookup table for determining if a device is a touch device. + static std::bitset<128> touch_devices; + + DISALLOW_COPY_AND_ASSIGN(TouchFactory); +}; + +std::bitset<128> TouchFactory::touch_devices; +#endif + namespace { RootView* FindRootViewForGdkWindow(GdkWindow* gdk_window) { @@ -41,7 +72,18 @@ RootView* FindRootViewForGdkWindow(GdkWindow* gdk_window) { #if defined(HAVE_XINPUT2) bool X2EventIsTouchEvent(XEvent* xev) { // TODO(sad): Determine if the captured event is a touch-event. - return false; + XGenericEventCookie* cookie = &xev->xcookie; + switch (cookie->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_Motion: { + // Is the event coming from a touch device? + return TouchFactory::IsTouchDevice( + static_cast<XIDeviceEvent*>(cookie->data)->sourceid); + } + default: + return false; + } } #endif // HAVE_XINPUT2 @@ -50,13 +92,13 @@ bool X2EventIsTouchEvent(XEvent* xev) { #if defined(HAVE_XINPUT2) bool DispatchX2Event(RootView* root, XEvent* xev) { if (X2EventIsTouchEvent(xev)) { - // TODO(sad): Create a TouchEvent, and send it off to |root|. If the event + // Create a TouchEvent, and send it off to |root|. If the event // is processed by |root|, then return. Otherwise let it fall through so it // can be used (if desired) as a mouse event. - // TouchEvent touch(xev); - // if (root->OnTouchEvent(touch)) - // return true; + TouchEvent touch(xev); + if (root->OnTouchEvent(touch)) + return true; } XGenericEventCookie* cookie = &xev->xcookie; @@ -171,6 +213,12 @@ bool DispatchXEvent(XEvent* xev) { return false; } +#if defined(HAVE_XINPUT2) +void SetTouchDeviceList(std::vector<unsigned int>& devices) { + TouchFactory::SetTouchDeviceListInternal(devices); +} +#endif + AcceleratorHandler::AcceleratorHandler() {} bool AcceleratorHandler::Dispatch(GdkEvent* event) { diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc index 753e9de..92f6cf7 100644 --- a/views/widget/root_view.cc +++ b/views/widget/root_view.cc @@ -285,6 +285,12 @@ void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { default_keyboard_handler_ = NULL; } +#if defined(TOUCH_UI) + if (touch_pressed_handler_) { + touch_pressed_handler_ = NULL; + } +#endif + FocusManager* focus_manager = widget_->GetFocusManager(); // An unparanted RootView does not have a FocusManager. if (focus_manager) |