OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/exo/shell_surface.h" | 5 #include "components/exo/shell_surface.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell_window_ids.h" | 8 #include "ash/shell_window_ids.h" |
9 #include "ash/wm/window_state.h" | 9 #include "ash/wm/window_state.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
14 #include "base/trace_event/trace_event_argument.h" | 14 #include "base/trace_event/trace_event_argument.h" |
15 #include "components/exo/surface.h" | 15 #include "components/exo/surface.h" |
16 #include "ui/aura/window.h" | 16 #include "ui/aura/window.h" |
17 #include "ui/aura/window_property.h" | 17 #include "ui/aura/window_property.h" |
18 #include "ui/aura/window_targeter.h" | 18 #include "ui/aura/window_targeter.h" |
19 #include "ui/base/hit_test.h" | 19 #include "ui/base/hit_test.h" |
20 #include "ui/gfx/path.h" | 20 #include "ui/gfx/path.h" |
21 #include "ui/views/widget/widget.h" | 21 #include "ui/views/widget/widget.h" |
| 22 #include "ui/wm/core/window_util.h" |
22 #include "ui/wm/public/activation_client.h" | 23 #include "ui/wm/public/activation_client.h" |
23 | 24 |
24 DECLARE_WINDOW_PROPERTY_TYPE(std::string*) | 25 DECLARE_WINDOW_PROPERTY_TYPE(std::string*) |
25 | 26 |
26 namespace exo { | 27 namespace exo { |
27 namespace { | 28 namespace { |
28 | 29 |
29 class CustomFrameView : public views::NonClientFrameView { | 30 class CustomFrameView : public views::NonClientFrameView { |
30 public: | 31 public: |
31 explicit CustomFrameView(views::Widget* widget) : widget_(widget) {} | 32 explicit CustomFrameView(views::Widget* widget) : widget_(widget) {} |
(...skipping 21 matching lines...) Expand all Loading... |
53 }; | 54 }; |
54 | 55 |
55 class CustomWindowTargeter : public aura::WindowTargeter { | 56 class CustomWindowTargeter : public aura::WindowTargeter { |
56 public: | 57 public: |
57 CustomWindowTargeter() {} | 58 CustomWindowTargeter() {} |
58 ~CustomWindowTargeter() override {} | 59 ~CustomWindowTargeter() override {} |
59 | 60 |
60 // Overridden from aura::WindowTargeter: | 61 // Overridden from aura::WindowTargeter: |
61 bool EventLocationInsideBounds(aura::Window* window, | 62 bool EventLocationInsideBounds(aura::Window* window, |
62 const ui::LocatedEvent& event) const override { | 63 const ui::LocatedEvent& event) const override { |
63 return PointInsideBounds(window, event.location()); | |
64 } | |
65 | |
66 private: | |
67 bool PointInsideBounds(const aura::Window* window, | |
68 const gfx::Point& point) const { | |
69 Surface* surface = ShellSurface::GetMainSurface(window); | 64 Surface* surface = ShellSurface::GetMainSurface(window); |
70 if (!surface) | 65 if (!surface) |
71 return false; | 66 return false; |
72 | 67 |
73 gfx::Point local_point = point; | 68 gfx::Point local_point = event.location(); |
74 if (window->parent()) { | 69 if (window->parent()) |
75 aura::Window::ConvertPointToTarget(window->parent(), window, | 70 aura::Window::ConvertPointToTarget(window->parent(), window, |
76 &local_point); | 71 &local_point); |
77 } | |
78 | |
79 // If point is inside a child window then it's also inside the parent. | |
80 for (const aura::Window* child : window->children()) { | |
81 if (PointInsideBounds(child, local_point)) | |
82 return true; | |
83 } | |
84 | 72 |
85 aura::Window::ConvertPointToTarget(window, surface, &local_point); | 73 aura::Window::ConvertPointToTarget(window, surface, &local_point); |
86 return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1))); | 74 return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1))); |
87 } | 75 } |
88 | 76 |
| 77 private: |
89 DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter); | 78 DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter); |
90 }; | 79 }; |
91 | 80 |
92 class ShellSurfaceWidget : public views::Widget { | 81 class ShellSurfaceWidget : public views::Widget { |
93 public: | 82 public: |
94 explicit ShellSurfaceWidget(ShellSurface* shell_surface) | 83 explicit ShellSurfaceWidget(ShellSurface* shell_surface) |
95 : shell_surface_(shell_surface) {} | 84 : shell_surface_(shell_surface) {} |
96 | 85 |
97 // Overridden from views::Widget | 86 // Overridden from views::Widget |
98 void Close() override { shell_surface_->Close(); } | 87 void Close() override { shell_surface_->Close(); } |
99 | 88 |
100 private: | 89 private: |
101 ShellSurface* const shell_surface_; | 90 ShellSurface* const shell_surface_; |
102 | 91 |
103 DISALLOW_COPY_AND_ASSIGN(ShellSurfaceWidget); | 92 DISALLOW_COPY_AND_ASSIGN(ShellSurfaceWidget); |
104 }; | 93 }; |
105 | 94 |
106 } // namespace | 95 } // namespace |
107 | 96 |
108 //////////////////////////////////////////////////////////////////////////////// | 97 //////////////////////////////////////////////////////////////////////////////// |
109 // ShellSurface, public: | 98 // ShellSurface, public: |
110 | 99 |
111 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(std::string*, kApplicationIdKey, nullptr) | 100 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(std::string*, kApplicationIdKey, nullptr) |
112 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(Surface*, kMainSurfaceKey, nullptr) | 101 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(Surface*, kMainSurfaceKey, nullptr) |
113 | 102 |
114 ShellSurface::ShellSurface(Surface* surface, | 103 ShellSurface::ShellSurface(Surface* surface, |
115 ShellSurface* parent, | 104 ShellSurface* parent, |
116 const gfx::Rect& initial_bounds) | 105 const gfx::Rect& initial_bounds, |
117 : surface_(surface), | 106 bool activatable) |
| 107 : widget_(nullptr), |
| 108 surface_(surface), |
118 parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr), | 109 parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr), |
119 initial_bounds_(initial_bounds) { | 110 initial_bounds_(initial_bounds), |
| 111 activatable_(activatable) { |
120 ash::Shell::GetInstance()->activation_client()->AddObserver(this); | 112 ash::Shell::GetInstance()->activation_client()->AddObserver(this); |
121 surface_->SetSurfaceDelegate(this); | 113 surface_->SetSurfaceDelegate(this); |
122 surface_->AddSurfaceObserver(this); | 114 surface_->AddSurfaceObserver(this); |
123 surface_->Show(); | 115 surface_->Show(); |
124 set_owned_by_client(); | 116 set_owned_by_client(); |
125 if (parent_) | 117 if (parent_) |
126 parent_->AddObserver(this); | 118 parent_->AddObserver(this); |
127 } | 119 } |
128 | 120 |
129 ShellSurface::ShellSurface(Surface* surface) | 121 ShellSurface::ShellSurface(Surface* surface) |
130 : ShellSurface(surface, nullptr, gfx::Rect()) {} | 122 : ShellSurface(surface, nullptr, gfx::Rect(), true) {} |
131 | 123 |
132 ShellSurface::~ShellSurface() { | 124 ShellSurface::~ShellSurface() { |
133 ash::Shell::GetInstance()->activation_client()->RemoveObserver(this); | 125 ash::Shell::GetInstance()->activation_client()->RemoveObserver(this); |
134 if (surface_) { | 126 if (surface_) { |
135 surface_->SetSurfaceDelegate(nullptr); | 127 surface_->SetSurfaceDelegate(nullptr); |
136 surface_->RemoveSurfaceObserver(this); | 128 surface_->RemoveSurfaceObserver(this); |
137 } | 129 } |
138 if (parent_) | 130 if (parent_) |
139 parent_->RemoveObserver(this); | 131 parent_->RemoveObserver(this); |
140 if (widget_) { | 132 if (widget_) { |
141 ash::wm::GetWindowState(widget_->GetNativeWindow())->RemoveObserver(this); | 133 ash::wm::GetWindowState(widget_->GetNativeWindow())->RemoveObserver(this); |
142 if (widget_->IsVisible()) | 134 if (widget_->IsVisible()) |
143 widget_->Hide(); | 135 widget_->Hide(); |
144 widget_->CloseNow(); | 136 widget_->CloseNow(); |
145 } | 137 } |
146 } | 138 } |
147 | 139 |
148 void ShellSurface::SetParent(ShellSurface* parent) { | 140 void ShellSurface::SetParent(ShellSurface* parent) { |
149 TRACE_EVENT1("exo", "ShellSurface::SetParent", "parent", | 141 TRACE_EVENT1("exo", "ShellSurface::SetParent", "parent", |
150 parent ? base::UTF16ToASCII(parent->title_) : "null"); | 142 parent ? base::UTF16ToASCII(parent->title_) : "null"); |
151 | 143 |
152 if (parent_) | 144 if (parent_) { |
153 parent_->RemoveObserver(this); | 145 parent_->RemoveObserver(this); |
| 146 if (widget_) |
| 147 wm::RemoveTransientChild(parent_, widget_->GetNativeWindow()); |
| 148 } |
154 parent_ = parent ? parent->GetWidget()->GetNativeWindow() : nullptr; | 149 parent_ = parent ? parent->GetWidget()->GetNativeWindow() : nullptr; |
155 if (parent_) | 150 if (parent_) { |
156 parent_->AddObserver(this); | 151 parent_->AddObserver(this); |
| 152 if (widget_) |
| 153 wm::AddTransientChild(parent_, widget_->GetNativeWindow()); |
| 154 } |
157 } | 155 } |
158 | 156 |
159 void ShellSurface::Maximize() { | 157 void ShellSurface::Maximize() { |
160 TRACE_EVENT0("exo", "ShellSurface::Maximize"); | 158 TRACE_EVENT0("exo", "ShellSurface::Maximize"); |
161 | 159 |
162 if (!widget_) | 160 if (!widget_) |
163 CreateShellSurfaceWidget(); | 161 CreateShellSurfaceWidget(); |
164 | 162 |
165 // Ask client to configure its surface if already maximized. | 163 // Ask client to configure its surface if already maximized. |
166 if (widget_->IsMaximized()) { | 164 if (widget_->IsMaximized()) { |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 // SurfaceDelegate overrides: | 275 // SurfaceDelegate overrides: |
278 | 276 |
279 void ShellSurface::OnSurfaceCommit() { | 277 void ShellSurface::OnSurfaceCommit() { |
280 surface_->CommitSurfaceHierarchy(); | 278 surface_->CommitSurfaceHierarchy(); |
281 | 279 |
282 if (enabled() && !widget_) | 280 if (enabled() && !widget_) |
283 CreateShellSurfaceWidget(); | 281 CreateShellSurfaceWidget(); |
284 | 282 |
285 if (widget_) { | 283 if (widget_) { |
286 // Update surface bounds and widget size. | 284 // Update surface bounds and widget size. |
287 gfx::Point origin; | 285 gfx::Rect visible_bounds = GetVisibleBounds(); |
288 views::View::ConvertPointToWidget(this, &origin); | 286 surface_->SetBounds( |
289 // Use |geometry_| if set, otherwise use the visual bounds of the surface. | 287 gfx::Rect(gfx::Point() - visible_bounds.OffsetFromOrigin(), |
290 gfx::Rect geometry = | 288 surface_->layer()->size())); |
291 geometry_.IsEmpty() ? surface_->GetVisibleBounds() : geometry_; | 289 widget_->SetSize(visible_bounds.size()); |
292 surface_->SetBounds(gfx::Rect(origin - geometry.OffsetFromOrigin(), | |
293 surface_->layer()->size())); | |
294 widget_->SetSize(geometry.size()); | |
295 | 290 |
296 // Show widget if not already visible. | 291 // Show widget if not already visible. |
297 if (!widget_->IsClosed() && !widget_->IsVisible()) | 292 if (!widget_->IsClosed() && !widget_->IsVisible()) |
298 widget_->Show(); | 293 widget_->Show(); |
299 } | 294 } |
300 } | 295 } |
301 | 296 |
302 bool ShellSurface::IsSurfaceSynchronized() const { | 297 bool ShellSurface::IsSurfaceSynchronized() const { |
303 // A shell surface is always desynchronized. | 298 // A shell surface is always desynchronized. |
304 return false; | 299 return false; |
(...skipping 20 matching lines...) Expand all Loading... |
325 surface_destroyed_callback_.Run(); | 320 surface_destroyed_callback_.Run(); |
326 } | 321 } |
327 | 322 |
328 //////////////////////////////////////////////////////////////////////////////// | 323 //////////////////////////////////////////////////////////////////////////////// |
329 // views::WidgetDelegate overrides: | 324 // views::WidgetDelegate overrides: |
330 | 325 |
331 base::string16 ShellSurface::GetWindowTitle() const { | 326 base::string16 ShellSurface::GetWindowTitle() const { |
332 return title_; | 327 return title_; |
333 } | 328 } |
334 | 329 |
| 330 void ShellSurface::WindowClosing() { |
| 331 SetEnabled(false); |
| 332 widget_ = nullptr; |
| 333 } |
| 334 |
335 views::Widget* ShellSurface::GetWidget() { | 335 views::Widget* ShellSurface::GetWidget() { |
336 return widget_.get(); | 336 return widget_; |
337 } | 337 } |
338 | 338 |
339 const views::Widget* ShellSurface::GetWidget() const { | 339 const views::Widget* ShellSurface::GetWidget() const { |
340 return widget_.get(); | 340 return widget_; |
341 } | 341 } |
342 | 342 |
343 views::View* ShellSurface::GetContentsView() { | 343 views::View* ShellSurface::GetContentsView() { |
344 return this; | 344 return this; |
345 } | 345 } |
346 | 346 |
347 views::NonClientFrameView* ShellSurface::CreateNonClientFrameView( | 347 views::NonClientFrameView* ShellSurface::CreateNonClientFrameView( |
348 views::Widget* widget) { | 348 views::Widget* widget) { |
349 return new CustomFrameView(widget); | 349 return new CustomFrameView(widget); |
350 } | 350 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 SetEnabled(false); | 396 SetEnabled(false); |
397 } | 397 } |
398 | 398 |
399 //////////////////////////////////////////////////////////////////////////////// | 399 //////////////////////////////////////////////////////////////////////////////// |
400 // aura::client::ActivationChangeObserver overrides: | 400 // aura::client::ActivationChangeObserver overrides: |
401 | 401 |
402 void ShellSurface::OnWindowActivated( | 402 void ShellSurface::OnWindowActivated( |
403 aura::client::ActivationChangeObserver::ActivationReason reason, | 403 aura::client::ActivationChangeObserver::ActivationReason reason, |
404 aura::Window* gained_active, | 404 aura::Window* gained_active, |
405 aura::Window* lost_active) { | 405 aura::Window* lost_active) { |
| 406 DCHECK(activatable_); |
| 407 |
406 if (!widget_) | 408 if (!widget_) |
407 return; | 409 return; |
408 | 410 |
409 if (gained_active == widget_->GetNativeWindow() || | 411 if (gained_active == widget_->GetNativeWindow() || |
410 lost_active == widget_->GetNativeWindow()) { | 412 lost_active == widget_->GetNativeWindow()) { |
411 Configure(); | 413 Configure(); |
412 } | 414 } |
413 } | 415 } |
414 | 416 |
415 //////////////////////////////////////////////////////////////////////////////// | 417 //////////////////////////////////////////////////////////////////////////////// |
416 // ShellSurface, private: | 418 // ShellSurface, private: |
417 | 419 |
418 void ShellSurface::CreateShellSurfaceWidget() { | 420 void ShellSurface::CreateShellSurfaceWidget() { |
419 DCHECK(enabled()); | 421 DCHECK(enabled()); |
420 DCHECK(!widget_); | 422 DCHECK(!widget_); |
421 | 423 |
422 views::Widget::InitParams params; | 424 views::Widget::InitParams params; |
423 params.type = views::Widget::InitParams::TYPE_WINDOW; | 425 params.type = views::Widget::InitParams::TYPE_WINDOW; |
424 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 426 params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET; |
425 params.delegate = this; | 427 params.delegate = this; |
426 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; | 428 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; |
427 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 429 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
428 params.show_state = ui::SHOW_STATE_NORMAL; | 430 params.show_state = ui::SHOW_STATE_NORMAL; |
429 gfx::Point position(initial_bounds_.origin()); | 431 params.parent = ash::Shell::GetContainer( |
430 if (parent_) { | 432 ash::Shell::GetPrimaryRootWindow(), ash::kShellWindowId_DefaultContainer); |
431 params.child = true; | 433 if (!initial_bounds_.IsEmpty()) { |
432 params.parent = parent_; | 434 gfx::Point position(initial_bounds_.origin()); |
433 aura::Window::ConvertPointToTarget(GetMainSurface(parent_), parent_, | 435 if (parent_) { |
434 &position); | 436 aura::Window::ConvertPointToTarget(GetMainSurface(parent_), params.parent, |
435 } else { | 437 &position); |
436 params.parent = | 438 } |
437 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), | 439 params.bounds = gfx::Rect(position + GetVisibleBounds().OffsetFromOrigin(), |
438 ash::kShellWindowId_DefaultContainer); | 440 initial_bounds_.size()); |
439 } | 441 } |
440 params.bounds = gfx::Rect(position, initial_bounds_.size()); | 442 params.activatable = activatable_ ? views::Widget::InitParams::ACTIVATABLE_YES |
441 widget_.reset(new ShellSurfaceWidget(this)); | 443 : views::Widget::InitParams::ACTIVATABLE_NO; |
| 444 |
| 445 // Note: NativeWidget owns this widget. |
| 446 widget_ = new ShellSurfaceWidget(this); |
442 widget_->Init(params); | 447 widget_->Init(params); |
443 widget_->GetNativeWindow()->set_owned_by_parent(false); | |
444 widget_->GetNativeWindow()->SetName("ExoShellSurface"); | 448 widget_->GetNativeWindow()->SetName("ExoShellSurface"); |
445 widget_->GetNativeWindow()->AddChild(surface_); | 449 widget_->GetNativeWindow()->AddChild(surface_); |
446 widget_->GetNativeWindow()->SetEventTargeter( | 450 widget_->GetNativeWindow()->SetEventTargeter( |
447 make_scoped_ptr(new CustomWindowTargeter)); | 451 make_scoped_ptr(new CustomWindowTargeter)); |
448 SetApplicationId(widget_->GetNativeWindow(), &application_id_); | 452 SetApplicationId(widget_->GetNativeWindow(), &application_id_); |
449 SetMainSurface(widget_->GetNativeWindow(), surface_); | 453 SetMainSurface(widget_->GetNativeWindow(), surface_); |
450 | 454 |
451 // Start tracking window state changes. | 455 // Start tracking window state changes. |
452 ash::wm::GetWindowState(widget_->GetNativeWindow())->AddObserver(this); | 456 ash::wm::GetWindowState(widget_->GetNativeWindow())->AddObserver(this); |
453 | 457 |
454 // The position of a top-level shell surface is managed by Ash. | 458 // Make shell surface a transient child if |parent_| has been set. |
455 ash::wm::GetWindowState(widget_->GetNativeWindow()) | 459 if (parent_) |
456 ->set_window_position_managed(true); | 460 wm::AddTransientChild(parent_, widget_->GetNativeWindow()); |
| 461 |
| 462 // Ash manages the position of a top-level shell surfaces unless |
| 463 // |initial_bounds_| has been set. |
| 464 if (initial_bounds_.IsEmpty()) { |
| 465 ash::wm::GetWindowState(widget_->GetNativeWindow()) |
| 466 ->set_window_position_managed(true); |
| 467 } |
457 } | 468 } |
458 | 469 |
459 void ShellSurface::Configure() { | 470 void ShellSurface::Configure() { |
460 DCHECK(widget_); | 471 DCHECK(widget_); |
461 | 472 |
462 if (configure_callback_.is_null()) | 473 if (configure_callback_.is_null()) |
463 return; | 474 return; |
464 | 475 |
465 configure_callback_.Run( | 476 configure_callback_.Run( |
466 widget_->GetWindowBoundsInScreen().size(), | 477 widget_->GetWindowBoundsInScreen().size(), |
467 ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), | 478 ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), |
468 widget_->IsActive()); | 479 widget_->IsActive()); |
469 } | 480 } |
470 | 481 |
| 482 gfx::Rect ShellSurface::GetVisibleBounds() const { |
| 483 // Use |geometry_| if set, otherwise use the visual bounds of the surface. |
| 484 return geometry_.IsEmpty() ? surface_->GetVisibleBounds() : geometry_; |
| 485 } |
| 486 |
471 } // namespace exo | 487 } // namespace exo |
OLD | NEW |