app_list_bubble_event_filter.cc 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/app_list/app_list_bubble_event_filter.h"
  5. #include "ash/bubble/bubble_utils.h"
  6. #include "ash/shelf/hotseat_widget.h"
  7. #include "ash/shelf/shelf.h"
  8. #include "ash/shelf/shelf_widget.h"
  9. #include "ash/shell.h"
  10. #include "ash/system/status_area_widget.h"
  11. #include "base/callback.h"
  12. #include "base/check.h"
  13. #include "ui/aura/window.h"
  14. #include "ui/events/event.h"
  15. #include "ui/gfx/geometry/point.h"
  16. #include "ui/gfx/geometry/rect.h"
  17. #include "ui/views/widget/widget.h"
  18. namespace ash {
  19. AppListBubbleEventFilter::AppListBubbleEventFilter(
  20. views::Widget* widget,
  21. views::View* button,
  22. base::RepeatingCallback<void()> on_click_outside)
  23. : widget_(widget), button_(button), on_click_outside_(on_click_outside) {
  24. DCHECK(widget_);
  25. DCHECK(on_click_outside_);
  26. Shell::Get()->AddPreTargetHandler(this);
  27. }
  28. AppListBubbleEventFilter::~AppListBubbleEventFilter() {
  29. Shell::Get()->RemovePreTargetHandler(this);
  30. }
  31. void AppListBubbleEventFilter::SetButton(views::View* button) {
  32. button_ = button;
  33. }
  34. void AppListBubbleEventFilter::OnMouseEvent(ui::MouseEvent* event) {
  35. if (event->type() == ui::ET_MOUSE_PRESSED)
  36. ProcessPressedEvent(*event);
  37. }
  38. void AppListBubbleEventFilter::OnTouchEvent(ui::TouchEvent* event) {
  39. if (event->type() == ui::ET_TOUCH_PRESSED)
  40. ProcessPressedEvent(*event);
  41. }
  42. void AppListBubbleEventFilter::ProcessPressedEvent(
  43. const ui::LocatedEvent& event) {
  44. // Check the general rules for closing bubbles.
  45. if (!bubble_utils::ShouldCloseBubbleForEvent(event))
  46. return;
  47. gfx::Point event_location = event.target()
  48. ? event.target()->GetScreenLocation(event)
  49. : event.root_location();
  50. // Ignore clicks inside the widget.
  51. if (widget_->GetWindowBoundsInScreen().Contains(event_location))
  52. return;
  53. // Ignore clicks that hit the button (which usually spawned the widget).
  54. // Use HitTestPoint() because the shelf home button has a custom view targeter
  55. // that handles clicks outside its bounds, like in the corner of the screen.
  56. if (button_) {
  57. gfx::Point point_in_button = event_location;
  58. views::View::ConvertPointFromScreen(button_, &point_in_button);
  59. if (button_->HitTestPoint(point_in_button))
  60. return;
  61. }
  62. // Ignore clicks in the shelf area containing app icons.
  63. aura::Window* target = static_cast<aura::Window*>(event.target());
  64. if (target) {
  65. Shelf* shelf = Shelf::ForWindow(target);
  66. if (target == shelf->hotseat_widget()->GetNativeWindow() &&
  67. shelf->hotseat_widget()->EventTargetsShelfView(event)) {
  68. return;
  69. }
  70. // Don't dismiss the auto-hide shelf if event happened in status area. Then
  71. // the event can still be propagated.
  72. const aura::Window* status_window =
  73. shelf->shelf_widget()->status_area_widget()->GetNativeWindow();
  74. if (status_window && status_window->Contains(target))
  75. return;
  76. }
  77. on_click_outside_.Run();
  78. }
  79. } // namespace ash