summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-13 03:47:37 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-13 03:47:37 +0000
commit9d56dd31573039d45135ec516260bcc070cc284f (patch)
treef1df57876f1d1fc9998dda7d35adc98764a34b94 /views
parente49002ab6fab8693dda975ee8bd0ffaae8bbc5cb (diff)
downloadchromium_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.cc50
-rw-r--r--views/controls/menu/menu_host.h19
-rw-r--r--views/controls/menu/menu_host_gtk.cc144
-rw-r--r--views/controls/menu/menu_host_gtk.h47
-rw-r--r--views/controls/menu/menu_host_views.cc33
-rw-r--r--views/controls/menu/menu_host_views.h40
-rw-r--r--views/controls/menu/menu_host_win.cc61
-rw-r--r--views/controls/menu/menu_host_win.h40
-rw-r--r--views/views.gyp6
-rw-r--r--views/widget/native_widget_gtk.cc80
-rw-r--r--views/widget/native_widget_gtk.h9
-rw-r--r--views/widget/native_widget_private.h9
-rw-r--r--views/widget/native_widget_views.cc19
-rw-r--r--views/widget/native_widget_views.h3
-rw-r--r--views/widget/native_widget_win.cc14
-rw-r--r--views/widget/native_widget_win.h3
-rw-r--r--views/widget/root_view.cc38
-rw-r--r--views/widget/root_view.h8
-rw-r--r--views/widget/widget.cc4
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();