summaryrefslogtreecommitdiffstats
path: root/content/browser/renderer_host/render_widget_host_view_gtk.cc
diff options
context:
space:
mode:
authorscheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-11 19:00:53 +0000
committerscheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-11 19:00:53 +0000
commit57e02bedcb1a410fef4b67bf67ebd710de65b205 (patch)
treec09d8fb50b8f02de16f048bb51ba6bf2d3fc511c /content/browser/renderer_host/render_widget_host_view_gtk.cc
parent67c125db892ec5222d74012da3c6d353cdf24671 (diff)
downloadchromium_src-57e02bedcb1a410fef4b67bf67ebd710de65b205.zip
chromium_src-57e02bedcb1a410fef4b67bf67ebd710de65b205.tar.gz
chromium_src-57e02bedcb1a410fef4b67bf67ebd710de65b205.tar.bz2
Linux implementation of mouse lock in render widget host view.
Also, fix to render view to disable mouse capture when mouse lock is engaged. BUG=41781 TEST=Manual test in ppapi/examples/mouse_lock. Review URL: http://codereview.chromium.org/8163007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104932 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host/render_widget_host_view_gtk.cc')
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.cc177
1 files changed, 170 insertions, 7 deletions
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc
index 368eaa4..05a44a2c 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -33,6 +33,7 @@
#include "content/browser/renderer_host/render_widget_host.h"
#include "content/common/content_switches.h"
#include "content/common/native_web_keyboard_event.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/x11/WebScreenInfoFactory.h"
@@ -94,6 +95,12 @@ GdkCursor* GetMozSpinningCursor() {
return moz_spinning_cursor;
}
+bool MovedToCenter(const WebKit::WebMouseEvent& mouse_event,
+ const gfx::Point& center) {
+ return mouse_event.globalX == center.x() &&
+ mouse_event.globalY == center.y();
+}
+
} // namespace
using WebKit::WebInputEventFactory;
@@ -115,6 +122,7 @@ class RenderWidgetHostViewGtkWidget {
gtk_widget_set_size_request(widget, 0, 0);
gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
+ GDK_STRUCTURE_MASK |
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
@@ -127,6 +135,10 @@ class RenderWidgetHostViewGtkWidget {
g_signal_connect(widget, "expose-event",
G_CALLBACK(OnExposeEvent), host_view);
+ g_signal_connect(widget, "realize",
+ G_CALLBACK(OnRealize), host_view);
+ g_signal_connect(widget, "configure-event",
+ G_CALLBACK(OnConfigureEvent), host_view);
g_signal_connect(widget, "key-press-event",
G_CALLBACK(OnKeyPressReleaseEvent), host_view);
g_signal_connect(widget, "key-release-event",
@@ -170,9 +182,32 @@ class RenderWidgetHostViewGtkWidget {
return FALSE;
}
+ static gboolean OnRealize(GtkWidget* widget,
+ RenderWidgetHostViewGtk* host_view) {
+ // Use GtkSignalRegistrar to register events on a widget we don't
+ // control the lifetime of, auto disconnecting at our end of our life.
+ host_view->signals_.Connect(gtk_widget_get_toplevel(widget),
+ "configure-event",
+ G_CALLBACK(OnConfigureEvent), host_view);
+ return FALSE;
+ }
+
+ static gboolean OnConfigureEvent(GtkWidget* widget,
+ GdkEventConfigure* event,
+ RenderWidgetHostViewGtk* host_view) {
+ host_view->widget_center_valid_ = false;
+ host_view->mouse_has_been_warped_to_new_center_ = false;
+ return FALSE;
+ }
+
static gboolean OnKeyPressReleaseEvent(GtkWidget* widget,
GdkEventKey* event,
RenderWidgetHostViewGtk* host_view) {
+ // ESC exits mouse lock.
+ if (host_view->mouse_locked_ && event->keyval == GDK_Escape) {
+ host_view->UnlockMouse();
+ return TRUE;
+ }
// Force popups or fullscreen windows to close on Escape so they won't keep
// the keyboard grabbed or be stuck onscreen if the renderer is hanging.
bool should_close_on_escape =
@@ -351,8 +386,31 @@ class RenderWidgetHostViewGtkWidget {
}
host_view->ModifyEventForEdgeDragging(widget, event);
- host_view->GetRenderWidgetHost()->ForwardMouseEvent(
- WebInputEventFactory::mouseEvent(event));
+
+ WebKit::WebMouseEvent mouse_event =
+ WebInputEventFactory::mouseEvent(event);
+
+ if (host_view->mouse_locked_) {
+ gfx::Point center = host_view->GetWidgetCenter();
+
+ bool moved_to_center = MovedToCenter(mouse_event, center);
+ if (moved_to_center)
+ host_view->mouse_has_been_warped_to_new_center_ = true;
+
+ host_view->ModifyEventMovementAndCoords(&mouse_event);
+
+ if (!moved_to_center &&
+ (mouse_event.movementX || mouse_event.movementY)) {
+ GdkDisplay* display = gtk_widget_get_display(widget);
+ GdkScreen* screen = gtk_widget_get_screen(widget);
+ gdk_display_warp_pointer(display, screen, center.x(), center.y());
+ if (host_view->mouse_has_been_warped_to_new_center_)
+ host_view->GetRenderWidgetHost()->ForwardMouseEvent(mouse_event);
+ }
+ } else { // Mouse is not locked.
+ host_view->ModifyEventMovementAndCoords(&mouse_event);
+ host_view->GetRenderWidgetHost()->ForwardMouseEvent(mouse_event);
+ }
return FALSE;
}
@@ -372,8 +430,15 @@ class RenderWidgetHostViewGtkWidget {
// additionally send this crossing event with the state indicating the
// button is down, it causes problems with drag and drop in WebKit.)
if (!(event->state & any_button_mask)) {
- host_view->GetRenderWidgetHost()->ForwardMouseEvent(
- WebInputEventFactory::mouseEvent(event));
+ WebKit::WebMouseEvent mouse_event =
+ WebInputEventFactory::mouseEvent(event);
+ host_view->ModifyEventMovementAndCoords(&mouse_event);
+ // When crossing out and back into a render view the movement values
+ // must represent the instantaneous movement of the mouse, not the jump
+ // from the exit to re-entry point.
+ mouse_event.movementX = 0;
+ mouse_event.movementY = 0;
+ host_view->GetRenderWidgetHost()->ForwardMouseEvent(mouse_event);
}
return FALSE;
@@ -516,6 +581,7 @@ RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
}
RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() {
+ UnlockMouse();
set_last_mouse_down(NULL);
view_.Destroy();
}
@@ -1178,12 +1244,63 @@ gfx::PluginWindowHandle RenderWidgetHostViewGtk::GetCompositingSurface() {
}
bool RenderWidgetHostViewGtk::LockMouse() {
- NOTIMPLEMENTED();
- return false;
+ if (mouse_locked_)
+ return true;
+
+ mouse_locked_ = true;
+
+ // Release any current grab.
+ GtkWidget* current_grab_window = gtk_grab_get_current();
+ if (current_grab_window) {
+ gtk_grab_remove(current_grab_window);
+ LOG(WARNING) << "Locking Mouse with gdk_pointer_grab, "
+ << "but had to steal grab from another window";
+ }
+
+ GtkWidget* widget = view_.get();
+ GdkWindow* window = gtk_widget_get_window(widget);
+ GdkCursor* cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+
+ GdkGrabStatus grab_status =
+ gdk_pointer_grab(window,
+ FALSE, // owner_events
+ static_cast<GdkEventMask>(
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK),
+ window, // confine_to
+ cursor,
+ GDK_CURRENT_TIME);
+
+ if (grab_status != GDK_GRAB_SUCCESS) {
+ LOG(WARNING) << "Failed to grab pointer for LockMouse. "
+ << "gdk_pointer_grab returned: " << grab_status;
+ mouse_locked_ = false;
+ return false;
+ }
+
+ // Clear the tooltip window.
+ SetTooltipText(string16());
+
+ return true;
}
void RenderWidgetHostViewGtk::UnlockMouse() {
- NOTIMPLEMENTED();
+ if (!mouse_locked_)
+ return;
+
+ mouse_locked_ = false;
+
+ GtkWidget* widget = view_.get();
+ GdkDisplay* display = gtk_widget_get_display(widget);
+ GdkScreen* screen = gtk_widget_get_screen(widget);
+ gdk_display_pointer_ungrab(display, GDK_CURRENT_TIME);
+ gdk_display_warp_pointer(display, screen,
+ unlocked_global_mouse_position_.x(),
+ unlocked_global_mouse_position_.y());
+
+ if (host_)
+ host_->LostMouseLock();
}
void RenderWidgetHostViewGtk::ForwardKeyboardEvent(
@@ -1234,6 +1351,52 @@ void RenderWidgetHostViewGtk::set_last_mouse_down(GdkEventButton* event) {
last_mouse_down_ = temp;
}
+gfx::Point RenderWidgetHostViewGtk::GetWidgetCenter() {
+ if (widget_center_valid_)
+ return widget_center_;
+
+ GdkWindow* window = gtk_widget_get_window(view_.get());
+ gint window_x = 0;
+ gint window_y = 0;
+ gdk_window_get_origin(window, &window_x, &window_y);
+ gint window_w = 0;
+ gint window_h = 0;
+ gdk_drawable_get_size(window, &window_w, &window_h);
+
+ widget_center_.SetPoint(window_x + window_w / 2,
+ window_y + window_h / 2);
+ widget_center_valid_ = true;
+ return widget_center_;
+}
+
+void RenderWidgetHostViewGtk::ModifyEventMovementAndCoords(
+ WebKit::WebMouseEvent* event) {
+ // Movement is computed by taking the difference of the new cursor position
+ // and the previous. Under mouse lock the cursor will be warped back to the
+ // center so that we are not limited by clipping boundaries.
+ // We do not measure movement as the delta from cursor to center because
+ // we may receive more mouse movement events before our warp has taken
+ // effect.
+ event->movementX = event->globalX - global_mouse_position_.x();
+ event->movementY = event->globalY - global_mouse_position_.y();
+
+ global_mouse_position_.SetPoint(event->globalX, event->globalY);
+
+ // Under mouse lock, coordinates of mouse are locked to what they were when
+ // mouse lock was entered.
+ if (mouse_locked_) {
+ event->x = unlocked_mouse_position_.x();
+ event->y = unlocked_mouse_position_.y();
+ event->windowX = unlocked_mouse_position_.x();
+ event->windowY = unlocked_mouse_position_.y();
+ event->globalX = unlocked_global_mouse_position_.x();
+ event->globalY = unlocked_global_mouse_position_.y();
+ } else {
+ unlocked_mouse_position_.SetPoint(event->windowX, event->windowY);
+ unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY);
+ }
+}
+
// static
void RenderWidgetHostView::GetDefaultScreenInfo(
WebKit::WebScreenInfo* results) {