wide_frame_view.cc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright 2018 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/frame/wide_frame_view.h"
  5. #include <memory>
  6. #include "ash/frame/header_view.h"
  7. #include "ash/frame/non_client_frame_view_ash.h"
  8. #include "ash/public/cpp/window_properties.h"
  9. #include "ash/screen_util.h"
  10. #include "ash/shell.h"
  11. #include "ash/wm/overview/overview_controller.h"
  12. #include "ash/wm/window_state.h"
  13. #include "ash/wm/wm_event.h"
  14. #include "base/bind.h"
  15. #include "base/metrics/user_metrics.h"
  16. #include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
  17. #include "chromeos/ui/frame/default_frame_header.h"
  18. #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
  19. #include "ui/aura/window.h"
  20. #include "ui/aura/window_targeter.h"
  21. #include "ui/display/display.h"
  22. #include "ui/display/screen.h"
  23. #include "ui/views/widget/widget.h"
  24. #include "ui/views/window/caption_button_layout_constants.h"
  25. namespace ash {
  26. namespace {
  27. using ::chromeos::ImmersiveFullscreenController;
  28. class WideFrameTargeter : public aura::WindowTargeter {
  29. public:
  30. explicit WideFrameTargeter(HeaderView* header_view)
  31. : header_view_(header_view) {}
  32. WideFrameTargeter(const WideFrameTargeter&) = delete;
  33. WideFrameTargeter& operator=(const WideFrameTargeter&) = delete;
  34. ~WideFrameTargeter() override = default;
  35. // aura::WindowTargeter:
  36. bool GetHitTestRects(aura::Window* target,
  37. gfx::Rect* hit_test_rect_mouse,
  38. gfx::Rect* hit_test_rect_touch) const override {
  39. if (header_view_->in_immersive_mode() && !header_view_->is_revealed()) {
  40. aura::Window* source = header_view_->GetWidget()->GetNativeWindow();
  41. *hit_test_rect_mouse = source->bounds();
  42. aura::Window::ConvertRectToTarget(source, target->parent(),
  43. hit_test_rect_mouse);
  44. hit_test_rect_mouse->set_y(target->bounds().y());
  45. hit_test_rect_mouse->set_height(1);
  46. hit_test_rect_touch->SetRect(0, 0, 0, 0);
  47. return true;
  48. }
  49. return aura::WindowTargeter::GetHitTestRects(target, hit_test_rect_mouse,
  50. hit_test_rect_touch);
  51. }
  52. private:
  53. HeaderView* header_view_;
  54. };
  55. } // namespace
  56. // static
  57. gfx::Rect WideFrameView::GetFrameBounds(views::Widget* target) {
  58. static const int kFrameHeight =
  59. views::GetCaptionButtonLayoutSize(
  60. views::CaptionButtonLayoutSize::kNonBrowserCaption)
  61. .height();
  62. aura::Window* target_window = target->GetNativeWindow();
  63. gfx::Rect bounds =
  64. screen_util::GetIdealBoundsForMaximizedOrFullscreenOrPinnedState(
  65. target_window);
  66. bounds.set_height(kFrameHeight);
  67. return bounds;
  68. }
  69. void WideFrameView::Init(ImmersiveFullscreenController* controller) {
  70. DCHECK(target_);
  71. controller->Init(this, target_, header_view_);
  72. }
  73. void WideFrameView::SetCaptionButtonModel(
  74. std::unique_ptr<chromeos::CaptionButtonModel> model) {
  75. header_view_->caption_button_container()->SetModel(std::move(model));
  76. header_view_->UpdateCaptionButtons();
  77. }
  78. WideFrameView::WideFrameView(views::Widget* target)
  79. : target_(target),
  80. frame_context_menu_controller_(
  81. std::make_unique<FrameContextMenuController>(target_, this)) {
  82. // WideFrameView is owned by its client, not by Views.
  83. SetOwnedByWidget(false);
  84. aura::Window* target_window = target->GetNativeWindow();
  85. target_window->AddObserver(this);
  86. // Use the HeaderView itself as a frame view because WideFrameView is
  87. // is the frame only.
  88. header_view_ = AddChildView(
  89. std::make_unique<HeaderView>(target, /*frame view=*/nullptr));
  90. header_view_->Init();
  91. GetTargetHeaderView()->SetShouldPaintHeader(false);
  92. header_view_->set_context_menu_controller(
  93. frame_context_menu_controller_.get());
  94. views::Widget::InitParams params;
  95. params.type = views::Widget::InitParams::TYPE_POPUP;
  96. params.delegate = this;
  97. params.bounds = GetFrameBounds(target);
  98. params.name = "WideFrameView";
  99. params.parent = target->GetNativeWindow();
  100. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  101. // Setup Opacity Control.
  102. // WideFrame should be used only when the rounded corner is not necessary.
  103. params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque;
  104. auto widget = std::make_unique<views::Widget>();
  105. widget->Init(std::move(params));
  106. widget_ = std::move(widget);
  107. aura::Window* window = widget_->GetNativeWindow();
  108. // Overview normally clips the caption container which exists on the same
  109. // window. But this WideFrameView exists as a separate window, which we hide
  110. // in overview using the `kHideInOverviewKey` property. However, we still want
  111. // to show it in the desks mini_views.
  112. window->SetProperty(kHideInOverviewKey, true);
  113. window->SetProperty(kForceVisibleInMiniViewKey, true);
  114. window->SetEventTargeter(std::make_unique<WideFrameTargeter>(header_view()));
  115. set_owned_by_client();
  116. WindowState::Get(window)->set_allow_set_bounds_direct(true);
  117. paint_as_active_subscription_ =
  118. target_->RegisterPaintAsActiveChangedCallback(base::BindRepeating(
  119. &WideFrameView::PaintAsActiveChanged, base::Unretained(this)));
  120. PaintAsActiveChanged();
  121. }
  122. WideFrameView::~WideFrameView() {
  123. if (widget_)
  124. widget_->CloseNow();
  125. if (target_) {
  126. HeaderView* target_header_view = GetTargetHeaderView();
  127. target_header_view->SetShouldPaintHeader(true);
  128. target_header_view->GetFrameHeader()->UpdateFrameHeaderKey();
  129. target_->GetNativeWindow()->RemoveObserver(this);
  130. }
  131. }
  132. void WideFrameView::Layout() {
  133. int onscreen_height = header_view_->GetPreferredOnScreenHeight();
  134. if (onscreen_height == 0 || !GetVisible()) {
  135. header_view_->SetVisible(false);
  136. } else {
  137. const int height = header_view_->GetPreferredHeight();
  138. header_view_->SetBounds(0, onscreen_height - height, width(), height);
  139. header_view_->SetVisible(true);
  140. }
  141. }
  142. void WideFrameView::OnMouseEvent(ui::MouseEvent* event) {
  143. if (event->IsOnlyLeftMouseButton()) {
  144. if ((event->flags() & ui::EF_IS_DOUBLE_CLICK)) {
  145. base::RecordAction(
  146. base::UserMetricsAction("Caption_ClickTogglesMaximize"));
  147. const WMEvent wm_event(WM_EVENT_TOGGLE_MAXIMIZE_CAPTION);
  148. WindowState::Get(target_->GetNativeWindow())->OnWMEvent(&wm_event);
  149. }
  150. event->SetHandled();
  151. }
  152. }
  153. void WideFrameView::OnWindowDestroying(aura::Window* window) {
  154. window->RemoveObserver(this);
  155. target_ = nullptr;
  156. }
  157. void WideFrameView::OnDisplayMetricsChanged(const display::Display& display,
  158. uint32_t changed_metrics) {
  159. aura::Window* target_window = target_->GetNativeWindow();
  160. // The target window is detached from the tree when the window is being moved
  161. // to another desks, or another display, and it may trigger the display
  162. // metrics change if the target window is in fullscreen. Do not try to layout
  163. // in this case. The it'll be layout when the window is added back.
  164. // (crbug.com/1267128)
  165. if (!target_window->GetRootWindow())
  166. return;
  167. display::Screen* screen = display::Screen::GetScreen();
  168. if (screen->GetDisplayNearestWindow(target_->GetNativeWindow()).id() !=
  169. display.id() ||
  170. !widget_) {
  171. return;
  172. }
  173. DCHECK(target_);
  174. // Ignore if this is called when the targe window state is nor proper
  175. // state. This can happen when switching the state to other states, in which
  176. // case, the wide frame will be removed.
  177. if (!WindowState::Get(target_window)->IsMaximizedOrFullscreenOrPinned()) {
  178. return;
  179. }
  180. GetWidget()->SetBounds(GetFrameBounds(target_));
  181. }
  182. void WideFrameView::OnImmersiveRevealStarted() {
  183. header_view_->OnImmersiveRevealStarted();
  184. }
  185. void WideFrameView::OnImmersiveRevealEnded() {
  186. header_view_->OnImmersiveRevealEnded();
  187. }
  188. void WideFrameView::OnImmersiveFullscreenEntered() {
  189. header_view_->OnImmersiveFullscreenEntered();
  190. widget_->GetNativeWindow()->SetTransparent(true);
  191. if (target_)
  192. GetTargetHeaderView()->OnImmersiveFullscreenEntered();
  193. }
  194. void WideFrameView::OnImmersiveFullscreenExited() {
  195. header_view_->OnImmersiveFullscreenExited();
  196. widget_->GetNativeWindow()->SetTransparent(false);
  197. if (target_)
  198. GetTargetHeaderView()->OnImmersiveFullscreenExited();
  199. Layout();
  200. }
  201. void WideFrameView::SetVisibleFraction(double visible_fraction) {
  202. header_view_->SetVisibleFraction(visible_fraction);
  203. }
  204. std::vector<gfx::Rect> WideFrameView::GetVisibleBoundsInScreen() const {
  205. return header_view_->GetVisibleBoundsInScreen();
  206. }
  207. bool WideFrameView::ShouldShowContextMenu(
  208. View* source,
  209. const gfx::Point& screen_coords_point) {
  210. gfx::Point point_in_header_coords(screen_coords_point);
  211. views::View::ConvertPointToTarget(this, header_view_,
  212. &point_in_header_coords);
  213. return header_view_->HitTestRect(
  214. gfx::Rect(point_in_header_coords, gfx::Size(1, 1)));
  215. }
  216. HeaderView* WideFrameView::GetTargetHeaderView() {
  217. auto* frame_view = static_cast<NonClientFrameViewAsh*>(
  218. target_->non_client_view()->frame_view());
  219. return frame_view->GetHeaderView();
  220. }
  221. void WideFrameView::PaintAsActiveChanged() {
  222. header_view_->GetFrameHeader()->SetPaintAsActive(
  223. target_->ShouldPaintAsActive());
  224. }
  225. } // namespace ash