summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc7
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_views.cc116
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_views.h17
-rw-r--r--chrome/browser/ui/browser_init.cc29
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/common/chrome_switches.cc5
-rw-r--r--chrome/common/chrome_switches.h4
-rw-r--r--views/event.h4
-rw-r--r--views/event_x.cc49
-rw-r--r--views/focus/accelerator_handler.h9
-rw-r--r--views/focus/accelerator_handler_touch.cc58
-rw-r--r--views/widget/root_view.cc6
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)