OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/wm/shelf_layout_manager.h" | 5 #include "ash/wm/shelf_layout_manager.h" |
6 | 6 |
7 #include "ash/launcher/launcher.h" | 7 #include "ash/launcher/launcher.h" |
8 #include "ash/screen_ash.h" | 8 #include "ash/screen_ash.h" |
9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
10 #include "ash/shell_delegate.h" | 10 #include "ash/shell_delegate.h" |
(...skipping 30 matching lines...) Expand all Loading... |
41 aura::Window* window = widget->GetNativeView(); | 41 aura::Window* window = widget->GetNativeView(); |
42 window->layer()->SetBounds(aura::ConvertRectToPixel(window, bounds)); | 42 window->layer()->SetBounds(aura::ConvertRectToPixel(window, bounds)); |
43 } | 43 } |
44 | 44 |
45 } // namespace | 45 } // namespace |
46 | 46 |
47 // static | 47 // static |
48 const int ShelfLayoutManager::kWorkspaceAreaBottomInset = 2; | 48 const int ShelfLayoutManager::kWorkspaceAreaBottomInset = 2; |
49 | 49 |
50 // static | 50 // static |
51 const int ShelfLayoutManager::kAutoHideHeight = 2; | 51 const int ShelfLayoutManager::kAutoHideSize = 2; |
52 | 52 |
53 // Notifies ShelfLayoutManager any time the mouse moves. | 53 // Notifies ShelfLayoutManager any time the mouse moves. |
54 class ShelfLayoutManager::AutoHideEventFilter : public aura::EventFilter { | 54 class ShelfLayoutManager::AutoHideEventFilter : public aura::EventFilter { |
55 public: | 55 public: |
56 explicit AutoHideEventFilter(ShelfLayoutManager* shelf); | 56 explicit AutoHideEventFilter(ShelfLayoutManager* shelf); |
57 virtual ~AutoHideEventFilter(); | 57 virtual ~AutoHideEventFilter(); |
58 | 58 |
59 // Returns true if the last mouse event was a mouse drag. | 59 // Returns true if the last mouse event was a mouse drag. |
60 bool in_mouse_drag() const { return in_mouse_drag_; } | 60 bool in_mouse_drag() const { return in_mouse_drag_; } |
61 | 61 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 return ui::GESTURE_STATUS_UNKNOWN; // Not handled. | 121 return ui::GESTURE_STATUS_UNKNOWN; // Not handled. |
122 } | 122 } |
123 | 123 |
124 //////////////////////////////////////////////////////////////////////////////// | 124 //////////////////////////////////////////////////////////////////////////////// |
125 // ShelfLayoutManager, public: | 125 // ShelfLayoutManager, public: |
126 | 126 |
127 ShelfLayoutManager::ShelfLayoutManager(views::Widget* status) | 127 ShelfLayoutManager::ShelfLayoutManager(views::Widget* status) |
128 : root_window_(Shell::GetInstance()->GetRootWindow()), | 128 : root_window_(Shell::GetInstance()->GetRootWindow()), |
129 in_layout_(false), | 129 in_layout_(false), |
130 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT), | 130 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT), |
131 shelf_height_(status->GetWindowScreenBounds().height()), | 131 alignment_(SHELF_ALIGNMENT_BOTTOM), |
132 launcher_(NULL), | 132 launcher_(NULL), |
133 status_(status), | 133 status_(status), |
134 workspace_manager_(NULL), | 134 workspace_manager_(NULL), |
135 window_overlaps_shelf_(false) { | 135 window_overlaps_shelf_(false) { |
136 root_window_->AddObserver(this); | 136 root_window_->AddObserver(this); |
137 } | 137 } |
138 | 138 |
139 ShelfLayoutManager::~ShelfLayoutManager() { | 139 ShelfLayoutManager::~ShelfLayoutManager() { |
140 root_window_->RemoveObserver(this); | 140 root_window_->RemoveObserver(this); |
141 } | 141 } |
142 | 142 |
143 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) { | 143 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) { |
144 if (auto_hide_behavior_ == behavior) | 144 if (auto_hide_behavior_ == behavior) |
145 return; | 145 return; |
146 auto_hide_behavior_ = behavior; | 146 auto_hide_behavior_ = behavior; |
147 UpdateVisibilityState(); | 147 UpdateVisibilityState(); |
148 } | 148 } |
149 | 149 |
150 bool ShelfLayoutManager::IsVisible() const { | 150 bool ShelfLayoutManager::IsVisible() const { |
151 return status_->IsVisible() && (state_.visibility_state == VISIBLE || | 151 return status_->IsVisible() && (state_.visibility_state == VISIBLE || |
152 (state_.visibility_state == AUTO_HIDE && | 152 (state_.visibility_state == AUTO_HIDE && |
153 state_.auto_hide_state == AUTO_HIDE_SHOWN)); | 153 state_.auto_hide_state == AUTO_HIDE_SHOWN)); |
154 } | 154 } |
155 | 155 |
156 gfx::Rect ShelfLayoutManager::GetMaximizedWindowBounds( | 156 gfx::Rect ShelfLayoutManager::GetMaximizedWindowBounds( |
157 aura::Window* window) const { | 157 aura::Window* window) { |
158 // TODO: needs to be multi-mon aware. | 158 // TODO: needs to be multi-mon aware. |
159 gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds()); | 159 gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds()); |
160 if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT || | 160 if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT || |
161 auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) { | 161 auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) { |
162 bounds.set_height(bounds.height() - kAutoHideHeight); | 162 AdjustBoundsBasedOnAlignment(kAutoHideSize, &bounds); |
163 return bounds; | 163 return bounds; |
164 } | 164 } |
165 // SHELF_AUTO_HIDE_BEHAVIOR_NEVER maximized windows don't get any taller. | 165 // SHELF_AUTO_HIDE_BEHAVIOR_NEVER maximized windows don't get any taller. |
166 return GetUnmaximizedWorkAreaBounds(window); | 166 return GetUnmaximizedWorkAreaBounds(window); |
167 } | 167 } |
168 | 168 |
169 gfx::Rect ShelfLayoutManager::GetUnmaximizedWorkAreaBounds( | 169 gfx::Rect ShelfLayoutManager::GetUnmaximizedWorkAreaBounds( |
170 aura::Window* window) const { | 170 aura::Window* window) { |
171 // TODO: needs to be multi-mon aware. | 171 // TODO: needs to be multi-mon aware. |
172 gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds()); | 172 gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds()); |
173 if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) | 173 int size; |
174 bounds.set_height(bounds.height() - kAutoHideHeight); | 174 if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) { |
175 else | 175 size = kAutoHideSize; |
176 bounds.set_height(bounds.height() - shelf_height_); | 176 } else { |
| 177 int width, height; |
| 178 GetShelfSize(&width, &height); |
| 179 size = std::max(width, height); |
| 180 } |
| 181 AdjustBoundsBasedOnAlignment(size, &bounds); |
177 return bounds; | 182 return bounds; |
178 } | 183 } |
179 | 184 |
180 void ShelfLayoutManager::SetLauncher(Launcher* launcher) { | 185 void ShelfLayoutManager::SetLauncher(Launcher* launcher) { |
181 if (launcher == launcher_) | 186 if (launcher == launcher_) |
182 return; | 187 return; |
183 | 188 |
184 launcher_ = launcher; | 189 launcher_ = launcher; |
185 shelf_height_ = | |
186 std::max(status_->GetWindowScreenBounds().height(), | |
187 launcher_widget()->GetWindowScreenBounds().height()); | |
188 LayoutShelf(); | 190 LayoutShelf(); |
189 } | 191 } |
190 | 192 |
| 193 void ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) { |
| 194 if (alignment_ == alignment) |
| 195 return; |
| 196 |
| 197 alignment_ = alignment; |
| 198 if (launcher_) |
| 199 launcher_->SetAlignment(alignment); |
| 200 LayoutShelf(); |
| 201 } |
| 202 |
| 203 gfx::Rect ShelfLayoutManager::GetIdealBounds() { |
| 204 // TODO: this is wrong. Figure out what monitor shelf is on and everything |
| 205 // should be based on it. |
| 206 gfx::Rect bounds( |
| 207 gfx::Screen::GetMonitorNearestWindow(status_->GetNativeView()).bounds()); |
| 208 int width = 0, height = 0; |
| 209 GetShelfSize(&width, &height); |
| 210 switch (alignment_) { |
| 211 case SHELF_ALIGNMENT_BOTTOM: |
| 212 return gfx::Rect(bounds.x(), bounds.bottom() - height, |
| 213 bounds.width(), height); |
| 214 case SHELF_ALIGNMENT_LEFT: |
| 215 return gfx::Rect(bounds.x(), bounds.y(), width, bounds.height()); |
| 216 case SHELF_ALIGNMENT_RIGHT: |
| 217 return gfx::Rect(bounds.right() - width, bounds.bottom() - height, width, |
| 218 height); |
| 219 } |
| 220 NOTREACHED(); |
| 221 return gfx::Rect(); |
| 222 } |
| 223 |
191 void ShelfLayoutManager::LayoutShelf() { | 224 void ShelfLayoutManager::LayoutShelf() { |
192 AutoReset<bool> auto_reset_in_layout(&in_layout_, true); | 225 AutoReset<bool> auto_reset_in_layout(&in_layout_, true); |
193 StopAnimating(); | 226 StopAnimating(); |
194 TargetBounds target_bounds; | 227 TargetBounds target_bounds; |
195 CalculateTargetBounds(state_, &target_bounds); | 228 CalculateTargetBounds(state_, &target_bounds); |
196 if (launcher_widget()) { | 229 if (launcher_widget()) { |
197 GetLayer(launcher_widget())->SetOpacity(target_bounds.opacity); | 230 GetLayer(launcher_widget())->SetOpacity(target_bounds.opacity); |
198 launcher_widget()->SetBounds(target_bounds.launcher_bounds); | 231 launcher_widget()->SetBounds(target_bounds.launcher_bounds); |
199 launcher_->SetStatusWidth( | 232 launcher_->SetStatusSize(target_bounds.status_bounds.size()); |
200 target_bounds.status_bounds.width()); | |
201 } | 233 } |
202 GetLayer(status_)->SetOpacity(target_bounds.opacity); | 234 GetLayer(status_)->SetOpacity(target_bounds.opacity); |
203 status_->SetBounds(target_bounds.status_bounds); | 235 status_->SetBounds(target_bounds.status_bounds); |
204 Shell::GetInstance()->SetMonitorWorkAreaInsets( | 236 Shell::GetInstance()->SetMonitorWorkAreaInsets( |
205 Shell::GetRootWindow(), | 237 Shell::GetRootWindow(), |
206 target_bounds.work_area_insets); | 238 target_bounds.work_area_insets); |
207 UpdateHitTestBounds(); | 239 UpdateHitTestBounds(); |
208 } | 240 } |
209 | 241 |
210 void ShelfLayoutManager::UpdateVisibilityState() { | 242 void ShelfLayoutManager::UpdateVisibilityState() { |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 UpdateHitTestBounds(); | 382 UpdateHitTestBounds(); |
351 UpdateShelfBackground(change_type); | 383 UpdateShelfBackground(change_type); |
352 } | 384 } |
353 | 385 |
354 void ShelfLayoutManager::StopAnimating() { | 386 void ShelfLayoutManager::StopAnimating() { |
355 if (launcher_widget()) | 387 if (launcher_widget()) |
356 GetLayer(launcher_widget())->GetAnimator()->StopAnimating(); | 388 GetLayer(launcher_widget())->GetAnimator()->StopAnimating(); |
357 GetLayer(status_)->GetAnimator()->StopAnimating(); | 389 GetLayer(status_)->GetAnimator()->StopAnimating(); |
358 } | 390 } |
359 | 391 |
| 392 void ShelfLayoutManager::GetShelfSize(int* width, int* height) { |
| 393 *width = *height = 0; |
| 394 gfx::Rect status_bounds(status_->GetWindowScreenBounds()); |
| 395 gfx::Size launcher_size = launcher_ ? |
| 396 launcher_widget()->GetContentsView()->GetPreferredSize() : gfx::Size(); |
| 397 if (alignment_ == SHELF_ALIGNMENT_BOTTOM) { |
| 398 *height = std::max(launcher_size.height(), status_bounds.height()); |
| 399 } else { |
| 400 // TODO: include status when supports alignment. |
| 401 *width = launcher_size.width(); |
| 402 } |
| 403 } |
| 404 |
| 405 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset, |
| 406 gfx::Rect* bounds) const { |
| 407 switch (alignment_) { |
| 408 case SHELF_ALIGNMENT_BOTTOM: |
| 409 bounds->Inset(gfx::Insets(0, 0, inset, 0)); |
| 410 break; |
| 411 case SHELF_ALIGNMENT_LEFT: |
| 412 bounds->Inset(gfx::Insets(0, inset, 0, 0)); |
| 413 break; |
| 414 case SHELF_ALIGNMENT_RIGHT: |
| 415 bounds->Inset(gfx::Insets(0, 0, 0, inset)); |
| 416 break; |
| 417 } |
| 418 } |
| 419 |
360 void ShelfLayoutManager::CalculateTargetBounds( | 420 void ShelfLayoutManager::CalculateTargetBounds( |
361 const State& state, | 421 const State& state, |
362 TargetBounds* target_bounds) const { | 422 TargetBounds* target_bounds) { |
363 const gfx::Rect& available_bounds( | 423 const gfx::Rect& available_bounds( |
364 status_->GetNativeView()->GetRootWindow()->bounds()); | 424 status_->GetNativeView()->GetRootWindow()->bounds()); |
365 int y = available_bounds.bottom(); | 425 gfx::Rect status_bounds(status_->GetWindowScreenBounds()); |
366 int shelf_height = 0; | 426 gfx::Size launcher_size = launcher_ ? |
| 427 launcher_widget()->GetContentsView()->GetPreferredSize() : gfx::Size(); |
| 428 int shelf_size = 0; |
| 429 int shelf_width = 0, shelf_height = 0; |
| 430 GetShelfSize(&shelf_width, &shelf_height); |
367 if (state.visibility_state == VISIBLE || | 431 if (state.visibility_state == VISIBLE || |
368 (state.visibility_state == AUTO_HIDE && | 432 (state.visibility_state == AUTO_HIDE && |
369 state.auto_hide_state == AUTO_HIDE_SHOWN)) | 433 state.auto_hide_state == AUTO_HIDE_SHOWN)) { |
370 shelf_height = shelf_height_; | 434 shelf_size = std::max(shelf_width, shelf_height); |
371 else if (state.visibility_state == AUTO_HIDE && | 435 } else if (state.visibility_state == AUTO_HIDE && |
372 state.auto_hide_state == AUTO_HIDE_HIDDEN) | 436 state.auto_hide_state == AUTO_HIDE_HIDDEN) { |
373 shelf_height = kAutoHideHeight; | 437 shelf_size = kAutoHideSize; |
374 y -= shelf_height; | |
375 gfx::Rect status_bounds(status_->GetWindowScreenBounds()); | |
376 // The status widget should extend to the bottom and right edges. | |
377 target_bounds->status_bounds = gfx::Rect( | |
378 base::i18n::IsRTL() ? available_bounds.x() : | |
379 available_bounds.right() - status_bounds.width(), | |
380 y + shelf_height_ - status_bounds.height(), | |
381 status_bounds.width(), status_bounds.height()); | |
382 if (launcher_widget()) { | |
383 gfx::Rect launcher_bounds(launcher_widget()->GetWindowScreenBounds()); | |
384 target_bounds->launcher_bounds = gfx::Rect( | |
385 available_bounds.x(), | |
386 y + (shelf_height_ - launcher_bounds.height()) / 2, | |
387 available_bounds.width(), | |
388 launcher_bounds.height()); | |
389 } | 438 } |
390 | 439 if (alignment_ == SHELF_ALIGNMENT_BOTTOM) { |
| 440 int y = available_bounds.bottom(); |
| 441 y -= shelf_size; |
| 442 // The status widget should extend to the bottom and right edges. |
| 443 target_bounds->status_bounds = gfx::Rect( |
| 444 base::i18n::IsRTL() ? available_bounds.x() : |
| 445 available_bounds.right() - status_bounds.width(), |
| 446 y + shelf_height - status_bounds.height(), |
| 447 status_bounds.width(), status_bounds.height()); |
| 448 if (launcher_widget()) { |
| 449 target_bounds->launcher_bounds = gfx::Rect( |
| 450 available_bounds.x(), |
| 451 y + (shelf_height - launcher_size.height()) / 2, |
| 452 available_bounds.width(), |
| 453 launcher_size.height()); |
| 454 } |
| 455 target_bounds->work_area_insets.Set( |
| 456 0, 0, GetWorkAreaSize(state, shelf_height), 0); |
| 457 } else { |
| 458 int x = (alignment_ == SHELF_ALIGNMENT_LEFT) ? |
| 459 available_bounds.x() + shelf_size - shelf_width : |
| 460 available_bounds.right() - shelf_size; |
| 461 target_bounds->status_bounds = gfx::Rect( |
| 462 x, available_bounds.bottom() - status_bounds.height(), |
| 463 shelf_width, status_bounds.height()); |
| 464 if (launcher_widget()) { |
| 465 target_bounds->launcher_bounds = gfx::Rect( |
| 466 x, |
| 467 available_bounds.y(), |
| 468 launcher_size.width(), |
| 469 available_bounds.height()); |
| 470 } |
| 471 if (alignment_ == SHELF_ALIGNMENT_LEFT) { |
| 472 target_bounds->work_area_insets.Set( |
| 473 0, GetWorkAreaSize(state, shelf_width), 0, 0); |
| 474 } else { |
| 475 target_bounds->work_area_insets.Set( |
| 476 0, 0, 0, GetWorkAreaSize(state, shelf_width)); |
| 477 } |
| 478 } |
391 target_bounds->opacity = | 479 target_bounds->opacity = |
392 (state.visibility_state == VISIBLE || | 480 (state.visibility_state == VISIBLE || |
393 state.visibility_state == AUTO_HIDE) ? 1.0f : 0.0f; | 481 state.visibility_state == AUTO_HIDE) ? 1.0f : 0.0f; |
394 | |
395 int work_area_bottom = 0; | |
396 if (state.visibility_state == VISIBLE) | |
397 work_area_bottom = shelf_height_; | |
398 else if (state.visibility_state == AUTO_HIDE) | |
399 work_area_bottom = kAutoHideHeight; | |
400 target_bounds->work_area_insets.Set(0, 0, work_area_bottom, 0); | |
401 } | 482 } |
402 | 483 |
403 void ShelfLayoutManager::UpdateShelfBackground( | 484 void ShelfLayoutManager::UpdateShelfBackground( |
404 BackgroundAnimator::ChangeType type) { | 485 BackgroundAnimator::ChangeType type) { |
405 bool launcher_paints = GetLauncherPaintsBackground(); | 486 bool launcher_paints = GetLauncherPaintsBackground(); |
406 if (launcher_) | 487 if (launcher_) |
407 launcher_->SetPaintsBackground(launcher_paints, type); | 488 launcher_->SetPaintsBackground(launcher_paints, type); |
408 // SystemTray normally draws a background, but we don't want it to draw a | 489 // SystemTray normally draws a background, but we don't want it to draw a |
409 // background when the launcher does. | 490 // background when the launcher does. |
410 if (Shell::GetInstance()->tray()) | 491 if (Shell::GetInstance()->tray()) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 return mouse_over_launcher ? AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN; | 530 return mouse_over_launcher ? AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN; |
450 } | 531 } |
451 | 532 |
452 void ShelfLayoutManager::UpdateHitTestBounds() { | 533 void ShelfLayoutManager::UpdateHitTestBounds() { |
453 gfx::Insets insets; | 534 gfx::Insets insets; |
454 // Only modify the hit test when the shelf is visible, so we don't mess with | 535 // Only modify the hit test when the shelf is visible, so we don't mess with |
455 // hover hit testing in the auto-hide state. | 536 // hover hit testing in the auto-hide state. |
456 if (state_.visibility_state == VISIBLE) { | 537 if (state_.visibility_state == VISIBLE) { |
457 // Let clicks at the very top of the launcher through so windows can be | 538 // Let clicks at the very top of the launcher through so windows can be |
458 // resized with the bottom-right corner and bottom edge. | 539 // resized with the bottom-right corner and bottom edge. |
459 insets.Set(kWorkspaceAreaBottomInset, 0, 0, 0); | 540 switch (alignment_) { |
| 541 case SHELF_ALIGNMENT_BOTTOM: |
| 542 insets.Set(kWorkspaceAreaBottomInset, 0, 0, 0); |
| 543 break; |
| 544 case SHELF_ALIGNMENT_LEFT: |
| 545 insets.Set(0, 0, 0, kWorkspaceAreaBottomInset); |
| 546 break; |
| 547 case SHELF_ALIGNMENT_RIGHT: |
| 548 insets.Set(0, kWorkspaceAreaBottomInset, 0, 0); |
| 549 break; |
| 550 } |
460 } | 551 } |
461 if (launcher_widget() && launcher_widget()->GetNativeWindow()) | 552 if (launcher_widget() && launcher_widget()->GetNativeWindow()) |
462 launcher_widget()->GetNativeWindow()->set_hit_test_bounds_override_outer( | 553 launcher_widget()->GetNativeWindow()->set_hit_test_bounds_override_outer( |
463 insets); | 554 insets); |
464 status_->GetNativeWindow()->set_hit_test_bounds_override_outer(insets); | 555 status_->GetNativeWindow()->set_hit_test_bounds_override_outer(insets); |
465 } | 556 } |
466 | 557 |
467 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) { | 558 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) { |
468 if (!window) | 559 if (!window) |
469 return false; | 560 return false; |
470 return (launcher_widget() && | 561 return (launcher_widget() && |
471 launcher_widget()->GetNativeWindow()->Contains(window)) || | 562 launcher_widget()->GetNativeWindow()->Contains(window)) || |
472 (status_ && status_->GetNativeWindow()->Contains(window)); | 563 (status_ && status_->GetNativeWindow()->Contains(window)); |
473 } | 564 } |
474 | 565 |
| 566 int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const { |
| 567 if (state.visibility_state == VISIBLE) |
| 568 return size; |
| 569 if (state.visibility_state == AUTO_HIDE) |
| 570 return kAutoHideSize; |
| 571 return 0; |
| 572 } |
| 573 |
475 } // namespace internal | 574 } // namespace internal |
476 } // namespace ash | 575 } // namespace ash |
OLD | NEW |