Commit 41e91f09 authored by Olesia Marukhno's avatar Olesia Marukhno Committed by Commit Bot

Fix bubbles not being closed after processing accelerators on Linux

Bug: 1098660

Change-Id: I3036489ce3b939d9668c6fa374c465caf8f98a2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2292290
Commit-Queue: Olesia Marukhno <olesiamarukhno@google.com>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790808}
parent afa61849
...@@ -611,7 +611,10 @@ void FocusManager::OnViewIsDeleting(View* view) { ...@@ -611,7 +611,10 @@ void FocusManager::OnViewIsDeleting(View* view) {
bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget( bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget(
const ui::Accelerator& accelerator) { const ui::Accelerator& accelerator) {
Widget* anchor_widget = GetBubbleAnchorWidget(); views::BubbleDialogDelegate* widget_delegate =
widget_->widget_delegate()->AsBubbleDialogDelegate();
Widget* anchor_widget =
widget_delegate ? widget_delegate->anchor_widget() : nullptr;
if (!anchor_widget) if (!anchor_widget)
return false; return false;
...@@ -619,15 +622,32 @@ bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget( ...@@ -619,15 +622,32 @@ bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget(
if (!focus_manager->IsAcceleratorRegistered(accelerator)) if (!focus_manager->IsAcceleratorRegistered(accelerator))
return false; return false;
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Processing an accelerator can delete things. Because we
// need these objects afterwards on Linux, save widget_ as weak pointer and
// save the close_on_deactivate property value of widget_delegate in a
// variable.
base::WeakPtr<Widget> widget_weak_ptr = widget_->GetWeakPtr();
const bool close_widget_on_deactivate =
widget_delegate->close_on_deactivate();
#endif
// The parent view must be focused for it to process events. // The parent view must be focused for it to process events.
focus_manager->SetFocusedView(anchor_widget->GetRootView()); focus_manager->SetFocusedView(anchor_widget->GetRootView());
return focus_manager->ProcessAccelerator(accelerator); const bool accelerator_processed =
} focus_manager->ProcessAccelerator(accelerator);
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Need to manually close the bubble widget on Linux. On Linux when the
// bubble is shown, the main widget remains active. Because of that when
// focus is set to the main widget to process accelerator, the main widget
// isn't activated and the bubble widget isn't deactivated and closed.
if (accelerator_processed && close_widget_on_deactivate) {
widget_weak_ptr->CloseWithReason(views::Widget::ClosedReason::kLostFocus);
}
#endif
Widget* FocusManager::GetBubbleAnchorWidget() { return accelerator_processed;
BubbleDialogDelegate* widget_delegate =
widget_->widget_delegate()->AsBubbleDialogDelegate();
return widget_delegate ? widget_delegate->anchor_widget() : nullptr;
} }
} // namespace views } // namespace views
...@@ -336,9 +336,6 @@ class VIEWS_EXPORT FocusManager : public ViewObserver { ...@@ -336,9 +336,6 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
bool RedirectAcceleratorToBubbleAnchorWidget( bool RedirectAcceleratorToBubbleAnchorWidget(
const ui::Accelerator& accelerator); const ui::Accelerator& accelerator);
// Returns bubble's anchor widget.
Widget* GetBubbleAnchorWidget();
// Whether arrow key traversal is enabled globally. // Whether arrow key traversal is enabled globally.
static bool arrow_key_traversal_enabled_; static bool arrow_key_traversal_enabled_;
......
...@@ -1244,9 +1244,8 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest { ...@@ -1244,9 +1244,8 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest {
GetWidget()->GetRootView()->AddChildView(std::make_unique<View>()); GetWidget()->GetRootView()->AddChildView(std::make_unique<View>());
anchor->SetFocusBehavior(View::FocusBehavior::ALWAYS); anchor->SetFocusBehavior(View::FocusBehavior::ALWAYS);
BubbleDialogDelegateView* bubble_delegate = bubble_ = TestBubbleDialogDelegateView::CreateAndShowBubble(anchor);
TestBubbleDialogDelegateView::CreateAndShowBubble(anchor); Widget* bubble_widget = bubble_->GetWidget();
Widget* bubble_widget = bubble_delegate->GetWidget();
parent_focus_manager_ = anchor->GetFocusManager(); parent_focus_manager_ = anchor->GetFocusManager();
bubble_focus_manager_ = bubble_widget->GetFocusManager(); bubble_focus_manager_ = bubble_widget->GetFocusManager();
...@@ -1258,8 +1257,10 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest { ...@@ -1258,8 +1257,10 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest {
} }
protected: protected:
FocusManager* parent_focus_manager_; FocusManager* parent_focus_manager_ = nullptr;
FocusManager* bubble_focus_manager_; FocusManager* bubble_focus_manager_ = nullptr;
BubbleDialogDelegateView* bubble_ = nullptr;
}; };
// Test that when an accelerator is sent to a bubble that isn't registered, // Test that when an accelerator is sent to a bubble that isn't registered,
...@@ -1267,6 +1268,7 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest { ...@@ -1267,6 +1268,7 @@ class RedirectToParentFocusManagerTest : public FocusManagerTest {
TEST_F(RedirectToParentFocusManagerTest, ParentHandlesAcceleratorFromBubble) { TEST_F(RedirectToParentFocusManagerTest, ParentHandlesAcceleratorFromBubble) {
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
ui::TestAcceleratorTarget parent_return_target(true); ui::TestAcceleratorTarget parent_return_target(true);
Widget* bubble_widget = bubble_->GetWidget();
EXPECT_EQ(0, parent_return_target.accelerator_count()); EXPECT_EQ(0, parent_return_target.accelerator_count());
parent_focus_manager_->RegisterAccelerator( parent_focus_manager_->RegisterAccelerator(
...@@ -1275,9 +1277,23 @@ TEST_F(RedirectToParentFocusManagerTest, ParentHandlesAcceleratorFromBubble) { ...@@ -1275,9 +1277,23 @@ TEST_F(RedirectToParentFocusManagerTest, ParentHandlesAcceleratorFromBubble) {
EXPECT_TRUE( EXPECT_TRUE(
!bubble_focus_manager_->IsAcceleratorRegistered(return_accelerator)); !bubble_focus_manager_->IsAcceleratorRegistered(return_accelerator));
// Accelerator was proccesed by the parent.
// The bubble should be closed after parent processed accelerator only if
// close_on_deactivate is true.
bubble_->set_close_on_deactivate(false);
// Accelerator was processed by the parent.
EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator)); EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
EXPECT_EQ(parent_return_target.accelerator_count(), 1); EXPECT_EQ(parent_return_target.accelerator_count(), 1);
EXPECT_FALSE(bubble_widget->IsClosed());
// Reset focus to the bubble widget. Focus was set to the the main widget
// to process accelerator.
bubble_focus_manager_->SetFocusedView(bubble_widget->GetRootView());
bubble_->set_close_on_deactivate(true);
EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
EXPECT_EQ(parent_return_target.accelerator_count(), 2);
EXPECT_TRUE(bubble_widget->IsClosed());
} }
// Test that when an accelerator is sent to a bubble that is registered on both // Test that when an accelerator is sent to a bubble that is registered on both
...@@ -1286,6 +1302,7 @@ TEST_F(RedirectToParentFocusManagerTest, BubbleHandlesRegisteredAccelerators) { ...@@ -1286,6 +1302,7 @@ TEST_F(RedirectToParentFocusManagerTest, BubbleHandlesRegisteredAccelerators) {
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
ui::TestAcceleratorTarget parent_return_target(true); ui::TestAcceleratorTarget parent_return_target(true);
ui::TestAcceleratorTarget bubble_return_target(true); ui::TestAcceleratorTarget bubble_return_target(true);
Widget* bubble_widget = bubble_->GetWidget();
EXPECT_EQ(0, bubble_return_target.accelerator_count()); EXPECT_EQ(0, bubble_return_target.accelerator_count());
EXPECT_EQ(0, parent_return_target.accelerator_count()); EXPECT_EQ(0, parent_return_target.accelerator_count());
...@@ -1297,10 +1314,32 @@ TEST_F(RedirectToParentFocusManagerTest, BubbleHandlesRegisteredAccelerators) { ...@@ -1297,10 +1314,32 @@ TEST_F(RedirectToParentFocusManagerTest, BubbleHandlesRegisteredAccelerators) {
return_accelerator, ui::AcceleratorManager::kNormalPriority, return_accelerator, ui::AcceleratorManager::kNormalPriority,
&parent_return_target); &parent_return_target);
// Accelerator was proccesed by the bubble and not by the parent. // The bubble shouldn't be closed after it processed accelerator without
// passing it to the parent.
bubble_->set_close_on_deactivate(true);
// Accelerator was processed by the bubble and not by the parent.
EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator)); EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
EXPECT_EQ(1, bubble_return_target.accelerator_count()); EXPECT_EQ(1, bubble_return_target.accelerator_count());
EXPECT_EQ(0, parent_return_target.accelerator_count()); EXPECT_EQ(0, parent_return_target.accelerator_count());
EXPECT_FALSE(bubble_widget->IsClosed());
}
// Test that when an accelerator is sent to a bubble that isn't registered
// for either the bubble or the bubble's parent, the bubble isn't closed.
TEST_F(RedirectToParentFocusManagerTest, NotProcessedAccelerator) {
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
Widget* bubble_widget = bubble_->GetWidget();
EXPECT_TRUE(
!bubble_focus_manager_->IsAcceleratorRegistered(return_accelerator));
EXPECT_TRUE(
!parent_focus_manager_->IsAcceleratorRegistered(return_accelerator));
// The bubble shouldn't be closed if the accelerator was passed to the parent
// but the parent didn't process it.
bubble_->set_close_on_deactivate(true);
EXPECT_FALSE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
EXPECT_FALSE(bubble_widget->IsClosed());
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment