diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-26 23:39:44 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-26 23:39:44 +0000 |
commit | 00987d375a99d62590ccd160bda19cd8ff892e8b (patch) | |
tree | d87ba35af20d6130da784185f4c0d40c77cc6fd7 | |
parent | 9ba258bc5d7da5194a8b0ecfb66c22e52fd75bf9 (diff) | |
download | chromium_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.cc | 37 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_gtk.h | 7 |
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_ |