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