summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-26 23:39:44 +0000
committertc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-26 23:39:44 +0000
commit00987d375a99d62590ccd160bda19cd8ff892e8b (patch)
treed87ba35af20d6130da784185f4c0d40c77cc6fd7
parent9ba258bc5d7da5194a8b0ecfb66c22e52fd75bf9 (diff)
downloadchromium_src-00987d375a99d62590ccd160bda19cd8ff892e8b.zip
chromium_src-00987d375a99d62590ccd160bda19cd8ff892e8b.tar.gz
chromium_src-00987d375a99d62590ccd160bda19cd8ff892e8b.tar.bz2
Fix a bug where if user has focus follows mouse, moving out of
the chrome window closes content popups. We need to grab all X mouse events using gdk_pointer_grab. This prevents other windows from getting focus. We no longer need the focus-out-event signal handler because we'll get the mouse down outside the browser window, forward it to the renderer, and it will tell us to close. I verified manually that killing the renderer while the popup is showing results in gdk_display_pointer_ungrab getting called. If the renderer hangs, the user just needs to click outside the popup. Review URL: http://codereview.chromium.org/112052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16946 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc37
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h7
2 files changed, 29 insertions, 15 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index b3324bf..9d8f2c1 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -129,9 +129,19 @@ class RenderWidgetHostViewGtkWidget {
int x = 0;
int y = 0;
gtk_widget_get_pointer(widget, &x, &y);
+ // If the mouse release happens outside our popup, force the popup to
+ // close. We do this so a hung renderer doesn't prevent us from
+ // releasing the x pointer grab.
+ bool click_in_popup = x >= 0 && y >= 0 && x < widget->allocation.width &&
+ y < widget->allocation.height;
+ if (!host_view->is_popup_first_mouse_release_ && !click_in_popup) {
+ host_view->host_->Shutdown();
+ return FALSE;
+ }
event->x = x;
event->y = y;
}
+ host_view->is_popup_first_mouse_release_ = false;
host_view->GetRenderWidgetHost()->ForwardMouseEvent(
WebInputEventFactory::mouseEvent(event));
@@ -170,12 +180,6 @@ class RenderWidgetHostViewGtkWidget {
DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget);
};
-static gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus,
- RenderWidgetHost* host) {
- host->Shutdown();
- return FALSE;
-}
-
// static
RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
RenderWidgetHost* widget) {
@@ -186,10 +190,10 @@ RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
: host_(widget_host),
parent_host_view_(NULL),
parent_(NULL),
- popup_signal_id_(0),
about_to_validate_and_paint_(false),
is_loading_(false),
- is_hidden_(false) {
+ is_hidden_(false),
+ is_popup_first_mouse_release_(true) {
host_->set_view(this);
}
@@ -216,9 +220,17 @@ void RenderWidgetHostViewGtk::InitAsPopup(
// Grab all input for the app. If a click lands outside the bounds of the
// popup, WebKit will notice and destroy us.
gtk_grab_add(view_.get());
- // We also destroy ourselves if our parent loses focus.
- popup_signal_id_ = g_signal_connect(parent_, "focus-out-event",
- G_CALLBACK(OnPopupParentFocusOut), host_);
+ // Now grab all of X's input.
+ gdk_pointer_grab(
+ parent_->window,
+ TRUE, // Only events outside of the window are reported with respect
+ // to |parent_->window|.
+ static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK),
+ NULL,
+ NULL,
+ GDK_CURRENT_TIME);
+
// Our parent widget actually keeps GTK focus within its window, but we have
// to make the webkit selection box disappear to maintain appearances.
parent_host_view->Blur();
@@ -362,7 +374,8 @@ void RenderWidgetHostViewGtk::Destroy() {
// parent and destroy the popup window.
if (parent_) {
if (activatable()) {
- g_signal_handler_disconnect(parent_, popup_signal_id_);
+ GdkDisplay *display = gtk_widget_get_display(parent_);
+ gdk_display_pointer_ungrab(display, GDK_CURRENT_TIME);
parent_host_view_->Focus();
}
gtk_widget_destroy(gtk_widget_get_parent(view_.get()));
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
index dba9ce1..90c5281 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -88,9 +88,6 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// The native view of our parent, equivalent to
// parent_host_view_->GetPluginNativeView().
GtkWidget* parent_;
- // We connect to the parent's focus out event. When we are destroyed, we need
- // to remove this handler, so we must keep track of its id.
- gulong popup_signal_id_;
// This is true when we are currently painting and thus should handle extra
// paint requests by expanding the invalid rect rather than actually
// painting.
@@ -106,6 +103,10 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// Whether or not this widget is hidden.
bool is_hidden_;
+
+ // We ignore the first mouse release on popups. This allows the popup to
+ // stay open.
+ bool is_popup_first_mouse_release_;
};
#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_