diff options
35 files changed, 810 insertions, 397 deletions
diff --git a/ash/accelerators/nested_dispatcher_controller_unittest.cc b/ash/accelerators/nested_dispatcher_controller_unittest.cc index c0a2e4f..905b353 100644 --- a/ash/accelerators/nested_dispatcher_controller_unittest.cc +++ b/ash/accelerators/nested_dispatcher_controller_unittest.cc @@ -4,6 +4,7 @@ #include "ash/accelerators/accelerator_controller.h" #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "base/bind.h" @@ -114,14 +115,10 @@ TEST_F(NestedDispatcherTest, AssociatedWindowBelowLockScreen) { MockDispatcher inner_dispatcher; aura::Window* default_container = Shell::GetInstance()->GetContainer( internal::kShellWindowId_DefaultContainer); - scoped_ptr<aura::Window>associated_window(aura::test::CreateTestWindowWithId( + scoped_ptr<aura::Window> associated_window(aura::test::CreateTestWindowWithId( 0, default_container)); - scoped_ptr<aura::Window>mock_lock_container( - aura::test::CreateTestWindowWithId(0, default_container)); - mock_lock_container->set_stops_event_propagation(true); - aura::test::CreateTestWindowWithId(0, mock_lock_container.get()); - EXPECT_TRUE(aura::test::WindowIsAbove(mock_lock_container.get(), - associated_window.get())); + + Shell::GetInstance()->delegate()->LockScreen(); DispatchKeyReleaseA(); aura::RootWindow* root_window = ash::Shell::GetInstance()->GetRootWindow(); aura::client::GetDispatcherClient(root_window)->RunWithDispatcher( @@ -129,6 +126,7 @@ TEST_F(NestedDispatcherTest, AssociatedWindowBelowLockScreen) { associated_window.get(), true /* nestable_tasks_allowed */); EXPECT_EQ(0, inner_dispatcher.num_key_events_dispatched()); + Shell::GetInstance()->delegate()->UnlockScreen(); } // Aura window above lock screen in z order. @@ -139,7 +137,6 @@ TEST_F(NestedDispatcherTest, AssociatedWindowAboveLockScreen) { internal::kShellWindowId_DefaultContainer); scoped_ptr<aura::Window>mock_lock_container( aura::test::CreateTestWindowWithId(0, default_container)); - mock_lock_container->set_stops_event_propagation(true); aura::test::CreateTestWindowWithId(0, mock_lock_container.get()); scoped_ptr<aura::Window>associated_window(aura::test::CreateTestWindowWithId( 0, default_container)); diff --git a/ash/ash.gyp b/ash/ash.gyp index abb5715..fa12fdc 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -188,6 +188,8 @@ 'wm/default_window_resizer.h', 'wm/dialog_frame_view.cc', 'wm/dialog_frame_view.h', + 'wm/event_client_impl.cc', + 'wm/event_client_impl.h', 'wm/frame_painter.cc', 'wm/frame_painter.h', 'wm/image_grid.cc', @@ -426,9 +428,13 @@ 'shell/app_list.cc', 'shell/bubble.cc', 'shell/example_factory.h', + 'shell/launcher_delegate_impl.cc', + 'shell/launcher_delegate_impl.h', 'shell/lock_view.cc', 'shell/panel_window.cc', 'shell/panel_window.h', + 'shell/shell_delegate_impl.cc', + 'shell/shell_delegate_impl.h', 'shell/shell_main.cc', 'shell/shell_main_parts.cc', 'shell/shell_main_parts.h', @@ -438,6 +444,8 @@ 'shell/widgets.cc', 'shell/window_type_launcher.cc', 'shell/window_type_launcher.h', + 'shell/window_watcher.cc', + 'shell/window_watcher.h', '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc', '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources_standard/ui_resources_standard.rc', '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc', diff --git a/ash/shell.cc b/ash/shell.cc index dcdf714..2d2489a 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -42,6 +42,7 @@ #include "ash/wm/base_layout_manager.h" #include "ash/wm/custom_frame_view_ash.h" #include "ash/wm/dialog_frame_view.h" +#include "ash/wm/event_client_impl.h" #include "ash/wm/panel_window_event_filter.h" #include "ash/wm/panel_layout_manager.h" #include "ash/wm/partial_screenshot_event_filter.h" @@ -194,7 +195,7 @@ void CreateSpecialContainers(aura::RootWindow* root_window) { lock_screen_containers); lock_container->SetLayoutManager( new internal::BaseLayoutManager(root_window)); - lock_container->set_stops_event_propagation(true); + // TODO(beng): stopsevents aura::Window* lock_modal_container = CreateContainer( internal::kShellWindowId_LockSystemModalContainer, @@ -551,6 +552,8 @@ Shell::~Shell() { resize_shadow_controller_.reset(); shadow_controller_.reset(); window_cycle_controller_.reset(); + event_client_.reset(); + monitor_controller_.reset(); // Launcher widget has a InputMethodBridge that references to // input_method_filter_'s input_method_. So explicitly release launcher_ @@ -639,6 +642,8 @@ void Shell::Init() { root_window_layout_ = new internal::RootWindowLayoutManager(root_window); root_window->SetLayoutManager(root_window_layout_); + event_client_.reset(new internal::EventClientImpl(root_window)); + if (delegate_.get()) status_widget_ = delegate_->CreateStatusArea(); @@ -776,9 +781,7 @@ void Shell::ToggleAppList() { } bool Shell::IsScreenLocked() const { - const aura::Window* lock_screen_container = GetContainer( - internal::kShellWindowId_LockScreenContainer); - return lock_screen_container->StopsEventPropagation(); + return !delegate_.get() || delegate_->IsScreenLocked(); } bool Shell::IsModalWindowOpen() const { diff --git a/ash/shell.h b/ash/shell.h index 23a13cd..764587f 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -60,6 +60,7 @@ class ActivationController; class AcceleratorFilter; class AppList; class DragDropController; +class EventClientImpl; class FocusCycler; class InputMethodEventFilter; class MonitorController; @@ -283,6 +284,7 @@ class ASH_EXPORT Shell { scoped_ptr<VideoDetector> video_detector_; scoped_ptr<WindowCycleController> window_cycle_controller_; scoped_ptr<internal::FocusCycler> focus_cycler_; + scoped_ptr<internal::EventClientImpl> event_client_; scoped_ptr<internal::MonitorController> monitor_controller_; // An event filter that pre-handles all key events to send them to an IME. diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc index 80ff70e..2003b32 100644 --- a/ash/shell/app_list.cc +++ b/ash/shell/app_list.cc @@ -7,6 +7,8 @@ #include "ash/app_list/app_list_model.h" #include "ash/app_list/app_list_view_delegate.h" #include "ash/app_list/app_list_view.h" +#include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell/example_factory.h" #include "ash/shell/toplevel_window.h" #include "base/basictypes.h" @@ -80,7 +82,7 @@ class WindowTypeLauncherItem : public ash::AppListItemModel { break; } case LOCK_SCREEN: { - CreateLockScreen(); + Shell::GetInstance()->delegate()->LockScreen(); break; } case WIDGETS_WINDOW: { diff --git a/ash/shell/launcher_delegate_impl.cc b/ash/shell/launcher_delegate_impl.cc new file mode 100644 index 0000000..b5f6e7f --- /dev/null +++ b/ash/shell/launcher_delegate_impl.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/shell/launcher_delegate_impl.h" + +#include "ash/shell/toplevel_window.h" +#include "ash/shell/window_watcher.h" +#include "ash/wm/window_util.h" +#include "grit/ui_resources.h" +#include "ui/aura/window.h" + +namespace ash { +namespace shell { + +LauncherDelegateImpl::LauncherDelegateImpl(WindowWatcher* watcher) + : watcher_(watcher) { +} + +LauncherDelegateImpl::~LauncherDelegateImpl() { +} + +void LauncherDelegateImpl::CreateNewWindow() { + ash::shell::ToplevelWindow::CreateParams create_params; + create_params.can_resize = true; + create_params.can_maximize = true; + ash::shell::ToplevelWindow::CreateToplevelWindow(create_params); +} + +void LauncherDelegateImpl::ItemClicked(const ash::LauncherItem& item) { + aura::Window* window = watcher_->GetWindowByID(item.id); + window->Show(); + ash::wm::ActivateWindow(window); +} + +int LauncherDelegateImpl::GetBrowserShortcutResourceId() { + return IDR_AURA_LAUNCHER_BROWSER_SHORTCUT; +} + +string16 LauncherDelegateImpl::GetTitle(const ash::LauncherItem& item) { + return watcher_->GetWindowByID(item.id)->title(); +} + +ui::MenuModel* LauncherDelegateImpl::CreateContextMenu( + const ash::LauncherItem& item) { + return NULL; +} + +ash::LauncherID LauncherDelegateImpl::GetIDByWindow(aura::Window* window) { + return watcher_->GetIDByWindow(window); +} + +} // namespace shell +} // namespace ash diff --git a/ash/shell/launcher_delegate_impl.h b/ash/shell/launcher_delegate_impl.h new file mode 100644 index 0000000..425e4cfd --- /dev/null +++ b/ash/shell/launcher_delegate_impl.h @@ -0,0 +1,47 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SHELL_LAUNCHER_DELEGATE_IMPL_H_ +#define ASH_SHELL_LAUNCHER_DELEGATE_IMPL_H_ +#pragma once + +#include "ash/launcher/launcher_delegate.h" +#include "base/compiler_specific.h" + +namespace aura { +class Window; +} + +namespace ash { +namespace shell { + +class WindowWatcher; + +class LauncherDelegateImpl : public ash::LauncherDelegate { + public: + explicit LauncherDelegateImpl(WindowWatcher* watcher); + virtual ~LauncherDelegateImpl(); + + void set_watcher(WindowWatcher* watcher) { watcher_ = watcher; } + + // LauncherDelegate overrides: + virtual void CreateNewWindow() OVERRIDE; + virtual void ItemClicked(const ash::LauncherItem& item) OVERRIDE; + virtual int GetBrowserShortcutResourceId() OVERRIDE; + virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE; + virtual ui::MenuModel* CreateContextMenu( + const ash::LauncherItem& item) OVERRIDE; + virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE; + + private: + // Used to update Launcher. Owned by main. + WindowWatcher* watcher_; + + DISALLOW_COPY_AND_ASSIGN(LauncherDelegateImpl); +}; + +} // namespace shell +} // namespace ash + +#endif // ASH_SHELL_LAUNCHER_DELEGATE_IMPL_H_ diff --git a/ash/shell/lock_view.cc b/ash/shell/lock_view.cc index c8a4d82..a604e89 100644 --- a/ash/shell/lock_view.cc +++ b/ash/shell/lock_view.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/shell/example_factory.h" #include "ash/tooltips/tooltip_controller.h" @@ -11,6 +12,7 @@ #include "ui/aura/window.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" +#include "ui/views/controls/button/text_button.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -19,18 +21,23 @@ using ash::Shell; namespace ash { namespace shell { -class LockView : public views::WidgetDelegateView { +class LockView : public views::WidgetDelegateView, + public views::ButtonListener { public: - LockView() {} + LockView() : unlock_button_(ALLOW_THIS_IN_INITIALIZER_LIST( + new views::NativeTextButton(this, ASCIIToUTF16("Unlock")))) { + AddChildView(unlock_button_); + unlock_button_->set_focusable(true); + } virtual ~LockView() {} - // Overridden from View: + // Overridden from views::View: virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(500, 400); } private: - // Overridden from View: + // Overridden from views::View: virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { canvas->FillRect(GetLocalBounds(), SK_ColorYELLOW); string16 text = ASCIIToUTF16("LOCKED!"); @@ -39,14 +46,35 @@ class LockView : public views::WidgetDelegateView { (height() - font_.GetHeight()) / 2, string_width, font_.GetHeight()); } - virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE { - return true; + virtual void Layout() OVERRIDE { + gfx::Rect bounds = GetLocalBounds(); + gfx::Size ps = unlock_button_->GetPreferredSize(); + bounds.set_y(bounds.bottom() - ps.height() - 5); + bounds.set_x((bounds.width() - ps.width()) / 2); + bounds.set_size(ps); + unlock_button_->SetBoundsRect(bounds); + } + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) OVERRIDE { + if (is_add && child == this) + unlock_button_->RequestFocus(); } - virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE { + + // Overridden from views::WidgetDelegateView: + virtual void WindowClosing() OVERRIDE { + Shell::GetInstance()->delegate()->UnlockScreen(); + } + + // Overridden from views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const views::Event& event) OVERRIDE { + DCHECK(sender == unlock_button_); GetWidget()->Close(); } gfx::Font font_; + views::NativeTextButton* unlock_button_; DISALLOW_COPY_AND_ASSIGN(LockView); }; @@ -54,7 +82,8 @@ class LockView : public views::WidgetDelegateView { void CreateLockScreen() { LockView* lock_view = new LockView; views::Widget* widget = new views::Widget; - views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); gfx::Size ps = lock_view->GetPreferredSize(); gfx::Size root_window_size = Shell::GetRootWindow()->bounds().size(); @@ -69,6 +98,7 @@ void CreateLockScreen() { widget->SetContentsView(lock_view); widget->Show(); widget->GetNativeView()->SetName("LockView"); + widget->GetNativeView()->Focus(); Shell::GetInstance()->tooltip_controller()->UpdateTooltip( widget->GetNativeView()); diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc new file mode 100644 index 0000000..2fb2c27a --- /dev/null +++ b/ash/shell/shell_delegate_impl.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/shell/shell_delegate_impl.h" + +#include "ash/shell/example_factory.h" +#include "ash/shell/launcher_delegate_impl.h" +#include "ash/shell_window_ids.h" +#include "ash/wm/partial_screenshot_view.h" +#include "base/message_loop.h" +#include "ui/aura/window.h" + +namespace ash { +namespace shell { + +ShellDelegateImpl::ShellDelegateImpl() + : watcher_(NULL), + launcher_delegate_(NULL), + locked_(false) { +} + +ShellDelegateImpl::~ShellDelegateImpl() { +} + +void ShellDelegateImpl::SetWatcher(WindowWatcher* watcher) { + watcher_ = watcher; + if (launcher_delegate_) + launcher_delegate_->set_watcher(watcher); +} + +views::Widget* ShellDelegateImpl::CreateStatusArea() { + return NULL; +} + +bool ShellDelegateImpl::CanCreateLauncher() { + return true; +} + +void ShellDelegateImpl::LockScreen() { + ash::shell::CreateLockScreen(); + locked_ = true; +} + +void ShellDelegateImpl::UnlockScreen() { + locked_ = false; +} + +bool ShellDelegateImpl::IsScreenLocked() const { + return locked_; +} + +void ShellDelegateImpl::Exit() { + MessageLoopForUI::current()->Quit(); +} + +ash::AppListViewDelegate* ShellDelegateImpl::CreateAppListViewDelegate() { + return ash::shell::CreateAppListViewDelegate(); +} + +std::vector<aura::Window*> ShellDelegateImpl::GetCycleWindowList( + CycleSource source) const { + aura::Window* default_container = ash::Shell::GetInstance()->GetContainer( + ash::internal::kShellWindowId_DefaultContainer); + std::vector<aura::Window*> windows = default_container->children(); + // Window cycling expects the topmost window at the front of the list. + std::reverse(windows.begin(), windows.end()); + return windows; +} + +void ShellDelegateImpl::StartPartialScreenshot( + ash::ScreenshotDelegate* screenshot_delegate) { + ash::PartialScreenshotView::StartPartialScreenshot(screenshot_delegate); +} + +ash::LauncherDelegate* ShellDelegateImpl::CreateLauncherDelegate( + ash::LauncherModel* model) { + launcher_delegate_ = new LauncherDelegateImpl(watcher_); + return launcher_delegate_; +} + +ash::SystemTrayDelegate* ShellDelegateImpl::CreateSystemTrayDelegate( + ash::SystemTray* tray) { + return NULL; +} + +ash::UserWallpaperDelegate* ShellDelegateImpl::CreateUserWallpaperDelegate() { + return NULL; +} + +} // namespace shell +} // namespace ash diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h new file mode 100644 index 0000000..797011b --- /dev/null +++ b/ash/shell/shell_delegate_impl.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SHELL_SHELL_DELEGATE_IMPL_H_ +#define ASH_SHELL_SHELL_DELEGATE_IMPL_H_ +#pragma once + +#include "ash/shell_delegate.h" +#include "base/compiler_specific.h" + +namespace ash { +namespace shell { + +class LauncherDelegateImpl; +class WindowWatcher; + +class ShellDelegateImpl : public ash::ShellDelegate { + public: + ShellDelegateImpl(); + virtual ~ShellDelegateImpl(); + + void SetWatcher(WindowWatcher* watcher); + + virtual views::Widget* CreateStatusArea() OVERRIDE; + virtual bool CanCreateLauncher() OVERRIDE; + virtual void LockScreen() OVERRIDE; + virtual void UnlockScreen() OVERRIDE; + virtual bool IsScreenLocked() const OVERRIDE; + virtual void Exit() OVERRIDE; + virtual ash::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE; + virtual std::vector<aura::Window*> GetCycleWindowList( + CycleSource source) const OVERRIDE; + virtual void StartPartialScreenshot( + ash::ScreenshotDelegate* screenshot_delegate) OVERRIDE; + virtual ash::LauncherDelegate* CreateLauncherDelegate( + ash::LauncherModel* model) OVERRIDE; + virtual ash::SystemTrayDelegate* CreateSystemTrayDelegate( + ash::SystemTray* tray) OVERRIDE; + virtual ash::UserWallpaperDelegate* CreateUserWallpaperDelegate() OVERRIDE; + + private: + // Used to update Launcher. Owned by main. + WindowWatcher* watcher_; + + LauncherDelegateImpl* launcher_delegate_; + + bool locked_; + + DISALLOW_COPY_AND_ASSIGN(ShellDelegateImpl); +}; + +} // namespace shell +} // namespace ash + +#endif // ASH_SHELL_SHELL_DELEGATE_IMPL_H_ diff --git a/ash/shell/shell_main.cc b/ash/shell/shell_main.cc index ee62358..3a5c699 100644 --- a/ash/shell/shell_main.cc +++ b/ash/shell/shell_main.cc @@ -12,16 +12,14 @@ #include "ash/shell_delegate.h" #include "ash/shell_factory.h" #include "ash/shell_window_ids.h" -#include "ash/shell/example_factory.h" -#include "ash/shell/toplevel_window.h" +#include "ash/shell/launcher_delegate_impl.h" +#include "ash/shell/shell_delegate_impl.h" #include "ash/shell/shell_main_parts.h" -#include "ash/wm/partial_screenshot_view.h" -#include "ash/wm/window_util.h" +#include "ash/shell/window_watcher.h" #include "base/at_exit.h" #include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" -#include "grit/ui_resources.h" #include "ui/aura/env.h" #include "ui/aura/client/window_types.h" #include "ui/aura/root_window.h" @@ -55,198 +53,6 @@ class ShellViewsDelegate : public views::TestViewsDelegate { DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate); }; -// WindowWatcher is responsible for listening for newly created windows and -// creating items on the Launcher for them. -class WindowWatcher : public aura::WindowObserver { - public: - WindowWatcher() - : window_(ash::Shell::GetInstance()->launcher()->window_container()) { - window_->AddObserver(this); - } - - virtual ~WindowWatcher() { - window_->RemoveObserver(this); - } - - aura::Window* GetWindowByID(ash::LauncherID id) { - IDToWindow::const_iterator i = id_to_window_.find(id); - return i != id_to_window_.end() ? i->second : NULL; - } - - ash::LauncherID GetIDByWindow(aura::Window* window) const { - for (IDToWindow::const_iterator i = id_to_window_.begin(); - i != id_to_window_.end(); ++i) { - if (i->second == window) - return i->first; - } - return 0; // TODO: add a constant for this. - } - - // aura::WindowObserver overrides: - virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE { - if (new_window->type() != aura::client::WINDOW_TYPE_NORMAL) - return; - - static int image_count = 0; - ash::LauncherModel* model = ash::Shell::GetInstance()->launcher()->model(); - ash::LauncherItem item; - item.type = ash::TYPE_TABBED; - id_to_window_[model->next_id()] = new_window; - item.num_tabs = image_count + 1; - item.image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); - item.image.allocPixels(); - item.image.eraseARGB(255, - image_count == 0 ? 255 : 0, - image_count == 1 ? 255 : 0, - image_count == 2 ? 255 : 0); - image_count = (image_count + 1) % 3; - model->Add(model->item_count(), item); - } - - virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE { - for (IDToWindow::iterator i = id_to_window_.begin(); - i != id_to_window_.end(); ++i) { - if (i->second == window) { - ash::LauncherModel* model = - ash::Shell::GetInstance()->launcher()->model(); - int index = model->ItemIndexByID(i->first); - DCHECK_NE(-1, index); - model->RemoveItemAt(index); - id_to_window_.erase(i); - break; - } - } - } - - private: - typedef std::map<ash::LauncherID, aura::Window*> IDToWindow; - - // Window watching for newly created windows to be added to. - aura::Window* window_; - - // Maps from window to the id we gave it. - IDToWindow id_to_window_; - - DISALLOW_COPY_AND_ASSIGN(WindowWatcher); -}; - -class LauncherDelegateImpl : public ash::LauncherDelegate { - public: - explicit LauncherDelegateImpl(WindowWatcher* watcher) - : watcher_(watcher) { - } - - void set_watcher(WindowWatcher* watcher) { watcher_ = watcher; } - - // LauncherDelegate overrides: - virtual void CreateNewWindow() OVERRIDE { - ash::shell::ToplevelWindow::CreateParams create_params; - create_params.can_resize = true; - create_params.can_maximize = true; - ash::shell::ToplevelWindow::CreateToplevelWindow(create_params); - } - - virtual void ItemClicked(const ash::LauncherItem& item) OVERRIDE { - aura::Window* window = watcher_->GetWindowByID(item.id); - window->Show(); - ash::wm::ActivateWindow(window); - } - - virtual int GetBrowserShortcutResourceId() OVERRIDE { - return IDR_AURA_LAUNCHER_BROWSER_SHORTCUT; - } - - virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE { - return watcher_->GetWindowByID(item.id)->title(); - } - - virtual ui::MenuModel* CreateContextMenu( - const ash::LauncherItem& item) OVERRIDE { - return NULL; - } - - virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE { - return watcher_->GetIDByWindow(window); - } - - private: - // Used to update Launcher. Owned by main. - WindowWatcher* watcher_; - - DISALLOW_COPY_AND_ASSIGN(LauncherDelegateImpl); -}; - -class ShellDelegateImpl : public ash::ShellDelegate { - public: - ShellDelegateImpl() : watcher_(NULL), launcher_delegate_(NULL) {} - - void SetWatcher(WindowWatcher* watcher) { - watcher_ = watcher; - if (launcher_delegate_) - launcher_delegate_->set_watcher(watcher); - } - - virtual views::Widget* CreateStatusArea() OVERRIDE { - return NULL; - } - - virtual bool CanCreateLauncher() OVERRIDE { - return true; - } - -#if defined(OS_CHROMEOS) - virtual void LockScreen() OVERRIDE { - ash::shell::CreateLockScreen(); - } -#endif - - virtual void Exit() OVERRIDE { - MessageLoopForUI::current()->Quit(); - } - - virtual ash::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE { - return ash::shell::CreateAppListViewDelegate(); - } - - std::vector<aura::Window*> GetCycleWindowList( - CycleSource source) const OVERRIDE { - aura::Window* default_container = ash::Shell::GetInstance()->GetContainer( - ash::internal::kShellWindowId_DefaultContainer); - std::vector<aura::Window*> windows = default_container->children(); - // Window cycling expects the topmost window at the front of the list. - std::reverse(windows.begin(), windows.end()); - return windows; - } - - virtual void StartPartialScreenshot( - ash::ScreenshotDelegate* screenshot_delegate) OVERRIDE { - ash::PartialScreenshotView::StartPartialScreenshot(screenshot_delegate); - } - - virtual ash::LauncherDelegate* CreateLauncherDelegate( - ash::LauncherModel* model) OVERRIDE { - launcher_delegate_ = new LauncherDelegateImpl(watcher_); - return launcher_delegate_; - } - - virtual ash::SystemTrayDelegate* CreateSystemTrayDelegate( - ash::SystemTray* tray) { - return NULL; - } - - virtual ash::UserWallpaperDelegate* CreateUserWallpaperDelegate() { - return NULL; - } - - private: - // Used to update Launcher. Owned by main. - WindowWatcher* watcher_; - - LauncherDelegateImpl* launcher_delegate_; - - DISALLOW_COPY_AND_ASSIGN(ShellDelegateImpl); -}; - } // namespace namespace ash { @@ -273,10 +79,11 @@ int main(int argc, char** argv) { if (!views::ViewsDelegate::views_delegate) views::ViewsDelegate::views_delegate = new ShellViewsDelegate; - ShellDelegateImpl* delegate = new ShellDelegateImpl; + ash::shell::ShellDelegateImpl* delegate = new ash::shell::ShellDelegateImpl; ash::Shell::CreateInstance(delegate); - scoped_ptr<WindowWatcher> window_watcher(new WindowWatcher); + scoped_ptr<ash::shell::WindowWatcher> window_watcher( + new ash::shell::WindowWatcher); delegate->SetWatcher(window_watcher.get()); ash::shell::InitWindowTypeLauncher(); diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc index 9efd285..61d0d9c 100644 --- a/ash/shell/window_type_launcher.cc +++ b/ash/shell/window_type_launcher.cc @@ -4,6 +4,8 @@ #include "ash/shell/window_type_launcher.h" +#include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/shell/example_factory.h" #include "ash/shell/panel_window.h" @@ -323,7 +325,7 @@ void WindowTypeLauncher::ButtonPressed(views::Button* sender, } else if (sender == bubble_button_) { CreatePointyBubble(sender); } else if (sender == lock_button_) { - CreateLockScreen(); + Shell::GetInstance()->delegate()->LockScreen(); } else if (sender == widgets_button_) { CreateWidgetsWindow(); } else if (sender == system_modal_button_) { diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc new file mode 100644 index 0000000..05c4f74 --- /dev/null +++ b/ash/shell/window_watcher.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/shell/window_watcher.h" + +#include "ash/launcher/launcher.h" +#include "ash/launcher/launcher_model.h" +#include "ash/shell.h" +#include "ui/aura/window.h" + +namespace ash { +namespace shell { + +WindowWatcher::WindowWatcher() + : window_(ash::Shell::GetInstance()->launcher()->window_container()) { + window_->AddObserver(this); +} + +WindowWatcher::~WindowWatcher() { + window_->RemoveObserver(this); +} + +aura::Window* WindowWatcher::GetWindowByID(ash::LauncherID id) { + IDToWindow::const_iterator i = id_to_window_.find(id); + return i != id_to_window_.end() ? i->second : NULL; +} + +ash::LauncherID WindowWatcher::GetIDByWindow(aura::Window* window) const { + for (IDToWindow::const_iterator i = id_to_window_.begin(); + i != id_to_window_.end(); ++i) { + if (i->second == window) + return i->first; + } + return 0; // TODO: add a constant for this. +} + +// aura::WindowObserver overrides: +void WindowWatcher::OnWindowAdded(aura::Window* new_window) { + if (new_window->type() != aura::client::WINDOW_TYPE_NORMAL) + return; + + static int image_count = 0; + ash::LauncherModel* model = ash::Shell::GetInstance()->launcher()->model(); + ash::LauncherItem item; + item.type = ash::TYPE_TABBED; + id_to_window_[model->next_id()] = new_window; + item.num_tabs = image_count + 1; + item.image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); + item.image.allocPixels(); + item.image.eraseARGB(255, + image_count == 0 ? 255 : 0, + image_count == 1 ? 255 : 0, + image_count == 2 ? 255 : 0); + image_count = (image_count + 1) % 3; + model->Add(model->item_count(), item); +} + +void WindowWatcher::OnWillRemoveWindow(aura::Window* window) { + for (IDToWindow::iterator i = id_to_window_.begin(); + i != id_to_window_.end(); ++i) { + if (i->second == window) { + ash::LauncherModel* model = + ash::Shell::GetInstance()->launcher()->model(); + int index = model->ItemIndexByID(i->first); + DCHECK_NE(-1, index); + model->RemoveItemAt(index); + id_to_window_.erase(i); + break; + } + } +} + +} // namespace shell +} // namespace ash diff --git a/ash/shell/window_watcher.h b/ash/shell/window_watcher.h new file mode 100644 index 0000000..d36a4c8 --- /dev/null +++ b/ash/shell/window_watcher.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SHELL_WINDOW_WATCHER_H_ +#define ASH_SHELL_WINDOW_WATCHER_H_ +#pragma once + +#include <map> + +#include "ash/launcher/launcher_types.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "ui/aura/window_observer.h" + +namespace aura { +class Window; +} + +namespace ash { +namespace shell { + +// WindowWatcher is responsible for listening for newly created windows and +// creating items on the Launcher for them. +class WindowWatcher : public aura::WindowObserver { + public: + WindowWatcher(); + virtual ~WindowWatcher(); + + aura::Window* GetWindowByID(ash::LauncherID id); + ash::LauncherID GetIDByWindow(aura::Window* window) const; + + // aura::WindowObserver overrides: + virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE; + virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE; + + private: + typedef std::map<ash::LauncherID, aura::Window*> IDToWindow; + + // Window watching for newly created windows to be added to. + aura::Window* window_; + + // Maps from window to the id we gave it. + IDToWindow id_to_window_; + + DISALLOW_COPY_AND_ASSIGN(WindowWatcher); +}; + +} // namespace shell +} // namespace ash + +#endif // ASH_SHELL_WINDOW_WATCHER_H_ diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index abcb72a..d6bc931 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h @@ -54,10 +54,14 @@ class ASH_EXPORT ShellDelegate { // until e.g. a user has logged in and their profile has been loaded. virtual bool CanCreateLauncher() = 0; -#if defined(OS_CHROMEOS) - // Invoked when a user uses Ctrl-Shift-L to lock the screen. + // Invoked when a user locks the screen. virtual void LockScreen() = 0; -#endif + + // Unlock the screen. Currently used only for tests. + virtual void UnlockScreen() = 0; + + // Returns true if the screen is currently locked. + virtual bool IsScreenLocked() const = 0; // Invoked when a user uses Ctrl-Shift-Q to close chrome. virtual void Exit() = 0; diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc index 9f5ff3a..d4dd7ea 100644 --- a/ash/shell_unittest.cc +++ b/ash/shell_unittest.cc @@ -5,6 +5,7 @@ #include "ash/ash_switches.h" #include "ash/launcher/launcher.h" #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/wm/root_window_layout_manager.h" @@ -244,46 +245,9 @@ TEST_F(ShellTest, CreateLockScreenModalWindow) { } TEST_F(ShellTest, IsScreenLocked) { - views::Widget::InitParams widget_params( - views::Widget::InitParams::TYPE_WINDOW); - - // A normal window does not lock the screen. - views::Widget* widget = CreateTestWindow(widget_params); - widget->Show(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - widget->Hide(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - - // A modal window with a normal window as parent does not locks the screen. - views::Widget* modal_widget = views::Widget::CreateWindowWithParent( - new ModalWindow(), widget->GetNativeView()); - modal_widget->Show(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - modal_widget->Close(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - widget->Close(); - - // A lock screen window locks the screen. - views::Widget* lock_widget = CreateTestWindow(widget_params); - ash::Shell::GetInstance()->GetContainer( - ash::internal::kShellWindowId_LockScreenContainer)-> - AddChild(lock_widget->GetNativeView()); - lock_widget->Show(); - EXPECT_TRUE(Shell::GetInstance()->IsScreenLocked()); - lock_widget->Hide(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - - // A modal window with a lock window as parent does not lock the screen. The - // screen is locked only when a lock window is visible. - views::Widget* lock_modal_widget = views::Widget::CreateWindowWithParent( - new ModalWindow(), lock_widget->GetNativeView()); - lock_modal_widget->Show(); - EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); - lock_widget->Show(); - EXPECT_TRUE(Shell::GetInstance()->IsScreenLocked()); - lock_modal_widget->Close(); + ash::Shell::GetInstance()->delegate()->LockScreen(); EXPECT_TRUE(Shell::GetInstance()->IsScreenLocked()); - lock_widget->Close(); + ash::Shell::GetInstance()->delegate()->UnlockScreen(); EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked()); } diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc index 3c8de10..49baee5 100644 --- a/ash/test/test_shell_delegate.cc +++ b/ash/test/test_shell_delegate.cc @@ -15,7 +15,7 @@ namespace ash { namespace test { -TestShellDelegate::TestShellDelegate() { +TestShellDelegate::TestShellDelegate() : locked_(false) { } TestShellDelegate::~TestShellDelegate() { @@ -29,10 +29,17 @@ bool TestShellDelegate::CanCreateLauncher() { return true; } -#if defined(OS_CHROMEOS) void TestShellDelegate::LockScreen() { + locked_ = true; +} + +void TestShellDelegate::UnlockScreen() { + locked_ = false; +} + +bool TestShellDelegate::IsScreenLocked() const { + return locked_; } -#endif void TestShellDelegate::Exit() { } diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h index f23517f..72412ffe 100644 --- a/ash/test/test_shell_delegate.h +++ b/ash/test/test_shell_delegate.h @@ -20,9 +20,9 @@ class TestShellDelegate : public ShellDelegate { // Overridden from ShellDelegate: virtual views::Widget* CreateStatusArea() OVERRIDE; virtual bool CanCreateLauncher() OVERRIDE; -#if defined(OS_CHROMEOS) virtual void LockScreen() OVERRIDE; -#endif + virtual void UnlockScreen() OVERRIDE; + virtual bool IsScreenLocked() const OVERRIDE; virtual void Exit() OVERRIDE; virtual AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE; virtual std::vector<aura::Window*> GetCycleWindowList( @@ -35,6 +35,8 @@ class TestShellDelegate : public ShellDelegate { virtual UserWallpaperDelegate* CreateUserWallpaperDelegate() OVERRIDE; private: + bool locked_; + DISALLOW_COPY_AND_ASSIGN(TestShellDelegate); }; diff --git a/ash/wm/event_client_impl.cc b/ash/wm/event_client_impl.cc new file mode 100644 index 0000000..58b4385 --- /dev/null +++ b/ash/wm/event_client_impl.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/event_client_impl.h" + +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" + +namespace ash { +namespace internal { + +EventClientImpl::EventClientImpl(aura::RootWindow* root_window) + : root_window_(root_window) { + aura::client::SetEventClient(root_window_, this); +} + +EventClientImpl::~EventClientImpl() { + aura::client::SetEventClient(root_window_, NULL); +} + +bool EventClientImpl::CanProcessEventsWithinSubtree( + const aura::Window* window) const { + if (Shell::GetInstance()->IsScreenLocked()) { + aura::Window* lock_screen_containers = + Shell::GetInstance()->GetContainer( + kShellWindowId_LockScreenContainersContainer); + aura::Window* lock_screen_related_containers = + Shell::GetInstance()->GetContainer( + kShellWindowId_LockScreenRelatedContainersContainer); + return lock_screen_containers->Contains(window) || + lock_screen_related_containers->Contains(window); + } + return true; +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/event_client_impl.h b/ash/wm/event_client_impl.h new file mode 100644 index 0000000..7148664 --- /dev/null +++ b/ash/wm/event_client_impl.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_EVENT_CLIENT_IMPL_H_ +#define ASH_WM_EVENT_CLIENT_IMPL_H_ +#pragma once + +#include "ash/ash_export.h" +#include "ui/aura/client/event_client.h" + +namespace aura { +class RootWindow; +} + +namespace ash { +namespace internal { + +class EventClientImpl : public aura::client::EventClient { + public: + explicit EventClientImpl(aura::RootWindow* root_window); + virtual ~EventClientImpl(); + + private: + // Overridden from aura::client::EventClient: + virtual bool CanProcessEventsWithinSubtree( + const aura::Window* window) const OVERRIDE; + + aura::RootWindow* root_window_; + + DISALLOW_COPY_AND_ASSIGN(EventClientImpl); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_WM_EVENT_CLIENT_IMPL_H_ diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc index 1dcd3be..c5769fb 100644 --- a/ash/wm/shelf_layout_manager_unittest.cc +++ b/ash/wm/shelf_layout_manager_unittest.cc @@ -162,7 +162,7 @@ TEST_F(ShelfLayoutManagerTest, DontReferenceLauncherAfterDeletion) { } // Various assertions around auto-hide. -TEST_F(ShelfLayoutManagerTest, AutoHide) { +TEST_F(ShelfLayoutManagerTest, DISABLED_AutoHide) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc index a4814e2..6dbb9cf 100644 --- a/ash/wm/system_modal_container_layout_manager_unittest.cc +++ b/ash/wm/system_modal_container_layout_manager_unittest.cc @@ -5,6 +5,7 @@ #include "ash/wm/system_modal_container_layout_manager.h" #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_util.h" @@ -227,6 +228,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, // Create a window in the lock screen container and ensure that it receives // the mouse event instead of the modal window (crbug.com/110920). + Shell::GetInstance()->delegate()->LockScreen(); EventTestWindow* lock_delegate = new EventTestWindow(false); scoped_ptr<aura::Window> lock(lock_delegate->OpenTestWindow( Shell::GetInstance()->GetContainer( @@ -247,6 +249,8 @@ TEST_F(SystemModalContainerLayoutManagerTest, EXPECT_EQ(1, transient_delegate->mouse_presses()); EXPECT_EQ(1, lock_delegate->mouse_presses()); EXPECT_EQ(1, lock_modal_delegate->mouse_presses()); + + Shell::GetInstance()->delegate()->UnlockScreen(); } } // namespace test diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc index 499acdc..3aaac40 100644 --- a/ash/wm/window_cycle_controller_unittest.cc +++ b/ash/wm/window_cycle_controller_unittest.cc @@ -132,21 +132,15 @@ TEST_F(WindowCycleControllerTest, HandleCycleWindow) { EXPECT_FALSE(controller->IsCycling()); EXPECT_TRUE(wm::IsActiveWindow(window0.get())); - // When a screen lock window is visible, cycling window does not take effect. - aura::Window* lock_screen_container = - Shell::GetInstance()->GetContainer( - internal::kShellWindowId_LockScreenContainer); - scoped_ptr<Window> lock_screen_window( - CreateTestWindowWithId(-1, lock_screen_container)); - lock_screen_window->Show(); + // When the screen is locked, cycling window does not take effect. + Shell::GetInstance()->delegate()->LockScreen(); EXPECT_TRUE(wm::IsActiveWindow(window0.get())); controller->HandleCycleWindow(WindowCycleController::FORWARD, false); EXPECT_TRUE(wm::IsActiveWindow(window0.get())); controller->HandleCycleWindow(WindowCycleController::BACKWARD, false); EXPECT_TRUE(wm::IsActiveWindow(window0.get())); - // Hiding the lock screen is equivalent to not being locked. - lock_screen_window->Hide(); + Shell::GetInstance()->delegate()->UnlockScreen(); EXPECT_TRUE(wm::IsActiveWindow(window0.get())); controller->HandleCycleWindow(WindowCycleController::FORWARD, false); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); diff --git a/chrome/browser/ui/views/ash/chrome_shell_delegate.cc b/chrome/browser/ui/views/ash/chrome_shell_delegate.cc index 3aecd39..c076abf 100644 --- a/chrome/browser/ui/views/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/views/ash/chrome_shell_delegate.cc @@ -9,6 +9,7 @@ #include "ash/wm/partial_screenshot_view.h" #include "ash/wm/window_util.h" #include "base/command_line.h" +#include "chrome/browser/chromeos/login/screen_locker.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/ash/app_list/app_list_view_delegate.h" @@ -89,14 +90,29 @@ bool ChromeShellDelegate::CanCreateLauncher() { #endif } -#if defined(OS_CHROMEOS) void ChromeShellDelegate::LockScreen() { +#if defined(OS_CHROMEOS) if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) { chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> NotifyScreenLockRequested(); } +#endif +} + +void ChromeShellDelegate::UnlockScreen() { + // This is used only for testing thus far. + NOTIMPLEMENTED(); } + +bool ChromeShellDelegate::IsScreenLocked() const { +#if defined(OS_CHROMEOS) + if (!chromeos::ScreenLocker::default_screen_locker()) + return false; + return chromeos::ScreenLocker::default_screen_locker()->locked(); +#else + return false; #endif +} void ChromeShellDelegate::Exit() { BrowserList::AttemptUserExit(); diff --git a/chrome/browser/ui/views/ash/chrome_shell_delegate.h b/chrome/browser/ui/views/ash/chrome_shell_delegate.h index 5fc9dec..2e3ac18 100644 --- a/chrome/browser/ui/views/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/views/ash/chrome_shell_delegate.h @@ -41,9 +41,9 @@ class ChromeShellDelegate : public ash::ShellDelegate, // ash::ShellDelegate overrides; virtual views::Widget* CreateStatusArea() OVERRIDE; virtual bool CanCreateLauncher() OVERRIDE; -#if defined(OS_CHROMEOS) virtual void LockScreen() OVERRIDE; -#endif + virtual void UnlockScreen() OVERRIDE; + virtual bool IsScreenLocked() const OVERRIDE; virtual void Exit() OVERRIDE; virtual ash::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE; virtual std::vector<aura::Window*> GetCycleWindowList( diff --git a/chrome/test/base/view_event_test_base.cc b/chrome/test/base/view_event_test_base.cc index e6c1ac1..4f88ed1 100644 --- a/chrome/test/base/view_event_test_base.cc +++ b/chrome/test/base/view_event_test_base.cc @@ -17,6 +17,7 @@ #if defined(USE_AURA) #include "ash/shell.h" +#include "ui/aura/client/event_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" #endif @@ -81,6 +82,10 @@ void ViewEventTestBase::SetUp() { ui::CompositorTestSupport::Initialize(); #if defined(USE_AURA) ash::Shell::CreateInstance(NULL); + // The shell runs with a locked screen in tests, so we must clear the event + // client so it doesn't interfere with event propagation. + aura::client::SetEventClient(ash::Shell::GetInstance()->GetRootWindow(), + NULL); #endif window_ = views::Widget::CreateWindow(this); } diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 89aea94..e0dafba 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp @@ -38,6 +38,8 @@ 'client/drag_drop_client.h', 'client/drag_drop_delegate.cc', 'client/drag_drop_delegate.h', + 'client/event_client.cc', + 'client/event_client.h', 'client/stacking_client.cc', 'client/stacking_client.h', 'client/tooltip_client.cc', diff --git a/ui/aura/client/event_client.cc b/ui/aura/client/event_client.cc new file mode 100644 index 0000000..dfb3410 --- /dev/null +++ b/ui/aura/client/event_client.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/client/event_client.h" + +#include "ui/aura/root_window.h" +#include "ui/aura/window_property.h" + +DECLARE_WINDOW_PROPERTY_TYPE(aura::client::EventClient*) + +namespace aura { +namespace client { + +DEFINE_WINDOW_PROPERTY_KEY(EventClient*, kRootWindowEventClientKey, NULL); + +void SetEventClient(RootWindow* root_window, EventClient* client) { + root_window->SetProperty(kRootWindowEventClientKey, client); +} + +EventClient* GetEventClient(const RootWindow* root_window) { + return root_window ? + root_window->GetProperty(kRootWindowEventClientKey) : NULL; +} + +} // namespace client +} // namespace aura diff --git a/ui/aura/client/event_client.h b/ui/aura/client/event_client.h new file mode 100644 index 0000000..caf3a2b --- /dev/null +++ b/ui/aura/client/event_client.h @@ -0,0 +1,36 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_CLIENT_EVENT_CLIENT_H_ +#define UI_AURA_CLIENT_EVENT_CLIENT_H_ +#pragma once + +#include "ui/aura/aura_export.h" +#include "ui/aura/window.h" + +namespace aura { + +class Event; +class RootWindow; + +namespace client { + +// An interface implemented by an object that alters event processing. +class AURA_EXPORT EventClient { + public: + // Returns true if events can be processed by |window| or any of its children. + virtual bool CanProcessEventsWithinSubtree(const Window* window) const = 0; + + protected: + virtual ~EventClient() {} +}; + +// Sets/Gets the event client on the RootWindow. +AURA_EXPORT void SetEventClient(RootWindow* root_window, EventClient* client); +AURA_EXPORT EventClient* GetEventClient(const RootWindow* root_window); + +} // namespace clients +} // namespace aura + +#endif // UI_AURA_CLIENT_EVENT_CLIENT_H_ diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 23bc107..01093de 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -12,6 +12,7 @@ #include "base/message_loop.h" #include "ui/aura/aura_switches.h" #include "ui/aura/client/activation_client.h" +#include "ui/aura/client/event_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window_host.h" #include "ui/aura/root_window_observer.h" @@ -190,6 +191,11 @@ bool RootWindow::DispatchKeyEvent(KeyEvent* event) { KeyEvent translated_event(*event); if (translated_event.key_code() == ui::VKEY_UNKNOWN) return false; + client::EventClient* client = client::GetEventClient(GetRootWindow()); + if (client && !client->CanProcessEventsWithinSubtree(focused_window_)) { + SetFocusedWindow(NULL, NULL); + return false; + } return ProcessKeyEvent(focused_window_, &translated_event); } diff --git a/ui/aura/root_window_unittest.cc b/ui/aura/root_window_unittest.cc index ab7e986..31eef5b 100644 --- a/ui/aura/root_window_unittest.cc +++ b/ui/aura/root_window_unittest.cc @@ -5,13 +5,16 @@ #include "ui/aura/root_window.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/client/event_client.h" #include "ui/aura/env.h" #include "ui/aura/event.h" #include "ui/aura/event_filter.h" #include "ui/aura/test/aura_test_base.h" +#include "ui/aura/test/event_generator.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h" #include "ui/base/hit_test.h" +#include "ui/base/keycodes/keyboard_codes.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" @@ -59,12 +62,18 @@ class NonClientDelegate : public test::TestWindowDelegate { // A simple EventFilter that keeps track of the number of key events that it's // seen. -class TestEventFilter : public EventFilter { +class EventCountFilter : public EventFilter { public: - TestEventFilter() : num_key_events_(0) {} - virtual ~TestEventFilter() {} + EventCountFilter() : num_key_events_(0), num_mouse_events_(0) {} + virtual ~EventCountFilter() {} int num_key_events() const { return num_key_events_; } + int num_mouse_events() const { return num_mouse_events_; } + + void Reset() { + num_key_events_ = 0; + num_mouse_events_ = 0; + } // EventFilter overrides: virtual bool PreHandleKeyEvent(Window* target, KeyEvent* event) OVERRIDE { @@ -72,7 +81,8 @@ class TestEventFilter : public EventFilter { return true; } virtual bool PreHandleMouseEvent(Window* target, MouseEvent* event) OVERRIDE { - return false; + num_mouse_events_++; + return true; } virtual ui::TouchStatus PreHandleTouchEvent( Window* target, TouchEvent* event) OVERRIDE { @@ -87,7 +97,10 @@ class TestEventFilter : public EventFilter { // How many key events have been received? int num_key_events_; - DISALLOW_COPY_AND_ASSIGN(TestEventFilter); + // How many mouse events have been received? + int num_mouse_events_; + + DISALLOW_COPY_AND_ASSIGN(EventCountFilter); }; } // namespace @@ -199,8 +212,120 @@ TEST_F(RootWindowTest, TranslatedEvent) { EXPECT_EQ("100,100", translated_event.root_location().ToString()); } +namespace { + +class TestEventClient : public client::EventClient { + public: + static const int kNonLockWindowId = 100; + static const int kLockWindowId = 200; + + explicit TestEventClient(RootWindow* root_window) + : root_window_(root_window), + lock_(false) { + client::SetEventClient(root_window_, this); + Window* lock_window = + test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); + lock_window->set_id(kLockWindowId); + Window* non_lock_window = + test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); + non_lock_window->set_id(kNonLockWindowId); + } + virtual ~TestEventClient() { + client::SetEventClient(root_window_, NULL); + } + + // Starts/stops locking. Locking prevents windows other than those inside + // the lock container from receiving events, getting focus etc. + void Lock() { + lock_ = true; + } + void Unlock() { + lock_ = false; + } + + Window* GetLockWindow() { + return const_cast<Window*>( + static_cast<const TestEventClient*>(this)->GetLockWindow()); + } + const Window* GetLockWindow() const { + return root_window_->GetChildById(kLockWindowId); + } + Window* GetNonLockWindow() { + return root_window_->GetChildById(kNonLockWindowId); + } + + private: + // Overridden from client::EventClient: + virtual bool CanProcessEventsWithinSubtree( + const Window* window) const OVERRIDE { + return lock_ ? GetLockWindow()->Contains(window) : true; + } + + RootWindow* root_window_; + bool lock_; + + DISALLOW_COPY_AND_ASSIGN(TestEventClient); +}; + +} // namespace + +TEST_F(RootWindowTest, CanProcessEventsWithinSubtree) { + TestEventClient client(root_window()); + test::TestWindowDelegate d; + + EventCountFilter* nonlock_ef = new EventCountFilter; + EventCountFilter* lock_ef = new EventCountFilter; + client.GetNonLockWindow()->SetEventFilter(nonlock_ef); + client.GetLockWindow()->SetEventFilter(lock_ef); + + Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20), + client.GetNonLockWindow()); + w1->set_id(1); + Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20), + client.GetNonLockWindow()); + w2->set_id(2); + scoped_ptr<Window> w3( + test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(20, 20, 20, 20), + client.GetLockWindow())); + + w1->Focus(); + EXPECT_TRUE(w1->GetFocusManager()->IsFocusedWindow(w1)); + + client.Lock(); + + // Since we're locked, the attempt to focus w2 will be ignored. + w2->Focus(); + EXPECT_TRUE(w1->GetFocusManager()->IsFocusedWindow(w1)); + EXPECT_FALSE(w1->GetFocusManager()->IsFocusedWindow(w2)); + + { + // Attempting to send a key event to w1 (not in the lock container) should + // cause focus to be reset. + test::EventGenerator generator(root_window()); + generator.PressKey(ui::VKEY_SPACE, 0); + EXPECT_EQ(NULL, w1->GetFocusManager()->GetFocusedWindow()); + } + + { + // Events sent to a window not in the lock container will not be processed. + // i.e. never sent to the non-lock container's event filter. + test::EventGenerator generator(root_window(), w1); + generator.PressLeftButton(); + EXPECT_EQ(0, nonlock_ef->num_mouse_events()); + + // Events sent to a window in the lock container will be processed. + test::EventGenerator generator3(root_window(), w3.get()); + generator3.PressLeftButton(); + EXPECT_EQ(1, lock_ef->num_mouse_events()); + } + + // Prevent w3 from being deleted by the hierarchy since its delegate is owned + // by this scope. + w3->parent()->RemoveChild(w3.get()); +} + TEST_F(RootWindowTest, IgnoreUnknownKeys) { - TestEventFilter* filter = new TestEventFilter; + EventCountFilter* filter = new EventCountFilter; root_window()->SetEventFilter(filter); // passes ownership KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0); diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 4755f62..0d609a3 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/stl_util.h" #include "base/string_util.h" +#include "ui/aura/client/event_client.h" #include "ui/aura/client/stacking_client.h" #include "ui/aura/client/visibility_client.h" #include "ui/aura/env.h" @@ -54,7 +55,6 @@ Window::Window(WindowDelegate* delegate) id_(-1), transparent_(false), user_data_(NULL), - stops_event_propagation_(false), ignore_events_(false), hit_test_bounds_override_outer_(0), hit_test_bounds_override_inner_(0) { @@ -450,12 +450,24 @@ bool Window::HasFocus() const { bool Window::CanFocus() const { if (!IsVisible() || !parent_ || (delegate_ && !delegate_->CanFocus())) return false; - return !IsBehindStopEventsWindow() && parent_->CanFocus(); + + // The client may forbid certain windows from receiving focus at a given point + // in time. + client::EventClient* client = client::GetEventClient(GetRootWindow()); + if (client && !client->CanProcessEventsWithinSubtree(this)) + return false; + + return parent_->CanFocus(); } bool Window::CanReceiveEvents() const { - return parent_ && IsVisible() && !IsBehindStopEventsWindow() && - parent_->CanReceiveEvents(); + // The client may forbid certain windows from receiving events at a given + // point in time. + client::EventClient* client = client::GetEventClient(GetRootWindow()); + if (client && !client->CanProcessEventsWithinSubtree(this)) + return false; + + return parent_ && IsVisible() && parent_->CanReceiveEvents(); } internal::FocusManager* Window::GetFocusManager() { @@ -491,15 +503,6 @@ bool Window::HasCapture() { return root_window && root_window->capture_window() == this; } -bool Window::StopsEventPropagation() const { - if (!stops_event_propagation_ || children_.empty()) - return false; - aura::Window::Windows::const_iterator it = - std::find_if(children_.begin(), children_.end(), - std::mem_fun(&aura::Window::IsVisible)); - return it != children_.end(); -} - void Window::SuppressPaint() { layer_->SuppressPaint(); } @@ -654,6 +657,16 @@ Window* Window::GetWindowForPoint(const gfx::Point& local_point, rend = children_.rend(); it != rend; ++it) { Window* child = *it; + + if (for_event_handling) { + // The client may not allow events to be processed by certain subtrees. + client::EventClient* client = client::GetEventClient(GetRootWindow()); + if (client && !client->CanProcessEventsWithinSubtree(child)) + continue; + } + + // We don't process events for invisible windows or those that have asked + // to ignore events. if (!child->IsVisible() || (for_event_handling && child->ignore_events_)) continue; @@ -664,9 +677,6 @@ Window* Window::GetWindowForPoint(const gfx::Point& local_point, for_event_handling); if (match) return match; - - if (for_event_handling && child->StopsEventPropagation()) - break; } return delegate_ ? this : NULL; @@ -801,15 +811,4 @@ void Window::UpdateLayerName(const std::string& name) { #endif } -bool Window::IsBehindStopEventsWindow() const { - Windows::const_iterator i = std::find(parent_->children().begin(), - parent_->children().end(), - this); - for (++i; i != parent_->children().end(); ++i) { - if ((*i)->StopsEventPropagation()) - return true; - } - return false; -} - } // namespace aura diff --git a/ui/aura/window.h b/ui/aura/window.h index 95c6c21..c50bc20 100644 --- a/ui/aura/window.h +++ b/ui/aura/window.h @@ -218,15 +218,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate { void AddObserver(WindowObserver* observer); void RemoveObserver(WindowObserver* observer); - // When set to true, this Window will stop propagation of all events targeted - // at Windows below it in the z-order, but only if this Window has children. - // This is used to implement lock-screen type functionality where we do not - // want events to be sent to running logged-in windows when the lock screen is - // displayed. - void set_stops_event_propagation(bool stops_event_propagation) { - stops_event_propagation_ = stops_event_propagation; - } - void set_ignore_events(bool ignore_events) { ignore_events_ = ignore_events; } // Sets the window to grab hits for an area extending |outer| pixels outside @@ -294,10 +285,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate { // Returns true if this window has a mouse capture. bool HasCapture(); - // Returns true if this window is currently stopping event - // propagation for any windows behind it in the z-order. - bool StopsEventPropagation() const; - // Suppresses painting window content by disgarding damaged rect and ignoring // new paint requests. void SuppressPaint(); @@ -358,8 +345,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate { // If |return_tightest| is true, returns the tightest-containing (i.e. // furthest down the hierarchy) Window containing the point; otherwise, // returns the loosest. If |for_event_handling| is true, then hit-test masks - // and StopsEventPropagation() are honored; otherwise, only bounds checks are - // performed. + // are honored; otherwise, only bounds checks are performed. Window* GetWindowForPoint(const gfx::Point& local_point, bool return_tightest, bool for_event_handling); @@ -392,10 +378,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate { // Updates the layer name with a name based on the window's name and id. void UpdateLayerName(const std::string& name); - // Returns true if this window is behind a window that stops event - // propagation. - bool IsBehindStopEventsWindow() const; - client::WindowType type_; WindowDelegate* delegate_; @@ -437,10 +419,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate { void* user_data_; - // When true, events are not sent to windows behind this one in the z-order, - // provided this window has children. See set_stops_event_propagation(). - bool stops_event_propagation_; - // Makes the window pass all events through to any windows behind it. bool ignore_events_; diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index f1bed32..9ea8a21 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc @@ -355,10 +355,6 @@ TEST_F(WindowTest, GetTopWindowContainingPoint) { scoped_ptr<Window> w311( CreateTestWindow(SK_ColorBLUE, 311, gfx::Rect(0, 0, 10, 10), w31.get())); - // The stop-event-propagation flag shouldn't have any effect on the behavior - // of this method. - w3->set_stops_event_propagation(true); - EXPECT_EQ(NULL, root->GetTopWindowContainingPoint(gfx::Point(0, 0))); EXPECT_EQ(w2.get(), root->GetTopWindowContainingPoint(gfx::Point(5, 5))); EXPECT_EQ(w2.get(), root->GetTopWindowContainingPoint(gfx::Point(10, 10))); @@ -808,58 +804,6 @@ TEST_F(WindowTest, Visibility) { EXPECT_TRUE(w3->IsVisible()); } -// When set_consume_events() is called with |true| for a Window, that Window -// should make sure that none behind it in the z-order see events if it has -// children. If it does not have children, event targeting works as usual. -TEST_F(WindowTest, StopsEventPropagation) { - TestWindowDelegate d11; - TestWindowDelegate d111; - TestWindowDelegate d121; - scoped_ptr<Window> w1(CreateTestWindowWithDelegate(NULL, 1, - gfx::Rect(0, 0, 500, 500), NULL)); - scoped_ptr<Window> w11(CreateTestWindowWithDelegate(&d11, 11, - gfx::Rect(0, 0, 500, 500), w1.get())); - scoped_ptr<Window> w111(CreateTestWindowWithDelegate(&d111, 111, - gfx::Rect(50, 50, 450, 450), w11.get())); - scoped_ptr<Window> w12(CreateTestWindowWithDelegate(NULL, 12, - gfx::Rect(0, 0, 500, 500), w1.get())); - scoped_ptr<Window> w121(CreateTestWindowWithDelegate(&d121, 121, - gfx::Rect(150, 150, 50, 50), NULL)); - - w12->set_stops_event_propagation(true); - EXPECT_EQ(w11.get(), w1->GetEventHandlerForPoint(gfx::Point(10, 10))); - - EXPECT_TRUE(w111->CanFocus()); - EXPECT_TRUE(w111->CanReceiveEvents()); - w111->Focus(); - EXPECT_EQ(w111.get(), w1->GetFocusManager()->GetFocusedWindow()); - - w12->AddChild(w121.get()); - - EXPECT_EQ(NULL, w1->GetEventHandlerForPoint(gfx::Point(10, 10))); - EXPECT_EQ(w121.get(), w1->GetEventHandlerForPoint(gfx::Point(175, 175))); - - // It should be possible to focus w121 since it is at or above the - // consumes_events_ window. - EXPECT_TRUE(w121->CanFocus()); - EXPECT_TRUE(w121->CanReceiveEvents()); - w121->Focus(); - EXPECT_EQ(w121.get(), w1->GetFocusManager()->GetFocusedWindow()); - - // An attempt to focus 111 should be ignored and w121 should retain focus, - // since a consumes_events_ window with a child is in the z-index above w111. - EXPECT_FALSE(w111->CanReceiveEvents()); - w111->Focus(); - EXPECT_EQ(w121.get(), w1->GetFocusManager()->GetFocusedWindow()); - - // Hiding w121 should make 111 focusable. - w121->Hide(); - EXPECT_TRUE(w111->CanFocus()); - EXPECT_TRUE(w111->CanReceiveEvents()); - w111->Focus(); - EXPECT_EQ(w111.get(), w1->GetFocusManager()->GetFocusedWindow()); -} - TEST_F(WindowTest, IgnoreEventsTest) { TestWindowDelegate d11; TestWindowDelegate d12; diff --git a/ui/oak/oak_aura_window_display.cc b/ui/oak/oak_aura_window_display.cc index 214a005..fce9406 100644 --- a/ui/oak/oak_aura_window_display.cc +++ b/ui/oak/oak_aura_window_display.cc @@ -32,7 +32,6 @@ ROW_ROOTWINDOW, ROW_TRANSIENTCHILDREN, ROW_TRANSIENTPARENT, ROW_USERDATA, -ROW_STOPSEVENTPROPAGATION, ROW_IGNOREEVENTS, ROW_CANFOCUS, ROW_HITTESTBOUNDSOVERRIDE, @@ -137,9 +136,6 @@ string16 OakAuraWindowDisplay::GetText(int row, int column_id) { window_->transient_parent()); case ROW_USERDATA: return PropertyWithVoidStar("User Data: ", window_->user_data()); - case ROW_STOPSEVENTPROPAGATION: - return PropertyWithBool("Stops event propagation: ", - window_->StopsEventPropagation()); case ROW_IGNOREEVENTS: return PropertyWithBool("Can receive events: ", window_->CanReceiveEvents()); |