diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-13 03:47:37 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-13 03:47:37 +0000 |
commit | 9d56dd31573039d45135ec516260bcc070cc284f (patch) | |
tree | f1df57876f1d1fc9998dda7d35adc98764a34b94 /views | |
parent | e49002ab6fab8693dda975ee8bd0ffaae8bbc5cb (diff) | |
download | chromium_src-9d56dd31573039d45135ec516260bcc070cc284f.zip chromium_src-9d56dd31573039d45135ec516260bcc070cc284f.tar.gz chromium_src-9d56dd31573039d45135ec516260bcc070cc284f.tar.bz2 |
Attempt 2 at:
Gets mouse capture to work for menus with pure views. As part of this
I moved what was in menu_host_gtk into native_widget_gtk. Gtk supports
two grab types, both mouse and key. We only want key grab when showing
menus.
BUG=none
TEST=none
TBR=ben@chromium.org
Review URL: http://codereview.chromium.org/7354006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92311 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/menu/menu_host.cc | 50 | ||||
-rw-r--r-- | views/controls/menu/menu_host.h | 19 | ||||
-rw-r--r-- | views/controls/menu/menu_host_gtk.cc | 144 | ||||
-rw-r--r-- | views/controls/menu/menu_host_gtk.h | 47 | ||||
-rw-r--r-- | views/controls/menu/menu_host_views.cc | 33 | ||||
-rw-r--r-- | views/controls/menu/menu_host_views.h | 40 | ||||
-rw-r--r-- | views/controls/menu/menu_host_win.cc | 61 | ||||
-rw-r--r-- | views/controls/menu/menu_host_win.h | 40 | ||||
-rw-r--r-- | views/views.gyp | 6 | ||||
-rw-r--r-- | views/widget/native_widget_gtk.cc | 80 | ||||
-rw-r--r-- | views/widget/native_widget_gtk.h | 9 | ||||
-rw-r--r-- | views/widget/native_widget_private.h | 9 | ||||
-rw-r--r-- | views/widget/native_widget_views.cc | 19 | ||||
-rw-r--r-- | views/widget/native_widget_views.h | 3 | ||||
-rw-r--r-- | views/widget/native_widget_win.cc | 14 | ||||
-rw-r--r-- | views/widget/native_widget_win.h | 3 | ||||
-rw-r--r-- | views/widget/root_view.cc | 38 | ||||
-rw-r--r-- | views/widget/root_view.h | 8 | ||||
-rw-r--r-- | views/widget/widget.cc | 4 |
19 files changed, 215 insertions, 412 deletions
diff --git a/views/controls/menu/menu_host.cc b/views/controls/menu/menu_host.cc index 57f7707..b767feb 100644 --- a/views/controls/menu/menu_host.cc +++ b/views/controls/menu/menu_host.cc @@ -18,10 +18,9 @@ namespace views { // MenuHost, public: MenuHost::MenuHost(SubmenuView* submenu) - : ALLOW_THIS_IN_INITIALIZER_LIST(native_menu_host_( - NativeMenuHost::CreateNativeMenuHost(this))), - submenu_(submenu), - destroying_(false) { + : submenu_(submenu), + destroying_(false), + showing_(false) { } MenuHost::~MenuHost() { @@ -39,7 +38,6 @@ void MenuHost::InitMenuHost(gfx::NativeWindow parent, params.parent = GTK_WIDGET(parent); #endif params.bounds = bounds; - params.native_widget = native_menu_host_->AsNativeWidget(); Init(params); SetContentsView(contents_view); ShowMenuHost(do_capture); @@ -50,9 +48,18 @@ bool MenuHost::IsMenuHostVisible() { } void MenuHost::ShowMenuHost(bool do_capture) { + // Doing a capture may make us get capture lost. Ignore it while we're in the + // process of showing. + showing_ = true; Show(); - if (do_capture) - native_menu_host_->StartCapturing(); + if (do_capture) { + native_widget_private()->SetMouseCapture(); + // We do this to effectively disable window manager keyboard accelerators + // for chromeos. Such accelerators could cause cause another window to + // become active and confuse things. + native_widget_private()->SetKeyboardCapture(); + } + showing_ = false; } void MenuHost::HideMenuHost() { @@ -74,6 +81,8 @@ void MenuHost::SetMenuHostBounds(const gfx::Rect& bounds) { void MenuHost::ReleaseMenuHostCapture() { if (native_widget_private()->HasMouseCapture()) native_widget_private()->ReleaseMouseCapture(); + if (native_widget_private()->HasKeyboardCapture()) + native_widget_private()->ReleaseKeyboardCapture(); } //////////////////////////////////////////////////////////////////////////////// @@ -87,29 +96,24 @@ bool MenuHost::ShouldReleaseCaptureOnMouseReleased() const { return false; } -//////////////////////////////////////////////////////////////////////////////// -// MenuHost, internal::NativeMenuHostDelegate implementation: - -void MenuHost::OnNativeMenuHostDestroy() { - if (!destroying_) { - // We weren't explicitly told to destroy ourselves, which means the menu was - // deleted out from under us (the window we're parented to was closed). Tell - // the SubmenuView to drop references to us. - submenu_->MenuHostDestroyed(); - } -} - -void MenuHost::OnNativeMenuHostCancelCapture() { - if (destroying_) +void MenuHost::OnMouseCaptureLost() { + if (destroying_ || showing_) return; MenuController* menu_controller = submenu_->GetMenuItem()->GetMenuController(); if (menu_controller && !menu_controller->drag_in_progress()) menu_controller->CancelAll(); + Widget::OnMouseCaptureLost(); } -internal::NativeWidgetDelegate* MenuHost::AsNativeWidgetDelegate() { - return this; +void MenuHost::OnNativeWidgetDestroyed() { + if (!destroying_) { + // We weren't explicitly told to destroy ourselves, which means the menu was + // deleted out from under us (the window we're parented to was closed). Tell + // the SubmenuView to drop references to us. + submenu_->MenuHostDestroyed(); + } + Widget::OnNativeWidgetDestroyed(); } } // namespace views diff --git a/views/controls/menu/menu_host.h b/views/controls/menu/menu_host.h index a33f445..0b5417b 100644 --- a/views/controls/menu/menu_host.h +++ b/views/controls/menu/menu_host.h @@ -20,17 +20,14 @@ class SubmenuView; class View; class Widget; -// SubmenuView uses a MenuHost to house the SubmenuView. MenuHost typically -// extends the native Widget type, but is defined here for clarity of what -// methods SubmenuView uses. +// SubmenuView uses a MenuHost to house the SubmenuView. // // SubmenuView owns the MenuHost. When SubmenuView is done with the MenuHost // |DestroyMenuHost| is invoked. The one exception to this is if the native // OS destroys the widget out from under us, in which case |MenuHostDestroyed| // is invoked back on the SubmenuView and the SubmenuView then drops references // to the MenuHost. -class MenuHost : public Widget, - public internal::NativeMenuHostDelegate { +class MenuHost : public Widget { public: explicit MenuHost(SubmenuView* submenu); virtual ~MenuHost(); @@ -67,13 +64,8 @@ class MenuHost : public Widget, // Overridden from Widget: virtual internal::RootView* CreateRootView() OVERRIDE; virtual bool ShouldReleaseCaptureOnMouseReleased() const OVERRIDE; - - // Overridden from NativeMenuHostDelegate: - virtual void OnNativeMenuHostDestroy() OVERRIDE; - virtual void OnNativeMenuHostCancelCapture() OVERRIDE; - virtual internal::NativeWidgetDelegate* AsNativeWidgetDelegate() OVERRIDE; - - NativeMenuHost* native_menu_host_; + virtual void OnMouseCaptureLost() OVERRIDE; + virtual void OnNativeWidgetDestroyed() OVERRIDE; // The view we contain. SubmenuView* submenu_; @@ -81,6 +73,9 @@ class MenuHost : public Widget, // If true, DestroyMenuHost has been invoked. bool destroying_; + // If true, we're attempting to Show. + bool showing_; + DISALLOW_COPY_AND_ASSIGN(MenuHost); }; diff --git a/views/controls/menu/menu_host_gtk.cc b/views/controls/menu/menu_host_gtk.cc deleted file mode 100644 index c3ff9cd..0000000 --- a/views/controls/menu/menu_host_gtk.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/controls/menu/menu_host_gtk.h" - -#include <gdk/gdk.h> - -#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) -#include <gdk/gdkx.h> -#include <X11/extensions/XInput2.h> -#endif - -#include "views/controls/menu/menu_host_views.h" -#include "views/controls/menu/native_menu_host_delegate.h" -#include "views/views_delegate.h" - -#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) -#include "views/touchui/touch_factory.h" -#endif - -namespace views { - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostGtk, public: - -MenuHostGtk::MenuHostGtk(internal::NativeMenuHostDelegate* delegate) - : NativeWidgetGtk(delegate->AsNativeWidgetDelegate()), - did_input_grab_(false), - delegate_(delegate) { -} - -MenuHostGtk::~MenuHostGtk() { -} - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostGtk, NativeMenuHost implementation: - -void MenuHostGtk::StartCapturing() { - DCHECK(!did_input_grab_); - - // Release the current grab. - GtkWidget* current_grab_window = gtk_grab_get_current(); - if (current_grab_window) - gtk_grab_remove(current_grab_window); - - // Make sure all app mouse/keyboard events are targeted at us only. - SetMouseCapture(); - - // And do a grab. NOTE: we do this to ensure we get mouse/keyboard - // events from other apps, a grab done with gtk_grab_add doesn't get - // events from other apps. - GdkGrabStatus pointer_grab_status = - gdk_pointer_grab(window_contents()->window, FALSE, - static_cast<GdkEventMask>( - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK), - NULL, NULL, GDK_CURRENT_TIME); - GdkGrabStatus keyboard_grab_status = - gdk_keyboard_grab(window_contents()->window, FALSE, - GDK_CURRENT_TIME); - - did_input_grab_ = pointer_grab_status == GDK_GRAB_SUCCESS && - keyboard_grab_status == GDK_GRAB_SUCCESS; - - DCHECK_EQ(GDK_GRAB_SUCCESS, pointer_grab_status); - DCHECK_EQ(GDK_GRAB_SUCCESS, keyboard_grab_status); - -#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) - ::Window window = GDK_WINDOW_XID(window_contents()->window); - Display* display = GDK_WINDOW_XDISPLAY(window_contents()->window); - bool xi2grab = TouchFactory::GetInstance()->GrabTouchDevices(display, window); - did_input_grab_ = did_input_grab_ && xi2grab; -#endif - - DCHECK(did_input_grab_); - // need keyboard grab. -} - -NativeWidget* MenuHostGtk::AsNativeWidget() { - return this; -} - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostGtk, NativeWidgetGtk overrides: - -void MenuHostGtk::InitNativeWidget(const Widget::InitParams& params) { - NativeWidgetGtk::InitNativeWidget(params); - // Make sure we get destroyed when the parent is destroyed. - gtk_window_set_destroy_with_parent(GTK_WINDOW(GetNativeView()), TRUE); - gtk_window_set_type_hint(GTK_WINDOW(GetNativeView()), - GDK_WINDOW_TYPE_HINT_MENU); -} - -void MenuHostGtk::ReleaseMouseCapture() { - NativeWidgetGtk::ReleaseMouseCapture(); - if (did_input_grab_) { - did_input_grab_ = false; - gdk_pointer_ungrab(GDK_CURRENT_TIME); - gdk_keyboard_ungrab(GDK_CURRENT_TIME); -#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) - TouchFactory::GetInstance()->UngrabTouchDevices( - GDK_WINDOW_XDISPLAY(window_contents()->window)); -#endif - } -} - -void MenuHostGtk::OnDestroy(GtkWidget* object) { - delegate_->OnNativeMenuHostDestroy(); - NativeWidgetGtk::OnDestroy(object); -} - -void MenuHostGtk::HandleXGrabBroke() { - // Grab may already be release in ReleaseGrab. - if (did_input_grab_) { - did_input_grab_ = false; - delegate_->OnNativeMenuHostCancelCapture(); - } - NativeWidgetGtk::HandleXGrabBroke(); -} - -void MenuHostGtk::HandleGtkGrabBroke() { - // Grab can be broken by drag & drop, other menu or screen locker. - if (did_input_grab_) { - ReleaseMouseCapture(); - delegate_->OnNativeMenuHostCancelCapture(); - } - NativeWidgetGtk::HandleGtkGrabBroke(); -} - -//////////////////////////////////////////////////////////////////////////////// -// NativeMenuHost, public: - -// static -NativeMenuHost* NativeMenuHost::CreateNativeMenuHost( - internal::NativeMenuHostDelegate* delegate) { - if (Widget::IsPureViews() && - ViewsDelegate::views_delegate->GetDefaultParentView()) { - return new MenuHostViews(delegate); - } - return new MenuHostGtk(delegate); -} - -} // namespace views diff --git a/views/controls/menu/menu_host_gtk.h b/views/controls/menu/menu_host_gtk.h deleted file mode 100644 index e49064e..0000000 --- a/views/controls/menu/menu_host_gtk.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#ifndef VIEWS_CONTROLS_MENU_MENU_HOST_GTK_H_ -#define VIEWS_CONTROLS_MENU_MENU_HOST_GTK_H_ -#pragma once - -#include "views/controls/menu/native_menu_host.h" -#include "views/widget/native_widget_gtk.h" - -namespace views { -namespace internal { -class NativeMenuHostDelegate; -} - -// NativeMenuHost implementation for Gtk. -class MenuHostGtk : public NativeWidgetGtk, - public NativeMenuHost { - public: - explicit MenuHostGtk(internal::NativeMenuHostDelegate* delegate); - virtual ~MenuHostGtk(); - - private: - // Overridden from NativeMenuHost: - virtual void StartCapturing() OVERRIDE; - virtual NativeWidget* AsNativeWidget() OVERRIDE; - - // Overridden from NativeWidgetGtk: - virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE; - virtual void ReleaseMouseCapture() OVERRIDE; - virtual void OnDestroy(GtkWidget* object) OVERRIDE; - virtual void HandleGtkGrabBroke() OVERRIDE; - virtual void HandleXGrabBroke() OVERRIDE; - - // Have we done input grab? - bool did_input_grab_; - - internal::NativeMenuHostDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(MenuHostGtk); -}; - -} // namespace views - -#endif // VIEWS_CONTROLS_MENU_MENU_HOST_GTK_H_ diff --git a/views/controls/menu/menu_host_views.cc b/views/controls/menu/menu_host_views.cc deleted file mode 100644 index 6896d67..0000000 --- a/views/controls/menu/menu_host_views.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/controls/menu/menu_host_views.h" - -#include "views/controls/menu/native_menu_host_delegate.h" - -namespace views { - -MenuHostViews::MenuHostViews(internal::NativeMenuHostDelegate* delegate) - : NativeWidgetViews(delegate->AsNativeWidgetDelegate()), - delegate_(delegate) { -} - -MenuHostViews::~MenuHostViews() { -} - -void MenuHostViews::StartCapturing() { - SetMouseCapture(); -} - -NativeWidget* MenuHostViews::AsNativeWidget() { - return this; -} - -void MenuHostViews::InitNativeWidget(const Widget::InitParams& params) { - NativeWidgetViews::InitNativeWidget(params); - GetView()->SetVisible(false); -} - -} // namespace views - diff --git a/views/controls/menu/menu_host_views.h b/views/controls/menu/menu_host_views.h deleted file mode 100644 index 7ab1729..0000000 --- a/views/controls/menu/menu_host_views.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef VIEWS_CONTROLS_MENU_MENU_HOST_VIEWS_H_ -#define VIEWS_CONTROLS_MENU_MENU_HOST_VIEWS_H_ -#pragma once - -#include "views/controls/menu/native_menu_host.h" -#include "views/widget/native_widget_views.h" - -namespace views { -namespace internal { -class NativeMenuHostDelegate; -} - -// MenuHost implementation for views. -class MenuHostViews : public NativeWidgetViews, - public NativeMenuHost { - public: - explicit MenuHostViews(internal::NativeMenuHostDelegate* delegate); - virtual ~MenuHostViews(); - - private: - // Overridden from NativeMenuHost: - virtual void StartCapturing() OVERRIDE; - virtual NativeWidget* AsNativeWidget() OVERRIDE; - - // Overridden from NativeWidgetViews: - virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE; - - internal::NativeMenuHostDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(MenuHostViews); -}; - -} // namespace views - -#endif // VIEWS_CONTROLS_MENU_MENU_HOST_VIEWS_H_ - diff --git a/views/controls/menu/menu_host_win.cc b/views/controls/menu/menu_host_win.cc deleted file mode 100644 index 2190b29..0000000 --- a/views/controls/menu/menu_host_win.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/controls/menu/menu_host_win.h" - -#include "views/controls/menu/menu_host_views.h" -#include "views/controls/menu/native_menu_host_delegate.h" -#include "views/views_delegate.h" - -namespace views { - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostWin, public: - -MenuHostWin::MenuHostWin(internal::NativeMenuHostDelegate* delegate) - : NativeWidgetWin(delegate->AsNativeWidgetDelegate()), - delegate_(delegate) { -} - -MenuHostWin::~MenuHostWin() { -} - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostWin, NativeMenuHost implementation: - -void MenuHostWin::StartCapturing() { - SetMouseCapture(); -} - -NativeWidget* MenuHostWin::AsNativeWidget() { - return this; -} - -//////////////////////////////////////////////////////////////////////////////// -// MenuHostWin, NativeWidgetWin overrides: - -void MenuHostWin::OnDestroy() { - delegate_->OnNativeMenuHostDestroy(); - NativeWidgetWin::OnDestroy(); -} - -void MenuHostWin::OnCancelMode() { - delegate_->OnNativeMenuHostCancelCapture(); - NativeWidgetWin::OnCancelMode(); -} - -//////////////////////////////////////////////////////////////////////////////// -// NativeMenuHost, public: - -// static -NativeMenuHost* NativeMenuHost::CreateNativeMenuHost( - internal::NativeMenuHostDelegate* delegate) { - if (Widget::IsPureViews() && - ViewsDelegate::views_delegate->GetDefaultParentView()) { - return new MenuHostViews(delegate); - } - return new MenuHostWin(delegate); -} - -} // namespace views diff --git a/views/controls/menu/menu_host_win.h b/views/controls/menu/menu_host_win.h deleted file mode 100644 index 9c9f8f8..0000000 --- a/views/controls/menu/menu_host_win.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef VIEWS_CONTROLS_MENU_MENU_HOST_WIN_H_ -#define VIEWS_CONTROLS_MENU_MENU_HOST_WIN_H_ -#pragma once - -#include "views/controls/menu/native_menu_host.h" -#include "views/widget/native_widget_win.h" - -namespace views { -namespace internal { -class NativeMenuHostDelegate; -} - -// MenuHost implementation for windows. -class MenuHostWin : public NativeWidgetWin, - public NativeMenuHost { - public: - explicit MenuHostWin(internal::NativeMenuHostDelegate* delegate); - virtual ~MenuHostWin(); - - private: - // Overridden from NativeMenuHost: - virtual void StartCapturing() OVERRIDE; - virtual NativeWidget* AsNativeWidget() OVERRIDE; - - // Overridden from NativeWidgetWin: - virtual void OnDestroy() OVERRIDE; - virtual void OnCancelMode() OVERRIDE; - - internal::NativeMenuHostDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(MenuHostWin); -}; - -} // namespace views - -#endif // VIEWS_CONTROLS_MENU_MENU_HOST_WIN_H_ diff --git a/views/views.gyp b/views/views.gyp index 1aab732..6b0ca88 100644 --- a/views/views.gyp +++ b/views/views.gyp @@ -124,14 +124,8 @@ 'controls/menu/menu_gtk.h', 'controls/menu/menu_host.cc', 'controls/menu/menu_host.h', - 'controls/menu/menu_host_gtk.cc', - 'controls/menu/menu_host_gtk.h', 'controls/menu/menu_host_root_view.cc', 'controls/menu/menu_host_root_view.h', - 'controls/menu/menu_host_views.cc', - 'controls/menu/menu_host_views.h', - 'controls/menu/menu_host_win.cc', - 'controls/menu/menu_host_win.h', 'controls/menu/menu_item_view.cc', 'controls/menu/menu_item_view.h', 'controls/menu/menu_item_view_gtk.cc', diff --git a/views/widget/native_widget_gtk.cc b/views/widget/native_widget_gtk.cc index 3e372f5..e474f71 100644 --- a/views/widget/native_widget_gtk.cc +++ b/views/widget/native_widget_gtk.cc @@ -377,7 +377,9 @@ NativeWidgetGtk::NativeWidgetGtk(internal::NativeWidgetDelegate* delegate) is_double_buffered_(false), should_handle_menu_key_release_(false), dragged_view_(NULL), - painted_(false) { + painted_(false), + has_mouse_grab_(false), + has_keyboard_grab_(false) { #if defined(TOUCH_UI) && defined(HAVE_XINPUT2) // Make sure the touch factory is initialized so that it can setup XInput2 for // the widget. @@ -679,6 +681,12 @@ void NativeWidgetGtk::InitNativeWidget(const Widget::InitParams& params) { // Make container here. CreateGtkWidget(modified_params); + if (params.type == Widget::InitParams::TYPE_MENU) { + gtk_window_set_destroy_with_parent(GTK_WINDOW(GetNativeView()), TRUE); + gtk_window_set_type_hint(GTK_WINDOW(GetNativeView()), + GDK_WINDOW_TYPE_HINT_MENU); + } + if (View::get_use_acceleration_when_possible()) { if (Widget::compositor_factory()) { compositor_ = (*Widget::compositor_factory())(); @@ -904,18 +912,72 @@ void NativeWidgetGtk::SendNativeAccessibilityEvent( void NativeWidgetGtk::SetMouseCapture() { DCHECK(!HasMouseCapture()); + + // Release the current grab. + GtkWidget* current_grab_window = gtk_grab_get_current(); + if (current_grab_window) + gtk_grab_remove(current_grab_window); + + // Make sure all app mouse/keyboard events are targeted at us only. gtk_grab_add(window_contents_); + + // And do a grab. NOTE: we do this to ensure we get mouse events from other + // apps, a grab done with gtk_grab_add doesn't get events from other apps. + GdkGrabStatus pointer_grab_status = + gdk_pointer_grab(window_contents()->window, FALSE, + static_cast<GdkEventMask>( + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK), + NULL, NULL, GDK_CURRENT_TIME); + // NOTE: technically grab may fail. We may want to try and continue on in that + // case. + DCHECK_EQ(GDK_GRAB_SUCCESS, pointer_grab_status); + has_mouse_grab_ = pointer_grab_status == GDK_GRAB_SUCCESS; + +#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) + ::Window window = GDK_WINDOW_XID(window_contents()->window); + Display* display = GDK_WINDOW_XDISPLAY(window_contents()->window); + bool xi2grab = TouchFactory::GetInstance()->GrabTouchDevices(display, window); + has_mouse_grab_ = has_mouse_grab_ && xi2grab; +#endif } void NativeWidgetGtk::ReleaseMouseCapture() { if (HasMouseCapture()) gtk_grab_remove(window_contents_); + if (has_mouse_grab_) { + has_mouse_grab_ = false; + gdk_pointer_ungrab(GDK_CURRENT_TIME); + gdk_keyboard_ungrab(GDK_CURRENT_TIME); +#if defined(HAVE_XINPUT2) && defined(TOUCH_UI) + TouchFactory::GetInstance()->UngrabTouchDevices( + GDK_WINDOW_XDISPLAY(window_contents()->window)); +#endif + } } bool NativeWidgetGtk::HasMouseCapture() const { - // TODO(beng): Should be able to use gtk_widget_has_grab() here but the - // trybots don't have Gtk 2.18. - return GTK_WIDGET_HAS_GRAB(window_contents_); + return has_mouse_grab_; +} + +void NativeWidgetGtk::SetKeyboardCapture() { + DCHECK(!has_keyboard_grab_); + + GdkGrabStatus keyboard_grab_status = + gdk_keyboard_grab(window_contents()->window, FALSE, GDK_CURRENT_TIME); + has_keyboard_grab_ = keyboard_grab_status == GDK_GRAB_SUCCESS; + DCHECK_EQ(GDK_GRAB_SUCCESS, keyboard_grab_status); +} + +void NativeWidgetGtk::ReleaseKeyboardCapture() { + if (has_keyboard_grab_) { + has_keyboard_grab_ = false; + gdk_keyboard_ungrab(GDK_CURRENT_TIME); + } +} + +bool NativeWidgetGtk::HasKeyboardCapture() { + return has_keyboard_grab_; } InputMethod* NativeWidgetGtk::GetInputMethodNative() { @@ -1706,9 +1768,19 @@ gboolean NativeWidgetGtk::OnConfigureEvent(GtkWidget* widget, } void NativeWidgetGtk::HandleXGrabBroke() { + if (has_keyboard_grab_) + has_keyboard_grab_ = false; + if (has_mouse_grab_) { + has_mouse_grab_ = false; + delegate_->OnMouseCaptureLost(); + } } void NativeWidgetGtk::HandleGtkGrabBroke() { + if (has_keyboard_grab_) + ReleaseKeyboardCapture(); + if (has_mouse_grab_) + ReleaseMouseCapture(); delegate_->OnMouseCaptureLost(); } diff --git a/views/widget/native_widget_gtk.h b/views/widget/native_widget_gtk.h index 00e0bed..425d42a 100644 --- a/views/widget/native_widget_gtk.h +++ b/views/widget/native_widget_gtk.h @@ -178,6 +178,9 @@ class NativeWidgetGtk : public internal::NativeWidgetPrivate, virtual void SetMouseCapture() OVERRIDE; virtual void ReleaseMouseCapture() OVERRIDE; virtual bool HasMouseCapture() const OVERRIDE; + virtual void SetKeyboardCapture() OVERRIDE; + virtual void ReleaseKeyboardCapture() OVERRIDE; + virtual bool HasKeyboardCapture() OVERRIDE; virtual InputMethod* GetInputMethodNative() OVERRIDE; virtual void ReplaceInputMethod(InputMethod* input_method) OVERRIDE; virtual void CenterWindow(const gfx::Size& size) OVERRIDE; @@ -451,6 +454,12 @@ class NativeWidgetGtk : public internal::NativeWidgetPrivate, // The compositor for accelerated drawing. scoped_refptr<ui::Compositor> compositor_; + // Have we done a mouse and pointer grab? + bool has_mouse_grab_; + + // Have we done a keyboard grab? + bool has_keyboard_grab_; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetGtk); }; diff --git a/views/widget/native_widget_private.h b/views/widget/native_widget_private.h index 6bba0dd..874612e 100644 --- a/views/widget/native_widget_private.h +++ b/views/widget/native_widget_private.h @@ -122,9 +122,16 @@ class NativeWidgetPrivate : public NativeWidget { virtual void SetMouseCapture() = 0; virtual void ReleaseMouseCapture() = 0; - // Returns true if this native widget is capturing all events. + // Returns true if this native widget is capturing mouse events. virtual bool HasMouseCapture() const = 0; + // Sets or release keyboard capture. + virtual void SetKeyboardCapture() = 0; + virtual void ReleaseKeyboardCapture() = 0; + + // Returns true if this native widget is capturing keyboard events. + virtual bool HasKeyboardCapture() = 0; + // Returns the InputMethod for this native widget. // Note that all widgets in a widget hierarchy share the same input method. // TODO(suzhe): rename to GetInputMethod() when NativeWidget implementation diff --git a/views/widget/native_widget_views.cc b/views/widget/native_widget_views.cc index c073b9d..2f1476d 100644 --- a/views/widget/native_widget_views.cc +++ b/views/widget/native_widget_views.cc @@ -160,17 +160,36 @@ void NativeWidgetViews::SendNativeAccessibilityEvent( } void NativeWidgetViews::SetMouseCapture() { + View* parent_root_view = GetParentNativeWidget()->GetWidget()->GetRootView(); + static_cast<internal::RootView*>(parent_root_view)->set_capture_view( + view_.get()); GetParentNativeWidget()->SetMouseCapture(); } void NativeWidgetViews::ReleaseMouseCapture() { + View* parent_root_view = GetParentNativeWidget()->GetWidget()->GetRootView(); + static_cast<internal::RootView*>(parent_root_view)->set_capture_view(NULL); GetParentNativeWidget()->ReleaseMouseCapture(); } bool NativeWidgetViews::HasMouseCapture() const { + // NOTE: we may need to tweak this to only return true if the parent native + // widget's RootView has us as the capture view. return GetParentNativeWidget()->HasMouseCapture(); } +void NativeWidgetViews::SetKeyboardCapture() { + GetParentNativeWidget()->SetKeyboardCapture(); +} + +void NativeWidgetViews::ReleaseKeyboardCapture() { + GetParentNativeWidget()->ReleaseKeyboardCapture(); +} + +bool NativeWidgetViews::HasKeyboardCapture() { + return GetParentNativeWidget()->HasKeyboardCapture(); +} + InputMethod* NativeWidgetViews::GetInputMethodNative() { return GetParentNativeWidget()->GetInputMethodNative(); } diff --git a/views/widget/native_widget_views.h b/views/widget/native_widget_views.h index 79a6205..c90f166 100644 --- a/views/widget/native_widget_views.h +++ b/views/widget/native_widget_views.h @@ -65,6 +65,9 @@ class NativeWidgetViews : public internal::NativeWidgetPrivate { virtual void SetMouseCapture() OVERRIDE; virtual void ReleaseMouseCapture() OVERRIDE; virtual bool HasMouseCapture() const OVERRIDE; + virtual void SetKeyboardCapture() OVERRIDE; + virtual void ReleaseKeyboardCapture() OVERRIDE; + virtual bool HasKeyboardCapture() OVERRIDE; virtual InputMethod* GetInputMethodNative() OVERRIDE; virtual void ReplaceInputMethod(InputMethod* input_method) OVERRIDE; virtual void CenterWindow(const gfx::Size& size) OVERRIDE; diff --git a/views/widget/native_widget_win.cc b/views/widget/native_widget_win.cc index 56d12dc..fa1b0ef 100644 --- a/views/widget/native_widget_win.cc +++ b/views/widget/native_widget_win.cc @@ -626,6 +626,19 @@ bool NativeWidgetWin::HasMouseCapture() const { return GetCapture() == hwnd(); } +void NativeWidgetWin::SetKeyboardCapture() { + // Windows doesn't really support keyboard grabs. +} + +void NativeWidgetWin::ReleaseKeyboardCapture() { + // Windows doesn't really support keyboard grabs. +} + +bool NativeWidgetWin::HasKeyboardCapture() { + // Windows doesn't really support keyboard grabs. + return false; +} + InputMethod* NativeWidgetWin::GetInputMethodNative() { return input_method_.get(); } @@ -1166,6 +1179,7 @@ LRESULT NativeWidgetWin::OnAppCommand(HWND window, } void NativeWidgetWin::OnCancelMode() { + SetMsgHandled(FALSE); } void NativeWidgetWin::OnCaptureChanged(HWND hwnd) { diff --git a/views/widget/native_widget_win.h b/views/widget/native_widget_win.h index 52dbb5c..ac7924d 100644 --- a/views/widget/native_widget_win.h +++ b/views/widget/native_widget_win.h @@ -216,6 +216,9 @@ class NativeWidgetWin : public ui::WindowImpl, virtual void SetMouseCapture() OVERRIDE; virtual void ReleaseMouseCapture() OVERRIDE; virtual bool HasMouseCapture() const OVERRIDE; + virtual void SetKeyboardCapture() OVERRIDE; + virtual void ReleaseKeyboardCapture() OVERRIDE; + virtual bool HasKeyboardCapture() OVERRIDE; virtual InputMethod* GetInputMethodNative() OVERRIDE; virtual void ReplaceInputMethod(InputMethod* input_method) OVERRIDE; virtual void CenterWindow(const gfx::Size& size) OVERRIDE; diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc index 9b1a3c3..ce35f8b 100644 --- a/views/widget/root_view.cc +++ b/views/widget/root_view.cc @@ -30,6 +30,7 @@ const char RootView::kViewClassName[] = "views/RootView"; RootView::RootView(Widget* widget) : widget_(widget), + capture_view_(NULL), mouse_pressed_handler_(NULL), mouse_move_handler_(NULL), last_click_handler_(NULL), @@ -167,6 +168,10 @@ void RootView::SchedulePaintInternal(const gfx::Rect& rect) { } bool RootView::OnMousePressed(const MouseEvent& event) { + if (capture_view_) { + MouseEvent e(event, this, capture_view_); + return capture_view_->OnMousePressed(e); + } MouseEvent e(event, this); UpdateCursor(e); @@ -242,6 +247,11 @@ bool RootView::OnMousePressed(const MouseEvent& event) { } bool RootView::OnMouseDragged(const MouseEvent& event) { + if (capture_view_) { + MouseEvent e(event, this, capture_view_); + return capture_view_->OnMouseDragged(e); + } + MouseEvent e(event, this); UpdateCursor(e); @@ -255,6 +265,12 @@ bool RootView::OnMouseDragged(const MouseEvent& event) { } void RootView::OnMouseReleased(const MouseEvent& event) { + if (capture_view_) { + MouseEvent e(event, this, capture_view_); + capture_view_->OnMouseReleased(e); + return; + } + MouseEvent e(event, this); UpdateCursor(e); @@ -270,6 +286,13 @@ void RootView::OnMouseReleased(const MouseEvent& event) { } void RootView::OnMouseCaptureLost() { + if (capture_view_) { + View* capture_view = capture_view_; + capture_view_ = NULL; + capture_view->OnMouseCaptureLost(); + return; + } + if (mouse_pressed_handler_) { // Synthesize a release event for UpdateCursor. MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_mouse_event_x_, @@ -285,6 +308,12 @@ void RootView::OnMouseCaptureLost() { } void RootView::OnMouseMoved(const MouseEvent& event) { + if (capture_view_) { + MouseEvent e(event, this, capture_view_); + capture_view_->OnMouseMoved(e); + return; + } + MouseEvent e(event, this); View* v = GetEventHandlerForPoint(e.location()); // Find the first enabled view, or the existing move handler, whichever comes @@ -312,6 +341,12 @@ void RootView::OnMouseMoved(const MouseEvent& event) { } void RootView::OnMouseExited(const MouseEvent& event) { + if (capture_view_) { + MouseEvent e(event, this, capture_view_); + capture_view_->OnMouseExited(e); + return; + } + if (mouse_move_handler_ != NULL) { mouse_move_handler_->OnMouseExited(event); mouse_move_handler_ = NULL; @@ -319,6 +354,9 @@ void RootView::OnMouseExited(const MouseEvent& event) { } bool RootView::OnMouseWheel(const MouseWheelEvent& event) { + if (capture_view_) + return capture_view_->OnMouseWheel(event); + MouseWheelEvent e(event, this); bool consumed = false; View* v = GetFocusManager()->GetFocusedView(); diff --git a/views/widget/root_view.h b/views/widget/root_view.h index b33ecf5..0ba3d51 100644 --- a/views/widget/root_view.h +++ b/views/widget/root_view.h @@ -64,6 +64,11 @@ class RootView : public View, // Input --------------------------------------------------------------------- + // If a capture view has been set all mouse events are forwarded to the + // capture view, regardless of whether the mouse is over the view. + void set_capture_view(View* v) { capture_view_ = v; } + View* capture_view() { return capture_view_; } + // Process a key event. Send the event to the focused view and up the focus // path, and finally to the default keyboard handler, until someone consumes // it. Returns whether anyone consumed the event. @@ -159,6 +164,9 @@ class RootView : public View, // Input --------------------------------------------------------------------- + // View capturing mouse input. + View* capture_view_; + // The view currently handing down - drag - up View* mouse_pressed_handler_; diff --git a/views/widget/widget.cc b/views/widget/widget.cc index a3f5c02..dcca28c 100644 --- a/views/widget/widget.cc +++ b/views/widget/widget.cc @@ -826,7 +826,9 @@ bool Widget::OnMouseEvent(const MouseEvent& event) { switch (event.type()) { case ui::ET_MOUSE_PRESSED: last_mouse_event_was_move_ = false; - if (GetRootView()->OnMousePressed(event)) { + // Make sure we're still visible before we attempt capture as the mouse + // press processing may have made the window hide (as happens with menus). + if (GetRootView()->OnMousePressed(event) && IsVisible()) { is_mouse_button_pressed_ = true; if (!native_widget_->HasMouseCapture()) native_widget_->SetMouseCapture(); |