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/shell.h" | 5 #include "ash/shell.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "ash/app_list/app_list.h" | 9 #include "ash/app_list/app_list.h" |
10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
11 #include "ash/drag_drop/drag_drop_controller.h" | 11 #include "ash/drag_drop/drag_drop_controller.h" |
12 #include "ash/focus_cycler.h" | 12 #include "ash/focus_cycler.h" |
13 #include "ash/ime/input_method_event_filter.h" | 13 #include "ash/ime/input_method_event_filter.h" |
14 #include "ash/launcher/launcher.h" | 14 #include "ash/launcher/launcher.h" |
15 #include "ash/shell_delegate.h" | 15 #include "ash/shell_delegate.h" |
16 #include "ash/shell_factory.h" | 16 #include "ash/shell_factory.h" |
17 #include "ash/shell_window_ids.h" | 17 #include "ash/shell_window_ids.h" |
18 #include "ash/system/audio/tray_volume.h" | 18 #include "ash/system/audio/tray_volume.h" |
19 #include "ash/system/brightness/tray_brightness.h" | 19 #include "ash/system/brightness/tray_brightness.h" |
20 #include "ash/system/settings/tray_settings.h" | 20 #include "ash/system/settings/tray_settings.h" |
21 #include "ash/system/power/power_status_controller.h" | 21 #include "ash/system/power/power_status_controller.h" |
22 #include "ash/system/power/tray_power_date.h" | 22 #include "ash/system/power/tray_power_date.h" |
23 #include "ash/system/tray/system_tray_delegate.h" | 23 #include "ash/system/tray/system_tray_delegate.h" |
24 #include "ash/system/tray/system_tray.h" | 24 #include "ash/system/tray/system_tray.h" |
25 #include "ash/system/tray/tray_empty.h" | 25 #include "ash/system/tray/tray_empty.h" |
26 #include "ash/system/user/tray_user.h" | 26 #include "ash/system/user/tray_user.h" |
27 #include "ash/tooltips/tooltip_controller.h" | 27 #include "ash/tooltips/tooltip_controller.h" |
28 #include "ash/wm/activation_controller.h" | 28 #include "ash/wm/activation_controller.h" |
29 #include "ash/wm/base_layout_manager.h" | 29 #include "ash/wm/base_layout_manager.h" |
30 #include "ash/wm/compact_layout_manager.h" | |
31 #include "ash/wm/compact_status_area_layout_manager.h" | |
32 #include "ash/wm/custom_frame_view_ash.h" | 30 #include "ash/wm/custom_frame_view_ash.h" |
33 #include "ash/wm/dialog_frame_view.h" | 31 #include "ash/wm/dialog_frame_view.h" |
34 #include "ash/wm/panel_window_event_filter.h" | 32 #include "ash/wm/panel_window_event_filter.h" |
35 #include "ash/wm/panel_layout_manager.h" | 33 #include "ash/wm/panel_layout_manager.h" |
36 #include "ash/wm/partial_screenshot_event_filter.h" | 34 #include "ash/wm/partial_screenshot_event_filter.h" |
37 #include "ash/wm/power_button_controller.h" | 35 #include "ash/wm/power_button_controller.h" |
38 #include "ash/wm/root_window_event_filter.h" | 36 #include "ash/wm/root_window_event_filter.h" |
39 #include "ash/wm/root_window_layout_manager.h" | 37 #include "ash/wm/root_window_layout_manager.h" |
40 #include "ash/wm/shadow_controller.h" | 38 #include "ash/wm/shadow_controller.h" |
41 #include "ash/wm/shelf_layout_manager.h" | 39 #include "ash/wm/shelf_layout_manager.h" |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 // static | 250 // static |
253 Shell* Shell::instance_ = NULL; | 251 Shell* Shell::instance_ = NULL; |
254 // static | 252 // static |
255 bool Shell::initially_hide_cursor_ = false; | 253 bool Shell::initially_hide_cursor_ = false; |
256 | 254 |
257 //////////////////////////////////////////////////////////////////////////////// | 255 //////////////////////////////////////////////////////////////////////////////// |
258 // Shell::TestApi | 256 // Shell::TestApi |
259 | 257 |
260 Shell::TestApi::TestApi(Shell* shell) : shell_(shell) {} | 258 Shell::TestApi::TestApi(Shell* shell) : shell_(shell) {} |
261 | 259 |
262 Shell::WindowMode Shell::TestApi::ComputeWindowMode(CommandLine* cmd) const { | |
263 return shell_->ComputeWindowMode(cmd); | |
264 } | |
265 | |
266 internal::RootWindowLayoutManager* Shell::TestApi::root_window_layout() { | 260 internal::RootWindowLayoutManager* Shell::TestApi::root_window_layout() { |
267 return shell_->root_window_layout_; | 261 return shell_->root_window_layout_; |
268 } | 262 } |
269 | 263 |
270 internal::InputMethodEventFilter* Shell::TestApi::input_method_event_filter() { | 264 internal::InputMethodEventFilter* Shell::TestApi::input_method_event_filter() { |
271 return shell_->input_method_filter_.get(); | 265 return shell_->input_method_filter_.get(); |
272 } | 266 } |
273 | 267 |
274 internal::WorkspaceController* Shell::TestApi::workspace_controller() { | 268 internal::WorkspaceController* Shell::TestApi::workspace_controller() { |
275 return shell_->workspace_controller_.get(); | 269 return shell_->workspace_controller_.get(); |
276 } | 270 } |
277 | 271 |
278 //////////////////////////////////////////////////////////////////////////////// | 272 //////////////////////////////////////////////////////////////////////////////// |
279 // Shell, public: | 273 // Shell, public: |
280 | 274 |
281 Shell::Shell(ShellDelegate* delegate) | 275 Shell::Shell(ShellDelegate* delegate) |
282 : root_window_(new aura::RootWindow), | 276 : root_window_(new aura::RootWindow), |
| 277 root_filter_(NULL), |
283 delegate_(delegate), | 278 delegate_(delegate), |
284 audio_controller_(NULL), | 279 audio_controller_(NULL), |
285 brightness_controller_(NULL), | 280 brightness_controller_(NULL), |
| 281 power_status_controller_(NULL), |
286 shelf_(NULL), | 282 shelf_(NULL), |
287 window_mode_(MODE_MANAGED), | |
288 desktop_background_mode_(BACKGROUND_IMAGE), | 283 desktop_background_mode_(BACKGROUND_IMAGE), |
289 root_window_layout_(NULL), | 284 root_window_layout_(NULL), |
290 status_widget_(NULL) { | 285 status_widget_(NULL) { |
291 } | 286 } |
292 | 287 |
293 Shell::~Shell() { | 288 Shell::~Shell() { |
294 RemoveRootWindowEventFilter(partial_screenshot_filter_.get()); | 289 RemoveRootWindowEventFilter(partial_screenshot_filter_.get()); |
295 RemoveRootWindowEventFilter(input_method_filter_.get()); | 290 RemoveRootWindowEventFilter(input_method_filter_.get()); |
296 RemoveRootWindowEventFilter(window_modality_controller_.get()); | 291 RemoveRootWindowEventFilter(window_modality_controller_.get()); |
297 #if !defined(OS_MACOSX) | 292 #if !defined(OS_MACOSX) |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 // order) since they have the second highest priority. | 385 // order) since they have the second highest priority. |
391 DCHECK_EQ(1U, GetRootWindowEventFilterCount()); | 386 DCHECK_EQ(1U, GetRootWindowEventFilterCount()); |
392 #if !defined(OS_MACOSX) | 387 #if !defined(OS_MACOSX) |
393 accelerator_filter_.reset(new internal::AcceleratorFilter); | 388 accelerator_filter_.reset(new internal::AcceleratorFilter); |
394 AddRootWindowEventFilter(accelerator_filter_.get()); | 389 AddRootWindowEventFilter(accelerator_filter_.get()); |
395 DCHECK_EQ(2U, GetRootWindowEventFilterCount()); | 390 DCHECK_EQ(2U, GetRootWindowEventFilterCount()); |
396 #endif | 391 #endif |
397 input_method_filter_.reset(new internal::InputMethodEventFilter); | 392 input_method_filter_.reset(new internal::InputMethodEventFilter); |
398 AddRootWindowEventFilter(input_method_filter_.get()); | 393 AddRootWindowEventFilter(input_method_filter_.get()); |
399 | 394 |
400 // Window mode must be set before computing containers or layout managers. | |
401 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
402 if (!delegate_.get() || !delegate_->GetOverrideWindowMode(&window_mode_)) | |
403 window_mode_ = ComputeWindowMode(command_line); | |
404 | |
405 aura::RootWindow* root_window = GetRootWindow(); | 395 aura::RootWindow* root_window = GetRootWindow(); |
406 root_window->SetCursor(aura::kCursorPointer); | 396 root_window->SetCursor(aura::kCursorPointer); |
407 if (initially_hide_cursor_) | 397 if (initially_hide_cursor_) |
408 root_window->ShowCursor(false); | 398 root_window->ShowCursor(false); |
409 | 399 |
410 activation_controller_.reset(new internal::ActivationController); | 400 activation_controller_.reset(new internal::ActivationController); |
411 | 401 |
412 CreateSpecialContainers(root_window); | 402 CreateSpecialContainers(root_window); |
413 | 403 |
414 stacking_controller_.reset(new internal::StackingController); | 404 stacking_controller_.reset(new internal::StackingController); |
415 | 405 |
416 root_window_layout_ = new internal::RootWindowLayoutManager(root_window); | 406 root_window_layout_ = new internal::RootWindowLayoutManager(root_window); |
417 root_window->SetLayoutManager(root_window_layout_); | 407 root_window->SetLayoutManager(root_window_layout_); |
418 | 408 |
419 if (delegate_.get()) | 409 if (delegate_.get()) |
420 status_widget_ = delegate_->CreateStatusArea(); | 410 status_widget_ = delegate_->CreateStatusArea(); |
421 | 411 |
| 412 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
422 if (command_line->HasSwitch(switches::kAshUberTray)) { | 413 if (command_line->HasSwitch(switches::kAshUberTray)) { |
423 // TODO(sad): This is rather ugly at the moment. This is because we are | 414 // TODO(sad): This is rather ugly at the moment. This is because we are |
424 // supporting both the old and the new status bar at the same time. This | 415 // supporting both the old and the new status bar at the same time. This |
425 // will soon get better once the new one is ready and the old one goes out | 416 // will soon get better once the new one is ready and the old one goes out |
426 // the door. | 417 // the door. |
427 tray_.reset(new SystemTray()); | 418 tray_.reset(new SystemTray()); |
428 if (status_widget_) { | 419 if (status_widget_) { |
429 status_widget_->GetContentsView()->RemoveAllChildViews(false); | 420 status_widget_->GetContentsView()->RemoveAllChildViews(false); |
430 status_widget_->GetContentsView()->AddChildView(tray_.get()); | 421 status_widget_->GetContentsView()->AddChildView(tray_.get()); |
431 } | 422 } |
(...skipping 17 matching lines...) Expand all Loading... |
449 tray_->AddTrayItem(tray_brightness); | 440 tray_->AddTrayItem(tray_brightness); |
450 tray_->AddTrayItem(new internal::TraySettings()); | 441 tray_->AddTrayItem(new internal::TraySettings()); |
451 } | 442 } |
452 if (!status_widget_) | 443 if (!status_widget_) |
453 status_widget_ = internal::CreateStatusArea(tray_.get()); | 444 status_widget_ = internal::CreateStatusArea(tray_.get()); |
454 | 445 |
455 aura::Window* default_container = | 446 aura::Window* default_container = |
456 GetContainer(internal::kShellWindowId_DefaultContainer); | 447 GetContainer(internal::kShellWindowId_DefaultContainer); |
457 launcher_.reset(new Launcher(default_container)); | 448 launcher_.reset(new Launcher(default_container)); |
458 | 449 |
459 if (window_mode_ == MODE_COMPACT) | 450 InitLayoutManagers(); |
460 SetupCompactWindowMode(); | |
461 else | |
462 SetupManagedWindowMode(); | |
463 | 451 |
464 if (!command_line->HasSwitch(switches::kAuraNoShadows)) | 452 if (!command_line->HasSwitch(switches::kAuraNoShadows)) |
465 shadow_controller_.reset(new internal::ShadowController()); | 453 shadow_controller_.reset(new internal::ShadowController()); |
466 | 454 |
467 focus_cycler_.reset(new internal::FocusCycler()); | 455 focus_cycler_.reset(new internal::FocusCycler()); |
468 focus_cycler_->AddWidget(status_widget_); | 456 focus_cycler_->AddWidget(status_widget_); |
469 focus_cycler_->AddWidget(launcher_->widget()); | 457 focus_cycler_->AddWidget(launcher_->widget()); |
470 launcher_->SetFocusCycler(focus_cycler_.get()); | 458 launcher_->SetFocusCycler(focus_cycler_.get()); |
471 | 459 |
472 // Force a layout. | 460 // Force a layout. |
473 root_window->layout_manager()->OnWindowResized(); | 461 root_window->layout_manager()->OnWindowResized(); |
474 | 462 |
475 window_modality_controller_.reset(new internal::WindowModalityController); | 463 window_modality_controller_.reset(new internal::WindowModalityController); |
476 AddRootWindowEventFilter(window_modality_controller_.get()); | 464 AddRootWindowEventFilter(window_modality_controller_.get()); |
477 | 465 |
478 visibility_controller_.reset(new internal::VisibilityController); | 466 visibility_controller_.reset(new internal::VisibilityController); |
479 | 467 |
480 tooltip_controller_.reset(new internal::TooltipController); | 468 tooltip_controller_.reset(new internal::TooltipController); |
481 AddRootWindowEventFilter(tooltip_controller_.get()); | 469 AddRootWindowEventFilter(tooltip_controller_.get()); |
482 | 470 |
483 drag_drop_controller_.reset(new internal::DragDropController); | 471 drag_drop_controller_.reset(new internal::DragDropController); |
484 power_button_controller_.reset(new PowerButtonController); | 472 power_button_controller_.reset(new PowerButtonController); |
485 video_detector_.reset(new VideoDetector); | 473 video_detector_.reset(new VideoDetector); |
486 window_cycle_controller_.reset(new WindowCycleController); | 474 window_cycle_controller_.reset(new WindowCycleController); |
487 } | 475 } |
488 | 476 |
489 Shell::WindowMode Shell::ComputeWindowMode(CommandLine* command_line) const { | |
490 // Some devices don't perform well with overlapping windows. | |
491 if (command_line->HasSwitch(switches::kAuraForceCompactWindowMode)) | |
492 return MODE_COMPACT; | |
493 | |
494 // If user set the flag, use their desired behavior. | |
495 if (command_line->HasSwitch(switches::kAuraWindowMode)) { | |
496 std::string mode = | |
497 command_line->GetSwitchValueASCII(switches::kAuraWindowMode); | |
498 if (mode == switches::kAuraWindowModeCompact) | |
499 return MODE_COMPACT; | |
500 if (mode == switches::kAuraWindowModeManaged) | |
501 return MODE_MANAGED; | |
502 } | |
503 | |
504 // Managed is the default. | |
505 return Shell::MODE_MANAGED; | |
506 } | |
507 | |
508 aura::Window* Shell::GetContainer(int container_id) { | 477 aura::Window* Shell::GetContainer(int container_id) { |
509 return const_cast<aura::Window*>( | 478 return const_cast<aura::Window*>( |
510 const_cast<const Shell*>(this)->GetContainer(container_id)); | 479 const_cast<const Shell*>(this)->GetContainer(container_id)); |
511 } | 480 } |
512 | 481 |
513 const aura::Window* Shell::GetContainer(int container_id) const { | 482 const aura::Window* Shell::GetContainer(int container_id) const { |
514 return GetRootWindow()->GetChildById(container_id); | 483 return GetRootWindow()->GetChildById(container_id); |
515 } | 484 } |
516 | 485 |
517 void Shell::AddRootWindowEventFilter(aura::EventFilter* filter) { | 486 void Shell::AddRootWindowEventFilter(aura::EventFilter* filter) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 internal::kShellWindowId_LockScreenContainer); | 536 internal::kShellWindowId_LockScreenContainer); |
568 return lock_screen_container->StopsEventPropagation(); | 537 return lock_screen_container->StopsEventPropagation(); |
569 } | 538 } |
570 | 539 |
571 bool Shell::IsModalWindowOpen() const { | 540 bool Shell::IsModalWindowOpen() const { |
572 const aura::Window* modal_container = GetContainer( | 541 const aura::Window* modal_container = GetContainer( |
573 internal::kShellWindowId_SystemModalContainer); | 542 internal::kShellWindowId_SystemModalContainer); |
574 return !modal_container->children().empty(); | 543 return !modal_container->children().empty(); |
575 } | 544 } |
576 | 545 |
577 void Shell::SetCompactStatusAreaOffset(gfx::Size& offset) { | |
578 compact_status_area_offset_ = offset; | |
579 | |
580 // Trigger a relayout. | |
581 if (IsWindowModeCompact()) { | |
582 aura::LayoutManager* layout_manager = GetContainer( | |
583 internal::kShellWindowId_StatusContainer)->layout_manager(); | |
584 if (layout_manager) | |
585 layout_manager->OnWindowResized(); | |
586 } | |
587 } | |
588 | |
589 views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView( | 546 views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView( |
590 views::Widget* widget) { | 547 views::Widget* widget) { |
591 if (CommandLine::ForCurrentProcess()->HasSwitch( | 548 if (CommandLine::ForCurrentProcess()->HasSwitch( |
592 switches::kAuraGoogleDialogFrames)) { | 549 switches::kAuraGoogleDialogFrames)) { |
593 return new internal::DialogFrameView; | 550 return new internal::DialogFrameView; |
594 } | 551 } |
595 // Normal non-compact-mode gets translucent-style window frames for dialogs. | 552 // Use translucent-style window frames for dialogs. |
596 if (!IsWindowModeCompact()) { | 553 internal::CustomFrameViewAsh* frame_view = new internal::CustomFrameViewAsh; |
597 internal::CustomFrameViewAsh* frame_view = new internal::CustomFrameViewAsh; | 554 frame_view->Init(widget); |
598 frame_view->Init(widget); | 555 return frame_view; |
599 return frame_view; | |
600 } | |
601 return NULL; | |
602 } | 556 } |
603 | 557 |
604 void Shell::RotateFocus(Direction direction) { | 558 void Shell::RotateFocus(Direction direction) { |
605 focus_cycler_->RotateFocus( | 559 focus_cycler_->RotateFocus( |
606 direction == FORWARD ? internal::FocusCycler::FORWARD : | 560 direction == FORWARD ? internal::FocusCycler::FORWARD : |
607 internal::FocusCycler::BACKWARD); | 561 internal::FocusCycler::BACKWARD); |
608 } | 562 } |
609 | 563 |
610 //////////////////////////////////////////////////////////////////////////////// | 564 //////////////////////////////////////////////////////////////////////////////// |
611 // Shell, private: | 565 // Shell, private: |
612 | 566 |
613 // Compact mode has a simplified layout manager and doesn't use the shelf, | 567 void Shell::InitLayoutManagers() { |
614 // desktop background, etc. The launcher still exists so we can use its | |
615 // data model and list of open windows, but we hide the UI to save space. | |
616 void Shell::SetupCompactWindowMode() { | |
617 DCHECK(root_window_layout_); | 568 DCHECK(root_window_layout_); |
618 DCHECK(status_widget_); | 569 DCHECK(status_widget_); |
619 | 570 |
620 // Don't use an event filter for the default container, as we don't support | |
621 // window dragging, double-click to maximize, etc. | |
622 aura::Window* default_container = | |
623 GetContainer(internal::kShellWindowId_DefaultContainer); | |
624 default_container->SetEventFilter(NULL); | |
625 | |
626 // Set up our new layout managers. | |
627 internal::CompactLayoutManager* compact_layout_manager = | |
628 new internal::CompactLayoutManager(); | |
629 compact_layout_manager->set_status_area_widget(status_widget_); | |
630 internal::CompactStatusAreaLayoutManager* status_area_layout_manager = | |
631 new internal::CompactStatusAreaLayoutManager(status_widget_); | |
632 GetContainer(internal::kShellWindowId_StatusContainer)-> | |
633 SetLayoutManager(status_area_layout_manager); | |
634 default_container->SetLayoutManager(compact_layout_manager); | |
635 | |
636 // Keep the launcher for its data model, but hide it. Do this before | |
637 // maximizing the windows so the work area is the right size. | |
638 launcher_->widget()->Hide(); | |
639 | |
640 // Set a solid black background. | |
641 SetDesktopBackgroundMode(BACKGROUND_SOLID_COLOR); | |
642 } | |
643 | |
644 void Shell::SetupManagedWindowMode() { | |
645 DCHECK(root_window_layout_); | |
646 DCHECK(status_widget_); | |
647 | |
648 internal::ShelfLayoutManager* shelf_layout_manager = | 571 internal::ShelfLayoutManager* shelf_layout_manager = |
649 new internal::ShelfLayoutManager(launcher_->widget(), status_widget_); | 572 new internal::ShelfLayoutManager(launcher_->widget(), status_widget_); |
650 GetContainer(internal::kShellWindowId_LauncherContainer)-> | 573 GetContainer(internal::kShellWindowId_LauncherContainer)-> |
651 SetLayoutManager(shelf_layout_manager); | 574 SetLayoutManager(shelf_layout_manager); |
652 shelf_ = shelf_layout_manager; | 575 shelf_ = shelf_layout_manager; |
653 | 576 |
654 internal::StatusAreaLayoutManager* status_area_layout_manager = | 577 internal::StatusAreaLayoutManager* status_area_layout_manager = |
655 new internal::StatusAreaLayoutManager(shelf_layout_manager); | 578 new internal::StatusAreaLayoutManager(shelf_layout_manager); |
656 GetContainer(internal::kShellWindowId_StatusContainer)-> | 579 GetContainer(internal::kShellWindowId_StatusContainer)-> |
657 SetLayoutManager(status_area_layout_manager); | 580 SetLayoutManager(status_area_layout_manager); |
658 | 581 |
659 aura::Window* default_container = | 582 aura::Window* default_container = |
660 GetContainer(internal::kShellWindowId_DefaultContainer); | 583 GetContainer(internal::kShellWindowId_DefaultContainer); |
661 // Workspace manager has its own layout managers. | 584 // Workspace manager has its own layout managers. |
662 workspace_controller_.reset( | 585 workspace_controller_.reset( |
663 new internal::WorkspaceController(default_container)); | 586 new internal::WorkspaceController(default_container)); |
664 workspace_controller_->workspace_manager()->set_shelf(shelf_layout_manager); | 587 workspace_controller_->workspace_manager()->set_shelf(shelf_layout_manager); |
665 | 588 |
666 // Ensure launcher is visible. | 589 // Ensure launcher is visible. |
667 launcher_->widget()->Show(); | 590 launcher_->widget()->Show(); |
668 | 591 |
669 // Create the desktop background image. | 592 // Create the desktop background image. |
670 SetDesktopBackgroundMode(BACKGROUND_IMAGE); | 593 SetDesktopBackgroundMode(BACKGROUND_IMAGE); |
671 } | 594 } |
672 | 595 |
673 void Shell::ResetLayoutManager(int container_id) { | |
674 GetContainer(container_id)->SetLayoutManager(NULL); | |
675 } | |
676 | |
677 void Shell::DisableWorkspaceGridLayout() { | 596 void Shell::DisableWorkspaceGridLayout() { |
678 if (workspace_controller_.get()) | 597 if (workspace_controller_.get()) |
679 workspace_controller_->workspace_manager()->set_grid_size(0); | 598 workspace_controller_->workspace_manager()->set_grid_size(0); |
680 } | 599 } |
681 | 600 |
682 } // namespace ash | 601 } // namespace ash |
OLD | NEW |