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