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 
5 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "ui/aura/client/aura_constants.h"
15 #include "ui/aura/client/drag_drop_client.h"
16 #include "ui/aura/client/focus_client.h"
17 #include "ui/aura/client/transient_window_client.h"
18 #include "ui/base/hit_test.h"
19 #include "ui/display/display.h"
20 #include "ui/display/screen.h"
21 #include "ui/gfx/geometry/dip_util.h"
22 #include "ui/platform_window/extensions/workspace_extension.h"
23 #include "ui/platform_window/platform_window.h"
24 #include "ui/platform_window/platform_window_init_properties.h"
25 #include "ui/views/corewm/tooltip_aura.h"
26 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h"
27 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
28 #include "ui/views/widget/widget_aura_utils.h"
29 #include "ui/views/window/native_frame_view.h"
30 #include "ui/wm/core/window_util.h"
31 
32 namespace views {
33 
34 namespace {
35 
DetermineInactivity(ui::WindowShowState show_state)36 bool DetermineInactivity(ui::WindowShowState show_state) {
37   if (show_state != ui::SHOW_STATE_DEFAULT &&
38       show_state != ui::SHOW_STATE_NORMAL &&
39       show_state != ui::SHOW_STATE_INACTIVE &&
40       show_state != ui::SHOW_STATE_MAXIMIZED) {
41     // It will behave like SHOW_STATE_NORMAL.
42     NOTIMPLEMENTED_LOG_ONCE();
43   }
44 
45   // See comment in PlatformWindow::Show().
46   return show_state == ui::SHOW_STATE_INACTIVE;
47 }
48 
GetPlatformWindowOpacity(Widget::InitParams::WindowOpacity opacity)49 ui::PlatformWindowOpacity GetPlatformWindowOpacity(
50     Widget::InitParams::WindowOpacity opacity) {
51   switch (opacity) {
52     case Widget::InitParams::WindowOpacity::kInferred:
53       return ui::PlatformWindowOpacity::kInferOpacity;
54     case Widget::InitParams::WindowOpacity::kOpaque:
55       return ui::PlatformWindowOpacity::kOpaqueWindow;
56     case Widget::InitParams::WindowOpacity::kTranslucent:
57       return ui::PlatformWindowOpacity::kTranslucentWindow;
58   }
59   return ui::PlatformWindowOpacity::kOpaqueWindow;
60 }
61 
GetPlatformWindowType(Widget::InitParams::Type window_type)62 ui::PlatformWindowType GetPlatformWindowType(
63     Widget::InitParams::Type window_type) {
64   switch (window_type) {
65     case Widget::InitParams::TYPE_WINDOW:
66       return ui::PlatformWindowType::kWindow;
67     case Widget::InitParams::TYPE_MENU:
68       return ui::PlatformWindowType::kMenu;
69     case Widget::InitParams::TYPE_TOOLTIP:
70       return ui::PlatformWindowType::kTooltip;
71     case Widget::InitParams::TYPE_DRAG:
72       return ui::PlatformWindowType::kDrag;
73     case Widget::InitParams::TYPE_BUBBLE:
74       return ui::PlatformWindowType::kBubble;
75     default:
76       return ui::PlatformWindowType::kPopup;
77   }
78   NOTREACHED();
79   return ui::PlatformWindowType::kPopup;
80 }
81 
ConvertWidgetInitParamsToInitProperties(const Widget::InitParams & params)82 ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties(
83     const Widget::InitParams& params) {
84   ui::PlatformWindowInitProperties properties;
85   properties.type = GetPlatformWindowType(params.type);
86   properties.activatable =
87       params.activatable == Widget::InitParams::ACTIVATABLE_YES;
88   properties.force_show_in_taskbar = params.force_show_in_taskbar;
89   properties.keep_on_top =
90       params.EffectiveZOrderLevel() != ui::ZOrderLevel::kNormal;
91   properties.visible_on_all_workspaces = params.visible_on_all_workspaces;
92   properties.remove_standard_frame = params.remove_standard_frame;
93   properties.workspace = params.workspace;
94   properties.opacity = GetPlatformWindowOpacity(params.opacity);
95 
96   if (params.parent && params.parent->GetHost())
97     properties.parent_widget = params.parent->GetHost()->GetAcceleratedWidget();
98 
99   return properties;
100 }
101 
102 }  // namespace
103 
104 ////////////////////////////////////////////////////////////////////////////////
105 // DesktopWindowTreeHostPlatform:
106 
DesktopWindowTreeHostPlatform(internal::NativeWidgetDelegate * native_widget_delegate,DesktopNativeWidgetAura * desktop_native_widget_aura)107 DesktopWindowTreeHostPlatform::DesktopWindowTreeHostPlatform(
108     internal::NativeWidgetDelegate* native_widget_delegate,
109     DesktopNativeWidgetAura* desktop_native_widget_aura)
110     : native_widget_delegate_(native_widget_delegate),
111       desktop_native_widget_aura_(desktop_native_widget_aura) {}
112 
~DesktopWindowTreeHostPlatform()113 DesktopWindowTreeHostPlatform::~DesktopWindowTreeHostPlatform() {
114   DCHECK(!platform_window()) << "The host must be closed before destroying it.";
115   desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
116   DestroyDispatcher();
117 }
118 
GetContentWindow()119 aura::Window* DesktopWindowTreeHostPlatform::GetContentWindow() {
120   return desktop_native_widget_aura_->content_window();
121 }
122 
Init(const Widget::InitParams & params)123 void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
124   if (params.type == Widget::InitParams::TYPE_WINDOW)
125     GetContentWindow()->SetProperty(aura::client::kAnimationsDisabledKey, true);
126 
127   // If we have a parent, record the parent/child relationship. We use this
128   // data during destruction to make sure that when we try to close a parent
129   // window, we also destroy all child windows.
130   if (params.parent && params.parent->GetHost()) {
131     window_parent_ =
132         static_cast<DesktopWindowTreeHostPlatform*>(params.parent->GetHost());
133     DCHECK(window_parent_);
134     window_parent_->window_children_.insert(this);
135   }
136 
137   ui::PlatformWindowInitProperties properties =
138       ConvertWidgetInitParamsToInitProperties(params);
139   AddAdditionalInitProperties(params, &properties);
140 
141   // Calculate initial bounds.
142   properties.bounds = ToPixelRect(params.bounds);
143 
144   // Set extensions delegate.
145   DCHECK(!properties.workspace_extension_delegate);
146   properties.workspace_extension_delegate = this;
147 
148   CreateAndSetPlatformWindow(std::move(properties));
149 
150   // Disable compositing on tooltips as a workaround for
151   // https://crbug.com/442111.
152   CreateCompositor(viz::FrameSinkId(),
153                    params.force_software_compositing ||
154                        params.type == Widget::InitParams::TYPE_TOOLTIP);
155 
156   WindowTreeHost::OnAcceleratedWidgetAvailable();
157   InitHost();
158   window()->Show();
159 }
160 
OnNativeWidgetCreated(const Widget::InitParams & params)161 void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
162     const Widget::InitParams& params) {
163   platform_window()->SetUseNativeFrame(params.type ==
164                                            Widget::InitParams::TYPE_WINDOW &&
165                                        !params.remove_standard_frame);
166 
167   native_widget_delegate_->OnNativeWidgetCreated();
168 }
169 
OnWidgetInitDone()170 void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
171 
OnActiveWindowChanged(bool active)172 void DesktopWindowTreeHostPlatform::OnActiveWindowChanged(bool active) {}
173 
174 std::unique_ptr<corewm::Tooltip>
CreateTooltip()175 DesktopWindowTreeHostPlatform::CreateTooltip() {
176   return std::make_unique<corewm::TooltipAura>();
177 }
178 
179 std::unique_ptr<aura::client::DragDropClient>
CreateDragDropClient(DesktopNativeCursorManager * cursor_manager)180 DesktopWindowTreeHostPlatform::CreateDragDropClient(
181     DesktopNativeCursorManager* cursor_manager) {
182 #if !defined(USE_X11)
183   ui::WmDragHandler* drag_handler = ui::GetWmDragHandler(*(platform_window()));
184   std::unique_ptr<DesktopDragDropClientOzone> drag_drop_client =
185       std::make_unique<DesktopDragDropClientOzone>(window(), cursor_manager,
186                                                    drag_handler);
187   // Set a class property key, which allows |drag_drop_client| to be used for
188   // drop action.
189   SetWmDropHandler(platform_window(), drag_drop_client.get());
190   return std::move(drag_drop_client);
191 #else
192   // TODO(https://crbug.com/990756): Move the X11 initialization of dnd here.
193   NOTIMPLEMENTED_LOG_ONCE();
194   return nullptr;
195 #endif
196 }
197 
Close()198 void DesktopWindowTreeHostPlatform::Close() {
199   // If we are in process of closing or the PlatformWindow has already been
200   // closed, do nothing.
201   if (close_widget_factory_.HasWeakPtrs() || !platform_window())
202     return;
203 
204   GetContentWindow()->Hide();
205 
206   // Hide while waiting for the close.
207   // Please note that it's better to call WindowTreeHost::Hide, which also calls
208   // PlatformWindow::Hide and Compositor::SetVisible(false).
209   Hide();
210 
211   // And we delay the close so that if we are called from an ATL callback,
212   // we don't destroy the window before the callback returned (as the caller
213   // may delete ourselves on destroy and the ATL callback would still
214   // dereference us when the callback returns).
215   base::ThreadTaskRunnerHandle::Get()->PostTask(
216       FROM_HERE, base::BindOnce(&DesktopWindowTreeHostPlatform::CloseNow,
217                                 close_widget_factory_.GetWeakPtr()));
218 }
219 
CloseNow()220 void DesktopWindowTreeHostPlatform::CloseNow() {
221   if (!platform_window())
222     return;
223 
224 #if defined(USE_OZONE)
225   SetWmDropHandler(platform_window(), nullptr);
226 #endif
227 
228   platform_window()->PrepareForShutdown();
229 
230   ReleaseCapture();
231   native_widget_delegate_->OnNativeWidgetDestroying();
232 
233   // If we have children, close them. Use a copy for iteration because they'll
234   // remove themselves.
235   std::set<DesktopWindowTreeHostPlatform*> window_children_copy =
236       window_children_;
237   for (auto* child : window_children_copy)
238     child->CloseNow();
239   DCHECK(window_children_.empty());
240 
241   // If we have a parent, remove ourselves from its children list.
242   if (window_parent_) {
243     window_parent_->window_children_.erase(this);
244     window_parent_ = nullptr;
245   }
246 
247   // Destroy the compositor before destroying the |platform_window()| since
248   // shutdown may try to swap, and the swap without a window may cause an error
249   // in X Server or Wayland, which causes a crash with in-process renderer, for
250   // example.
251   DestroyCompositor();
252 
253   platform_window()->Close();
254 }
255 
AsWindowTreeHost()256 aura::WindowTreeHost* DesktopWindowTreeHostPlatform::AsWindowTreeHost() {
257   return this;
258 }
259 
Show(ui::WindowShowState show_state,const gfx::Rect & restore_bounds)260 void DesktopWindowTreeHostPlatform::Show(ui::WindowShowState show_state,
261                                          const gfx::Rect& restore_bounds) {
262   if (compositor())
263     SetVisible(true);
264 
265   platform_window()->Show(DetermineInactivity(show_state));
266 
267   switch (show_state) {
268     case ui::SHOW_STATE_MAXIMIZED:
269       platform_window()->Maximize();
270       if (!restore_bounds.IsEmpty()) {
271         // Enforce |restored_bounds_in_pixels_| since calling Maximize() could
272         // have reset it.
273         platform_window()->SetRestoredBoundsInPixels(
274             ToPixelRect(restore_bounds));
275       }
276       break;
277     case ui::SHOW_STATE_MINIMIZED:
278       platform_window()->Minimize();
279       break;
280     case ui::SHOW_STATE_FULLSCREEN:
281       SetFullscreen(true);
282       break;
283     default:
284       break;
285   }
286 
287   if (native_widget_delegate_->CanActivate()) {
288     if (show_state != ui::SHOW_STATE_INACTIVE)
289       Activate();
290 
291     // SetInitialFocus() should be always be called, even for
292     // SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
293     // do the right thing.
294     // Activate() might fail if the window is non-activatable. In this case, we
295     // should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
296     // focused view from getting focused. See https://crbug.com/515594 for
297     // example.
298     native_widget_delegate_->SetInitialFocus(
299         IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
300   }
301 
302   GetContentWindow()->Show();
303 }
304 
IsVisible() const305 bool DesktopWindowTreeHostPlatform::IsVisible() const {
306   return platform_window()->IsVisible();
307 }
308 
SetSize(const gfx::Size & size)309 void DesktopWindowTreeHostPlatform::SetSize(const gfx::Size& size) {
310   gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(size)).size();
311   auto bounds_in_pixels = GetBoundsInPixels();
312   bounds_in_pixels.set_size(size_in_pixels);
313   WindowTreeHostPlatform::SetBoundsInPixels(bounds_in_pixels);
314 }
315 
StackAbove(aura::Window * window)316 void DesktopWindowTreeHostPlatform::StackAbove(aura::Window* window) {
317   if (!window || !window->GetRootWindow())
318     return;
319 
320   platform_window()->StackAbove(window->GetHost()->GetAcceleratedWidget());
321 }
322 
StackAtTop()323 void DesktopWindowTreeHostPlatform::StackAtTop() {
324   platform_window()->StackAtTop();
325 }
326 
CenterWindow(const gfx::Size & size)327 void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
328   gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(size)).size();
329   gfx::Rect parent_bounds_in_pixels = ToPixelRect(GetWorkAreaBoundsInScreen());
330 
331   // If |window_|'s transient parent bounds are big enough to contain |size|,
332   // use them instead.
333   if (wm::GetTransientParent(GetContentWindow())) {
334     gfx::Rect transient_parent_rect =
335         wm::GetTransientParent(GetContentWindow())->GetBoundsInScreen();
336     if (transient_parent_rect.height() >= size.height() &&
337         transient_parent_rect.width() >= size.width()) {
338       parent_bounds_in_pixels = ToPixelRect(transient_parent_rect);
339     }
340   }
341 
342   gfx::Rect window_bounds_in_pixels(
343       parent_bounds_in_pixels.x() +
344           (parent_bounds_in_pixels.width() - size_in_pixels.width()) / 2,
345       parent_bounds_in_pixels.y() +
346           (parent_bounds_in_pixels.height() - size_in_pixels.height()) / 2,
347       size_in_pixels.width(), size_in_pixels.height());
348   // Don't size the window bigger than the parent, otherwise the user may not be
349   // able to close or move it.
350   window_bounds_in_pixels.AdjustToFit(parent_bounds_in_pixels);
351 
352   SetBoundsInPixels(window_bounds_in_pixels);
353 }
354 
GetWindowPlacement(gfx::Rect * bounds,ui::WindowShowState * show_state) const355 void DesktopWindowTreeHostPlatform::GetWindowPlacement(
356     gfx::Rect* bounds,
357     ui::WindowShowState* show_state) const {
358   *bounds = GetRestoredBounds();
359 
360   if (IsFullscreen())
361     *show_state = ui::SHOW_STATE_FULLSCREEN;
362   else if (IsMinimized())
363     *show_state = ui::SHOW_STATE_MINIMIZED;
364   else if (IsMaximized())
365     *show_state = ui::SHOW_STATE_MAXIMIZED;
366   else if (!IsActive())
367     *show_state = ui::SHOW_STATE_INACTIVE;
368   else
369     *show_state = ui::SHOW_STATE_NORMAL;
370 }
371 
GetWindowBoundsInScreen() const372 gfx::Rect DesktopWindowTreeHostPlatform::GetWindowBoundsInScreen() const {
373   return ToDIPRect(GetBoundsInPixels());
374 }
375 
GetClientAreaBoundsInScreen() const376 gfx::Rect DesktopWindowTreeHostPlatform::GetClientAreaBoundsInScreen() const {
377   // Attempts to calculate the rect by asking the NonClientFrameView what it
378   // thought its GetBoundsForClientView() were broke combobox drop down
379   // placement.
380   return GetWindowBoundsInScreen();
381 }
382 
GetRestoredBounds() const383 gfx::Rect DesktopWindowTreeHostPlatform::GetRestoredBounds() const {
384   // We can't reliably track the restored bounds of a window, but we can get
385   // the 90% case down. When *chrome* is the process that requests maximizing
386   // or restoring bounds, we can record the current bounds before we request
387   // maximization, and clear it when we detect a state change.
388   gfx::Rect restored_bounds = platform_window()->GetRestoredBoundsInPixels();
389 
390   // When window is resized, |restored bounds| is not set and empty.
391   // If |restored bounds| is empty, it returns the current window size.
392   if (!restored_bounds.IsEmpty())
393     return ToDIPRect(restored_bounds);
394 
395   return GetWindowBoundsInScreen();
396 }
397 
GetWorkspace() const398 std::string DesktopWindowTreeHostPlatform::GetWorkspace() const {
399   auto* workspace_extension = ui::GetWorkspaceExtension(*platform_window());
400   return workspace_extension ? workspace_extension->GetWorkspace()
401                              : std::string();
402 }
403 
GetWorkAreaBoundsInScreen() const404 gfx::Rect DesktopWindowTreeHostPlatform::GetWorkAreaBoundsInScreen() const {
405   // TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
406   return display::Screen::GetScreen()
407       ->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
408       .work_area();
409 }
410 
SetShape(std::unique_ptr<Widget::ShapeRects> native_shape)411 void DesktopWindowTreeHostPlatform::SetShape(
412     std::unique_ptr<Widget::ShapeRects> native_shape) {
413   platform_window()->SetShape(std::move(native_shape), GetRootTransform());
414 }
415 
Activate()416 void DesktopWindowTreeHostPlatform::Activate() {
417   platform_window()->Activate();
418 }
419 
Deactivate()420 void DesktopWindowTreeHostPlatform::Deactivate() {
421   ReleaseCapture();
422   platform_window()->Deactivate();
423 }
424 
IsActive() const425 bool DesktopWindowTreeHostPlatform::IsActive() const {
426   return is_active_;
427 }
428 
Maximize()429 void DesktopWindowTreeHostPlatform::Maximize() {
430   platform_window()->Maximize();
431   if (IsMinimized())
432     Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
433 }
434 
Minimize()435 void DesktopWindowTreeHostPlatform::Minimize() {
436   ReleaseCapture();
437   platform_window()->Minimize();
438 }
439 
Restore()440 void DesktopWindowTreeHostPlatform::Restore() {
441   platform_window()->Restore();
442   Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
443 }
444 
IsMaximized() const445 bool DesktopWindowTreeHostPlatform::IsMaximized() const {
446   return platform_window()->GetPlatformWindowState() ==
447          ui::PlatformWindowState::kMaximized;
448 }
449 
IsMinimized() const450 bool DesktopWindowTreeHostPlatform::IsMinimized() const {
451   return platform_window()->GetPlatformWindowState() ==
452          ui::PlatformWindowState::kMinimized;
453 }
454 
HasCapture() const455 bool DesktopWindowTreeHostPlatform::HasCapture() const {
456   return platform_window()->HasCapture();
457 }
458 
SetZOrderLevel(ui::ZOrderLevel order)459 void DesktopWindowTreeHostPlatform::SetZOrderLevel(ui::ZOrderLevel order) {
460   platform_window()->SetZOrderLevel(order);
461 }
462 
GetZOrderLevel() const463 ui::ZOrderLevel DesktopWindowTreeHostPlatform::GetZOrderLevel() const {
464   return platform_window()->GetZOrderLevel();
465 }
466 
SetVisibleOnAllWorkspaces(bool always_visible)467 void DesktopWindowTreeHostPlatform::SetVisibleOnAllWorkspaces(
468     bool always_visible) {
469   auto* workspace_extension = ui::GetWorkspaceExtension(*platform_window());
470   if (workspace_extension)
471     workspace_extension->SetVisibleOnAllWorkspaces(always_visible);
472 }
473 
IsVisibleOnAllWorkspaces() const474 bool DesktopWindowTreeHostPlatform::IsVisibleOnAllWorkspaces() const {
475   auto* workspace_extension = ui::GetWorkspaceExtension(*platform_window());
476   return workspace_extension ? workspace_extension->IsVisibleOnAllWorkspaces()
477                              : false;
478 }
479 
SetWindowTitle(const base::string16 & title)480 bool DesktopWindowTreeHostPlatform::SetWindowTitle(
481     const base::string16& title) {
482   if (window_title_ == title)
483     return false;
484 
485   window_title_ = title;
486   platform_window()->SetTitle(window_title_);
487   return true;
488 }
489 
ClearNativeFocus()490 void DesktopWindowTreeHostPlatform::ClearNativeFocus() {
491   // This method is weird and misnamed. Instead of clearing the native focus,
492   // it sets the focus to our content_window, which will trigger a cascade
493   // of focus changes into views.
494   if (GetContentWindow() && aura::client::GetFocusClient(GetContentWindow()) &&
495       GetContentWindow()->Contains(
496           aura::client::GetFocusClient(GetContentWindow())
497               ->GetFocusedWindow())) {
498     aura::client::GetFocusClient(GetContentWindow())
499         ->FocusWindow(GetContentWindow());
500   }
501 }
502 
RunMoveLoop(const gfx::Vector2d & drag_offset,Widget::MoveLoopSource source,Widget::MoveLoopEscapeBehavior escape_behavior)503 Widget::MoveLoopResult DesktopWindowTreeHostPlatform::RunMoveLoop(
504     const gfx::Vector2d& drag_offset,
505     Widget::MoveLoopSource source,
506     Widget::MoveLoopEscapeBehavior escape_behavior) {
507   // TODO(crbug.com/896640): needs PlatformWindow support.
508   NOTIMPLEMENTED_LOG_ONCE();
509   return Widget::MOVE_LOOP_CANCELED;
510 }
511 
EndMoveLoop()512 void DesktopWindowTreeHostPlatform::EndMoveLoop() {
513   // TODO(crbug.com/896640): needs PlatformWindow support.
514   NOTIMPLEMENTED_LOG_ONCE();
515 }
516 
SetVisibilityChangedAnimationsEnabled(bool value)517 void DesktopWindowTreeHostPlatform::SetVisibilityChangedAnimationsEnabled(
518     bool value) {
519   platform_window()->SetVisibilityChangedAnimationsEnabled(value);
520 }
521 
CreateNonClientFrameView()522 NonClientFrameView* DesktopWindowTreeHostPlatform::CreateNonClientFrameView() {
523   return ShouldUseNativeFrame() ? new NativeFrameView(GetWidget()) : nullptr;
524 }
525 
ShouldUseNativeFrame() const526 bool DesktopWindowTreeHostPlatform::ShouldUseNativeFrame() const {
527   return platform_window()->ShouldUseNativeFrame();
528 }
529 
ShouldWindowContentsBeTransparent() const530 bool DesktopWindowTreeHostPlatform::ShouldWindowContentsBeTransparent() const {
531   return platform_window()->ShouldWindowContentsBeTransparent();
532 }
533 
FrameTypeChanged()534 void DesktopWindowTreeHostPlatform::FrameTypeChanged() {
535   Widget::FrameType new_type =
536       native_widget_delegate_->AsWidget()->frame_type();
537   if (new_type == Widget::FrameType::kDefault) {
538     // The default is determined by Widget::InitParams::remove_standard_frame
539     // and does not change.
540     return;
541   }
542   platform_window()->SetUseNativeFrame(new_type ==
543                                        Widget::FrameType::kForceNative);
544 
545   // Replace the frame and layout the contents. Even though we don't have a
546   // swappable glass frame like on Windows, we still replace the frame because
547   // the button assets don't update otherwise.
548   if (GetWidget()->non_client_view())
549     GetWidget()->non_client_view()->UpdateFrame();
550 }
551 
SetFullscreen(bool fullscreen)552 void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) {
553   if (IsFullscreen() == fullscreen)
554     return;
555 
556   platform_window()->ToggleFullscreen();
557 
558   // The state must change synchronously to let media react on fullscreen
559   // changes.
560   DCHECK_EQ(fullscreen, IsFullscreen());
561 
562   if (IsFullscreen() == fullscreen)
563     ScheduleRelayout();
564   // Else: the widget will be relaid out either when the window bounds change
565   // or when |platform_window|'s fullscreen state changes.
566 }
567 
IsFullscreen() const568 bool DesktopWindowTreeHostPlatform::IsFullscreen() const {
569   return platform_window()->GetPlatformWindowState() ==
570          ui::PlatformWindowState::kFullScreen;
571 }
572 
SetOpacity(float opacity)573 void DesktopWindowTreeHostPlatform::SetOpacity(float opacity) {
574   GetContentWindow()->layer()->SetOpacity(opacity);
575   platform_window()->SetOpacity(opacity);
576 }
577 
SetAspectRatio(const gfx::SizeF & aspect_ratio)578 void DesktopWindowTreeHostPlatform::SetAspectRatio(
579     const gfx::SizeF& aspect_ratio) {
580   platform_window()->SetAspectRatio(aspect_ratio);
581 }
582 
SetWindowIcons(const gfx::ImageSkia & window_icon,const gfx::ImageSkia & app_icon)583 void DesktopWindowTreeHostPlatform::SetWindowIcons(
584     const gfx::ImageSkia& window_icon,
585     const gfx::ImageSkia& app_icon) {
586   platform_window()->SetWindowIcons(window_icon, app_icon);
587 }
588 
InitModalType(ui::ModalType modal_type)589 void DesktopWindowTreeHostPlatform::InitModalType(ui::ModalType modal_type) {
590   NOTIMPLEMENTED_LOG_ONCE();
591 }
592 
FlashFrame(bool flash_frame)593 void DesktopWindowTreeHostPlatform::FlashFrame(bool flash_frame) {
594   platform_window()->FlashFrame(flash_frame);
595 }
596 
IsAnimatingClosed() const597 bool DesktopWindowTreeHostPlatform::IsAnimatingClosed() const {
598   return platform_window()->IsAnimatingClosed();
599 }
600 
IsTranslucentWindowOpacitySupported() const601 bool DesktopWindowTreeHostPlatform::IsTranslucentWindowOpacitySupported()
602     const {
603   return platform_window()->IsTranslucentWindowOpacitySupported();
604 }
605 
SizeConstraintsChanged()606 void DesktopWindowTreeHostPlatform::SizeConstraintsChanged() {
607   platform_window()->SizeConstraintsChanged();
608 }
609 
ShouldUpdateWindowTransparency() const610 bool DesktopWindowTreeHostPlatform::ShouldUpdateWindowTransparency() const {
611   return true;
612 }
613 
ShouldUseDesktopNativeCursorManager() const614 bool DesktopWindowTreeHostPlatform::ShouldUseDesktopNativeCursorManager()
615     const {
616   return true;
617 }
618 
ShouldCreateVisibilityController() const619 bool DesktopWindowTreeHostPlatform::ShouldCreateVisibilityController() const {
620   return true;
621 }
622 
GetRootTransform() const623 gfx::Transform DesktopWindowTreeHostPlatform::GetRootTransform() const {
624   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
625   // This might be called before the |platform_window| is created. Thus,
626   // explicitly check if that exists before trying to access its visibility and
627   // the display where it is shown.
628   if (platform_window() && IsVisible()) {
629     display = display::Screen::GetScreen()->GetDisplayNearestWindow(
630         GetWidget()->GetNativeWindow());
631   }
632 
633   float scale = display.device_scale_factor();
634   gfx::Transform transform;
635   transform.Scale(scale, scale);
636   return transform;
637 }
638 
ShowImpl()639 void DesktopWindowTreeHostPlatform::ShowImpl() {
640   Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
641 }
642 
HideImpl()643 void DesktopWindowTreeHostPlatform::HideImpl() {
644   WindowTreeHostPlatform::HideImpl();
645   native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
646 }
647 
OnClosed()648 void DesktopWindowTreeHostPlatform::OnClosed() {
649   SetPlatformWindow(nullptr);
650   desktop_native_widget_aura_->OnHostClosed();
651 }
652 
OnWindowStateChanged(ui::PlatformWindowState new_state)653 void DesktopWindowTreeHostPlatform::OnWindowStateChanged(
654     ui::PlatformWindowState new_state) {
655   bool was_minimized = old_state_ == ui::PlatformWindowState::kMinimized;
656   bool is_minimized = new_state == ui::PlatformWindowState::kMinimized;
657 
658   // Propagate minimization/restore to compositor to avoid drawing 'blank'
659   // frames that could be treated as previews, which show content even if a
660   // window is minimized.
661   if (is_minimized != was_minimized) {
662     if (is_minimized) {
663       SetVisible(false);
664       GetContentWindow()->Hide();
665     } else {
666       GetContentWindow()->Show();
667       SetVisible(true);
668     }
669   }
670 
671   old_state_ = new_state;
672 
673   // Now that we have different window properties, we may need to relayout the
674   // window. (The windows code doesn't need this because their window change is
675   // synchronous.)
676   ScheduleRelayout();
677 }
678 
OnCloseRequest()679 void DesktopWindowTreeHostPlatform::OnCloseRequest() {
680   GetWidget()->Close();
681 }
682 
OnActivationChanged(bool active)683 void DesktopWindowTreeHostPlatform::OnActivationChanged(bool active) {
684   if (is_active_ == active)
685     return;
686   is_active_ = active;
687   aura::WindowTreeHostPlatform::OnActivationChanged(active);
688   desktop_native_widget_aura_->HandleActivationChanged(active);
689   ScheduleRelayout();
690 }
691 
692 base::Optional<gfx::Size>
GetMinimumSizeForWindow()693 DesktopWindowTreeHostPlatform::GetMinimumSizeForWindow() {
694   return ToPixelRect(gfx::Rect(native_widget_delegate()->GetMinimumSize()))
695       .size();
696 }
697 
698 base::Optional<gfx::Size>
GetMaximumSizeForWindow()699 DesktopWindowTreeHostPlatform::GetMaximumSizeForWindow() {
700   return ToPixelRect(gfx::Rect(native_widget_delegate()->GetMaximumSize()))
701       .size();
702 }
703 
OnWorkspaceChanged()704 void DesktopWindowTreeHostPlatform::OnWorkspaceChanged() {
705   OnHostWorkspaceChanged();
706 }
707 
ToDIPRect(const gfx::Rect & rect_in_pixels) const708 gfx::Rect DesktopWindowTreeHostPlatform::ToDIPRect(
709     const gfx::Rect& rect_in_pixels) const {
710   gfx::RectF rect_in_dip = gfx::RectF(rect_in_pixels);
711   GetRootTransform().TransformRectReverse(&rect_in_dip);
712   return gfx::ToEnclosingRect(rect_in_dip);
713 }
714 
ToPixelRect(const gfx::Rect & rect_in_dip) const715 gfx::Rect DesktopWindowTreeHostPlatform::ToPixelRect(
716     const gfx::Rect& rect_in_dip) const {
717   gfx::RectF rect_in_pixels = gfx::RectF(rect_in_dip);
718   GetRootTransform().TransformRect(&rect_in_pixels);
719   return gfx::ToEnclosingRect(rect_in_pixels);
720 }
721 
ScheduleRelayout()722 void DesktopWindowTreeHostPlatform::ScheduleRelayout() {
723   Widget* widget = native_widget_delegate_->AsWidget();
724   NonClientView* non_client_view = widget->non_client_view();
725   // non_client_view may be NULL, especially during creation.
726   if (non_client_view) {
727     if (non_client_view->frame_view())
728       non_client_view->frame_view()->InvalidateLayout();
729     non_client_view->client_view()->InvalidateLayout();
730     non_client_view->InvalidateLayout();
731   }
732 }
733 
GetWidget()734 Widget* DesktopWindowTreeHostPlatform::GetWidget() {
735   return native_widget_delegate_->AsWidget();
736 }
737 
GetWidget() const738 const Widget* DesktopWindowTreeHostPlatform::GetWidget() const {
739   return native_widget_delegate_->AsWidget();
740 }
741 
SetVisible(bool visible)742 void DesktopWindowTreeHostPlatform::SetVisible(bool visible) {
743   if (compositor())
744     compositor()->SetVisible(visible);
745 
746   native_widget_delegate()->OnNativeWidgetVisibilityChanged(visible);
747 }
748 
AddAdditionalInitProperties(const Widget::InitParams & params,ui::PlatformWindowInitProperties * properties)749 void DesktopWindowTreeHostPlatform::AddAdditionalInitProperties(
750     const Widget::InitParams& params,
751     ui::PlatformWindowInitProperties* properties) {}
752 
753 ////////////////////////////////////////////////////////////////////////////////
754 // DesktopWindowTreeHost:
755 
756 // Linux subclasses this host and adds some Linux specific bits.
757 #if !defined(OS_LINUX) && !defined(OS_BSD)
758 // static
Create(internal::NativeWidgetDelegate * native_widget_delegate,DesktopNativeWidgetAura * desktop_native_widget_aura)759 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
760     internal::NativeWidgetDelegate* native_widget_delegate,
761     DesktopNativeWidgetAura* desktop_native_widget_aura) {
762   return new DesktopWindowTreeHostPlatform(native_widget_delegate,
763                                            desktop_native_widget_aura);
764 }
765 #endif
766 
767 }  // namespace views
768