diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-14 21:14:01 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-14 21:14:01 +0000 |
commit | f94f0f14dd3c9c49c6da8bdf3d7de19f4a6fb6b7 (patch) | |
tree | 17f77aa9323a3e1de24b6603e385301eab13d8c3 /ui/aura | |
parent | e49d616f0151b407d6b9296167facdc0655811c5 (diff) | |
download | chromium_src-f94f0f14dd3c9c49c6da8bdf3d7de19f4a6fb6b7.zip chromium_src-f94f0f14dd3c9c49c6da8bdf3d7de19f4a6fb6b7.tar.gz chromium_src-f94f0f14dd3c9c49c6da8bdf3d7de19f4a6fb6b7.tar.bz2 |
Move Aura to UI subdir.
BUG=none
TEST=none
TBR=sky
Review URL: http://codereview.chromium.org/7886042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101156 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura')
-rw-r--r-- | ui/aura/DEPS | 6 | ||||
-rw-r--r-- | ui/aura/OWNERS | 2 | ||||
-rw-r--r-- | ui/aura/aura.gyp | 98 | ||||
-rw-r--r-- | ui/aura/aura_export.h | 29 | ||||
-rw-r--r-- | ui/aura/demo/demo_main.cc | 109 | ||||
-rw-r--r-- | ui/aura/desktop.cc | 85 | ||||
-rw-r--r-- | ui/aura/desktop.h | 80 | ||||
-rw-r--r-- | ui/aura/desktop_host.h | 47 | ||||
-rw-r--r-- | ui/aura/desktop_host_linux.cc | 122 | ||||
-rw-r--r-- | ui/aura/desktop_host_win.cc | 96 | ||||
-rw-r--r-- | ui/aura/desktop_host_win.h | 60 | ||||
-rw-r--r-- | ui/aura/event.cc | 66 | ||||
-rw-r--r-- | ui/aura/event.h | 111 | ||||
-rw-r--r-- | ui/aura/event_win.cc | 222 | ||||
-rw-r--r-- | ui/aura/event_x.cc | 193 | ||||
-rw-r--r-- | ui/aura/focus_manager.cc | 32 | ||||
-rw-r--r-- | ui/aura/focus_manager.h | 37 | ||||
-rw-r--r-- | ui/aura/hit_test.h | 42 | ||||
-rw-r--r-- | ui/aura/root_window.cc | 58 | ||||
-rw-r--r-- | ui/aura/root_window.h | 43 | ||||
-rw-r--r-- | ui/aura/run_all_unittests.cc | 9 | ||||
-rw-r--r-- | ui/aura/test_suite.cc | 32 | ||||
-rw-r--r-- | ui/aura/test_suite.h | 22 | ||||
-rw-r--r-- | ui/aura/window.cc | 175 | ||||
-rw-r--r-- | ui/aura/window.h | 166 | ||||
-rw-r--r-- | ui/aura/window_delegate.h | 53 | ||||
-rw-r--r-- | ui/aura/window_manager.cc | 66 | ||||
-rw-r--r-- | ui/aura/window_manager.h | 47 | ||||
-rw-r--r-- | ui/aura/window_unittest.cc | 281 |
29 files changed, 2389 insertions, 0 deletions
diff --git a/ui/aura/DEPS b/ui/aura/DEPS new file mode 100644 index 0000000..7ac5dd0 --- /dev/null +++ b/ui/aura/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+grit/ui_resources.h", + "+grit/ui_strings.h", + "+skia/ext", + "+ui", +] diff --git a/ui/aura/OWNERS b/ui/aura/OWNERS new file mode 100644 index 0000000..3b48ffc --- /dev/null +++ b/ui/aura/OWNERS @@ -0,0 +1,2 @@ +ben@chromium.org +sky@chromium.org diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp new file mode 100644 index 0000000..8e9ef7f --- /dev/null +++ b/ui/aura/aura.gyp @@ -0,0 +1,98 @@ +# Copyright (c) 2011 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'aura', + 'type': '<(component)', + 'dependencies': [ + '../../base/base.gyp:base', + '../../base/base.gyp:base_i18n', + '../../skia/skia.gyp:skia', + '../gfx/compositor/compositor.gyp:compositor', + '../ui.gyp:gfx_resources', + '../ui.gyp:ui', + '../ui.gyp:ui_resources', + ], + 'defines': [ + 'AURA_IMPLEMENTATION', + ], + 'sources': [ + 'desktop_host.h', + 'desktop_host_linux.cc', + 'desktop_host_win.cc', + 'desktop_host_win.h', + 'desktop.cc', + 'desktop.h', + 'event.cc', + 'event.h', + 'event_win.cc', + 'event_x.cc', + 'focus_manager.cc', + 'focus_manager.h', + 'hit_test.h', + 'root_window.cc', + 'root_window.h', + 'window.cc', + 'window.h', + 'window_delegate.h', + 'window_manager.cc', + 'window_manager.h', + ], + }, + { + 'target_name': 'aura_demo', + 'type': 'executable', + 'dependencies': [ + '../../base/base.gyp:base', + '../../base/base.gyp:base_i18n', + '../../skia/skia.gyp:skia', + '../../third_party/icu/icu.gyp:icui18n', + '../../third_party/icu/icu.gyp:icuuc', + '../gfx/compositor/compositor.gyp:compositor', + '../ui.gyp:gfx_resources', + '../ui.gyp:ui', + '../ui.gyp:ui_resources', + 'aura', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'demo/demo_main.cc', + '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc', + '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc', + ], + }, + { + 'target_name': 'aura_unittests', + 'type': 'executable', + 'dependencies': [ + '<(DEPTH)/base/base.gyp:test_support_base', + '<(DEPTH)/chrome/chrome.gyp:packed_resources', + '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(DEPTH)/ui/ui.gyp:gfx_resources', + '<(DEPTH)/ui/ui.gyp:ui', + '<(DEPTH)/ui/ui.gyp:ui_resources', + 'aura', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'window_unittest.cc', + 'run_all_unittests.cc', + 'test_suite.cc', + 'test_suite.h', + '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc', + '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc', + ], + }, + ], +} diff --git a/ui/aura/aura_export.h b/ui/aura/aura_export.h new file mode 100644 index 0000000..6b75b50 --- /dev/null +++ b/ui/aura/aura_export.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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_AURA_EXPORT_H +#define UI_AURA_AURA_EXPORT_H +#pragma once + +// Defines AURA_EXPORT so that functionality implemented by the aura module +// can be exported to consumers. + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(AURA_IMPLEMENTATION) +#define AURA_EXPORT __declspec(dllexport) +#else +#define AURA_EXPORT __declspec(dllimport) +#endif // defined(AURA_IMPLEMENTATION) + +#else // defined(WIN32) +#define AURA_EXPORT __attribute__((visibility("default"))) +#endif + +#else // defined(COMPONENT_BUILD) +#define AURA_EXPORT +#endif + +#endif // UI_AURA_AURA_EXPORT_H diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc new file mode 100644 index 0000000..5233e9c --- /dev/null +++ b/ui/aura/demo/demo_main.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011 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 "aura/desktop.h" +#include "aura/event.h" +#include "aura/window.h" +#include "aura/window_delegate.h" +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/i18n/icu_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "third_party/skia/include/core/SkXfermode.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_paths.h" +#include "ui/gfx/canvas_skia.h" +#include "ui/gfx/rect.h" + +#if defined(USE_X11) +#include "aura/hit_test.h" +#include "base/message_pump_x.h" +#endif + +namespace { + +// Trivial WindowDelegate implementation that draws a colored background. +class DemoWindowDelegate : public aura::WindowDelegate { + public: + explicit DemoWindowDelegate(SkColor color) : color_(color) {} + + virtual void OnFocus() OVERRIDE {} + virtual void OnBlur() OVERRIDE {} + virtual bool OnKeyEvent(aura::KeyEvent* event) OVERRIDE { + return false; + } + + virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE { + return HTCAPTION; + } + + virtual bool OnMouseEvent(aura::MouseEvent* event) OVERRIDE { + return true; + } + + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + canvas->AsCanvasSkia()->drawColor(color_, SkXfermode::kSrc_Mode); + } + + virtual void OnWindowDestroying() OVERRIDE {} + virtual void OnWindowDestroyed() OVERRIDE {} + + private: + SkColor color_; + + DISALLOW_COPY_AND_ASSIGN(DemoWindowDelegate); +}; + + +} // namespace + +int main(int argc, char** argv) { + CommandLine::Init(argc, argv); + + // The exit manager is in charge of calling the dtors of singleton objects. + base::AtExitManager exit_manager; + + ui::RegisterPathProvider(); + icu_util::Initialize(); + ResourceBundle::InitSharedInstance("en-US"); + +#if defined(USE_X11) + base::MessagePumpX::DisableGtkMessagePump(); +#endif + + // Create the message-loop here before creating the desktop. + MessageLoop message_loop(MessageLoop::TYPE_UI); + + aura::Desktop::GetInstance(); + + // Create a hierarchy of test windows. + DemoWindowDelegate window_delegate1(SK_ColorBLUE); + aura::Window window1(&window_delegate1); + window1.set_id(1); + window1.Init(); + window1.SetBounds(gfx::Rect(100, 100, 400, 400), 0); + window1.SetVisibility(aura::Window::VISIBILITY_SHOWN); + window1.SetParent(NULL); + + DemoWindowDelegate window_delegate2(SK_ColorRED); + aura::Window window2(&window_delegate2); + window2.set_id(2); + window2.Init(); + window2.SetBounds(gfx::Rect(200, 200, 350, 350), 0); + window2.SetVisibility(aura::Window::VISIBILITY_SHOWN); + window2.SetParent(NULL); + + DemoWindowDelegate window_delegate3(SK_ColorGREEN); + aura::Window window3(&window_delegate3); + window3.set_id(3); + window3.Init(); + window3.SetBounds(gfx::Rect(10, 10, 50, 50), 0); + window3.SetVisibility(aura::Window::VISIBILITY_SHOWN); + window3.SetParent(&window2); + + aura::Desktop::GetInstance()->Run(); + return 0; +} + diff --git a/ui/aura/desktop.cc b/ui/aura/desktop.cc new file mode 100644 index 0000000..9e7cca2 --- /dev/null +++ b/ui/aura/desktop.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2011 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/desktop.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "ui/aura/desktop_host.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/gfx/compositor/compositor.h" +#include "ui/gfx/compositor/layer.h" + +namespace aura { + +// static +Desktop* Desktop::instance_ = NULL; + +Desktop::Desktop() + : host_(aura::DesktopHost::Create(gfx::Rect(200, 200, 1024, 768))), + ALLOW_THIS_IN_INITIALIZER_LIST(schedule_paint_(this)) { + DCHECK(MessageLoopForUI::current()) + << "The UI message loop must be initialized first."; + compositor_ = ui::Compositor::Create(this, host_->GetAcceleratedWidget(), + host_->GetSize()); + host_->SetDesktop(this); + DCHECK(compositor_.get()); + window_.reset(new internal::RootWindow); +} + +Desktop::~Desktop() { + if (instance_ == this) + instance_ = NULL; +} + +void Desktop::Show() { + host_->Show(); +} + +void Desktop::SetSize(const gfx::Size& size) { + host_->SetSize(size); +} + +void Desktop::Run() { + Show(); + MessageLoopForUI::current()->Run(host_.get()); +} + +void Desktop::Draw() { + compositor_->Draw(false); +} + +bool Desktop::OnMouseEvent(const MouseEvent& event) { + return window_->HandleMouseEvent(event); +} + +bool Desktop::OnKeyEvent(const KeyEvent& event) { + return window_->HandleKeyEvent(event); +} + +void Desktop::OnHostResized(const gfx::Size& size) { + gfx::Rect bounds(window_->bounds().origin(), size); + window_->SetBounds(bounds, 0); + compositor_->WidgetSizeChanged(size); +} + +void Desktop::ScheduleCompositorPaint() { + if (schedule_paint_.empty()) { + MessageLoop::current()->PostTask(FROM_HERE, + schedule_paint_.NewRunnableMethod(&Desktop::Draw)); + } +} + +// static +Desktop* Desktop::GetInstance() { + if (!instance_) { + instance_ = new Desktop; + instance_->window_->Init(); + instance_->compositor()->set_root_layer(instance_->window_->layer()); + } + return instance_; +} + +} // namespace aura diff --git a/ui/aura/desktop.h b/ui/aura/desktop.h new file mode 100644 index 0000000..089ed4e --- /dev/null +++ b/ui/aura/desktop.h @@ -0,0 +1,80 @@ +// Copyright (c) 2011 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_DESKTOP_H_ +#define UI_AURA_DESKTOP_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/task.h" +#include "ui/aura/root_window.h" +#include "ui/aura/aura_export.h" +#include "ui/gfx/compositor/compositor.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Size; +} + +namespace aura { + +class DesktopHost; +class MouseEvent; + +// Desktop is responsible for hosting a set of windows. +class AURA_EXPORT Desktop : public ui::CompositorDelegate { + public: + Desktop(); + ~Desktop(); + + // Shows the desktop host. + void Show(); + + // Sets the size of the desktop. + void SetSize(const gfx::Size& size); + + // Shows the desktop host and runs an event loop for it. + void Run(); + + // Draws the necessary set of windows. + void Draw(); + + // Handles a mouse event. Returns true if handled. + bool OnMouseEvent(const MouseEvent& event); + + // Handles a key event. Returns true if handled. + bool OnKeyEvent(const KeyEvent& event); + + // Called when the host changes size. + void OnHostResized(const gfx::Size& size); + + // Compositor we're drawing to. + ui::Compositor* compositor() { return compositor_.get(); } + + Window* window() { return window_.get(); } + + static Desktop* GetInstance(); + + private: + // Overridden from ui::CompositorDelegate + virtual void ScheduleCompositorPaint(); + + scoped_refptr<ui::Compositor> compositor_; + + scoped_ptr<internal::RootWindow> window_; + + scoped_ptr<DesktopHost> host_; + + static Desktop* instance_; + + // Used to schedule painting. + ScopedRunnableMethodFactory<Desktop> schedule_paint_; + + DISALLOW_COPY_AND_ASSIGN(Desktop); +}; + +} // namespace aura + +#endif // UI_AURA_DESKTOP_H_ diff --git a/ui/aura/desktop_host.h b/ui/aura/desktop_host.h new file mode 100644 index 0000000..8c2cfa6 --- /dev/null +++ b/ui/aura/desktop_host.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 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_DESKTOP_HOST_H_ +#define UI_AURA_DESKTOP_HOST_H_ +#pragma once + +#include "base/message_loop.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Rect; +class Size; +} + +namespace aura { + +class Desktop; + +// DesktopHost bridges between a native window and the embedded Desktop. It +// provides the accelerated widget and maps events from the native os to aura. +class DesktopHost : public MessageLoop::Dispatcher { + public: + virtual ~DesktopHost() {} + + // Creates a new DesktopHost. The caller owns the returned value. + static DesktopHost* Create(const gfx::Rect& bounds); + + // Sets the Desktop this DesktopHost is hosting. DesktopHost does not own the + // Desktop. + virtual void SetDesktop(Desktop* desktop) = 0; + + // Returns the accelerated widget. + virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; + + // Shows the DesktopHost. + virtual void Show() = 0; + + // Gets/Sets the size of the DesktopHost. + virtual gfx::Size GetSize() = 0; + virtual void SetSize(const gfx::Size& size) = 0; +}; + +} // namespace aura + +#endif // UI_AURA_DESKTOP_HOST_H_ diff --git a/ui/aura/desktop_host_linux.cc b/ui/aura/desktop_host_linux.cc new file mode 100644 index 0000000..a08d67a --- /dev/null +++ b/ui/aura/desktop_host_linux.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2011 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/desktop_host.h" + +#include "base/message_loop.h" +#include "base/message_pump_x.h" +#include "ui/aura/desktop.h" +#include "ui/aura/event.h" + +#include <X11/Xlib.h> + +namespace aura { + +namespace { + +class DesktopHostLinux : public DesktopHost { + public: + explicit DesktopHostLinux(const gfx::Rect& bounds); + virtual ~DesktopHostLinux(); + + private: + // base::MessageLoop::Dispatcher Override. + virtual DispatchStatus Dispatch(XEvent* xev) OVERRIDE; + + // DesktopHost Overrides. + virtual void SetDesktop(Desktop* desktop) OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void SetSize(const gfx::Size& size) OVERRIDE; + + Desktop* desktop_; + + // The display and the native X window hosting the desktop. + Display* xdisplay_; + ::Window xwindow_; + + // The size of |xwindow_|. + gfx::Rect bounds_; + + DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); +}; + +DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) + : desktop_(NULL), + xdisplay_(NULL), + xwindow_(0), + bounds_(bounds) { + // This assumes that the message-pump creates and owns the display. + xdisplay_ = base::MessagePumpX::GetDefaultXDisplay(); + xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), + bounds.x(), bounds.y(), + bounds.width(), bounds.height(), + 0, 0, 0); + XMapWindow(xdisplay_, xwindow_); + + long event_mask = ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask | + ExposureMask | VisibilityChangeMask | + StructureNotifyMask | PropertyChangeMask; + XSelectInput(xdisplay_, xwindow_, event_mask); + XFlush(xdisplay_); +} + +DesktopHostLinux::~DesktopHostLinux() { + XDestroyWindow(xdisplay_, xwindow_); +} + +base::MessagePumpDispatcher::DispatchStatus DesktopHostLinux::Dispatch( + XEvent* xev) { + bool handled = false; + switch (xev->type) { + case Expose: + desktop_->Draw(); + handled = true; + break; + case KeyPress: + case KeyRelease: { + KeyEvent keyev(xev); + handled = desktop_->OnKeyEvent(keyev); + break; + } + case ButtonPress: + case ButtonRelease: + case MotionNotify: { + MouseEvent mouseev(xev); + handled = desktop_->OnMouseEvent(mouseev); + break; + } + } + return handled ? EVENT_PROCESSED : EVENT_IGNORED; +} + +void DesktopHostLinux::SetDesktop(Desktop* desktop) { + desktop_ = desktop; +} + +gfx::AcceleratedWidget DesktopHostLinux::GetAcceleratedWidget() { + return xwindow_; +} + +void DesktopHostLinux::Show() { +} + +gfx::Size DesktopHostLinux::GetSize() { + return bounds_.size(); +} + +void DesktopHostLinux::SetSize(const gfx::Size& size) { + XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); +} + +} // namespace + +// static +DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { + return new DesktopHostLinux(bounds); +} + +} // namespace aura diff --git a/ui/aura/desktop_host_win.cc b/ui/aura/desktop_host_win.cc new file mode 100644 index 0000000..ef1de50 --- /dev/null +++ b/ui/aura/desktop_host_win.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2011 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/desktop_host_win.h" + +#include "base/message_loop.h" +#include "ui/aura/desktop.h" +#include "ui/aura/event.h" + +namespace aura { + +// static +DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { + return new DesktopHostWin(bounds); +} + +DesktopHostWin::DesktopHostWin(const gfx::Rect& bounds) : desktop_(NULL) { + Init(NULL, bounds); +} + +DesktopHostWin::~DesktopHostWin() { + DestroyWindow(hwnd()); +} + +bool DesktopHostWin::Dispatch(const MSG& msg) { + TranslateMessage(&msg); + DispatchMessage(&msg); + return true; +} + +void DesktopHostWin::SetDesktop(Desktop* desktop) { + desktop_ = desktop; +} + +gfx::AcceleratedWidget DesktopHostWin::GetAcceleratedWidget() { + return hwnd(); +} + +void DesktopHostWin::Show() { + ShowWindow(hwnd(), SW_SHOWNORMAL); +} + +gfx::Size DesktopHostWin::GetSize() { + RECT r; + GetClientRect(hwnd(), &r); + return gfx::Rect(r).size(); +} + +void DesktopHostWin::SetSize(const gfx::Size& size) { + SetWindowPos( + hwnd(), + NULL, + 0, + 0, + size.width(), + size.height(), + SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION); +} + +void DesktopHostWin::OnClose() { + // TODO: this obviously shouldn't be here. + MessageLoopForUI::current()->Quit(); +} + +LRESULT DesktopHostWin::OnKeyEvent(UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = { hwnd(), message, w_param, l_param }; + SetMsgHandled(desktop_->OnKeyEvent(KeyEvent(msg))); + return 0; +} + +LRESULT DesktopHostWin::OnMouseRange(UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = { hwnd(), message, w_param, l_param, 0, + { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } }; + MouseEvent event(msg); + bool handled = false; + if (!(event.flags() & ui::EF_IS_NON_CLIENT)) + handled = desktop_->OnMouseEvent(event); + SetMsgHandled(handled); + return 0; +} + +void DesktopHostWin::OnPaint(HDC dc) { + desktop_->Draw(); + ValidateRect(hwnd(), NULL); +} + +void DesktopHostWin::OnSize(UINT param, const CSize& size) { + desktop_->OnHostResized(gfx::Size(size.cx, size.cy)); +} + +} // namespace aura diff --git a/ui/aura/desktop_host_win.h b/ui/aura/desktop_host_win.h new file mode 100644 index 0000000..78e34eb --- /dev/null +++ b/ui/aura/desktop_host_win.h @@ -0,0 +1,60 @@ +// Copyright (c) 2011 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_DESKTOP_HOST_WIN_H_ +#define UI_AURA_DESKTOP_HOST_WIN_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "ui/aura/desktop_host.h" +#include "ui/base/win/window_impl.h" + +namespace aura { + +class DesktopHostWin : public DesktopHost, public ui::WindowImpl { + public: + explicit DesktopHostWin(const gfx::Rect& bounds); + virtual ~DesktopHostWin(); + + // MessageLoop::Dispatcher: + virtual bool Dispatch(const MSG& msg); + + // DesktopHost: + virtual void SetDesktop(Desktop* desktop) OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void SetSize(const gfx::Size& size) OVERRIDE; + + private: + BEGIN_MSG_MAP_EX(DesktopHostWin) + // Range handlers must go first! + MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) + MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange) + + // Key events. + MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent) + MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent) + MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent) + MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent) + + MSG_WM_CLOSE(OnClose) + MSG_WM_PAINT(OnPaint) + MSG_WM_SIZE(OnSize) + END_MSG_MAP() + + void OnClose(); + LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param); + LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param); + void OnPaint(HDC dc); + void OnSize(UINT param, const CSize& size); + + Desktop* desktop_; + + DISALLOW_COPY_AND_ASSIGN(DesktopHostWin); +}; + +} // namespace aura + +#endif // UI_AURA_DESKTOP_HOST_WIN_H_ diff --git a/ui/aura/event.cc b/ui/aura/event.cc new file mode 100644 index 0000000..ee79fce --- /dev/null +++ b/ui/aura/event.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 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/event.h" + +#include "ui/aura/window.h" + +namespace aura { + +Event::Event(ui::EventType type, int flags) + : type_(type), + time_stamp_(base::Time::NowFromSystemTime()), + flags_(flags) { + Init(); +} + +Event::Event(NativeEvent native_event, ui::EventType type, int flags) + : type_(type), + time_stamp_(base::Time::NowFromSystemTime()), + flags_(flags) { + InitWithNativeEvent(native_event); +} + +Event::Event(const Event& copy) + : native_event_(copy.native_event_), + type_(copy.type_), + time_stamp_(copy.time_stamp_), + flags_(copy.flags_) { +} + +LocatedEvent::LocatedEvent(const LocatedEvent& model, + Window* source, + Window* target) + : Event(model), + location_(model.location_) { + if (target && target != source) + Window::ConvertPointToWindow(source, target, &location_); +} + +LocatedEvent::LocatedEvent(ui::EventType type, + const gfx::Point& location, + int flags) + : Event(type, flags), + location_(location) { +} + +MouseEvent::MouseEvent(const MouseEvent& model, Window* source, Window* target) + : LocatedEvent(model, source, target) { +} + +MouseEvent::MouseEvent(ui::EventType type, + const gfx::Point& location, + int flags) + : LocatedEvent(type, location, flags) { +} + +KeyEvent::KeyEvent(ui::EventType type, + ui::KeyboardCode key_code, + int flags) + : Event(type, flags), + key_code_(key_code) { +} + +} // namespace aura + diff --git a/ui/aura/event.h b/ui/aura/event.h new file mode 100644 index 0000000..ed3a938 --- /dev/null +++ b/ui/aura/event.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011 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_EVENT_H_ +#define UI_AURA_EVENT_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/time.h" +#include "ui/aura/aura_export.h" +#include "ui/base/events.h" +#include "ui/base/keycodes/keyboard_codes.h" +#include "ui/gfx/point.h" + +#if defined(USE_X11) +typedef union _XEvent XEvent; +#endif + +namespace aura { + +#if defined(OS_WIN) +typedef MSG NativeEvent; +#elif defined(USE_X11) +typedef XEvent* NativeEvent; +#endif + +class Window; + +class AURA_EXPORT Event { + public: + const NativeEvent& native_event() const { return native_event_; } + ui::EventType type() const { return type_; } + const base::Time& time_stamp() const { return time_stamp_; } + int flags() const { return flags_; } + + protected: + Event(ui::EventType type, int flags); + Event(NativeEvent native_event, ui::EventType type, int flags); + Event(const Event& copy); + + private: + void operator=(const Event&); + + // Safely initializes the native event members of this class. + void Init(); + void InitWithNativeEvent(NativeEvent native_event); + + NativeEvent native_event_; + ui::EventType type_; + base::Time time_stamp_; + int flags_; +}; + +class AURA_EXPORT LocatedEvent : public Event { + public: + int x() const { return location_.x(); } + int y() const { return location_.y(); } + gfx::Point location() const { return location_; } + + protected: + explicit LocatedEvent(NativeEvent native_event); + + // Create a new LocatedEvent which is identical to the provided model. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + LocatedEvent(const LocatedEvent& model, Window* source, Window* target); + + // Used for synthetic events in testing. + LocatedEvent(ui::EventType type, const gfx::Point& location, int flags); + + gfx::Point location_; + + private: + DISALLOW_COPY_AND_ASSIGN(LocatedEvent); +}; + +class AURA_EXPORT MouseEvent : public LocatedEvent { + public: + explicit MouseEvent(NativeEvent native_event); + + // Create a new MouseEvent which is identical to the provided model. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + MouseEvent(const MouseEvent& model, Window* source, Window* target); + + // Used for synthetic events in testing. + MouseEvent(ui::EventType type, const gfx::Point& location, int flags); + + private: + DISALLOW_COPY_AND_ASSIGN(MouseEvent); +}; + +class AURA_EXPORT KeyEvent : public Event { + public: + explicit KeyEvent(NativeEvent native_event); + + // Used for synthetic events in testing. + KeyEvent(ui::EventType type, + ui::KeyboardCode key_code, + int flags); + + ui::KeyboardCode key_code() const { return key_code_; } + + private: + ui::KeyboardCode key_code_; +}; + +} // namespace aura + +#endif // UI_AURA_EVENT_H_ diff --git a/ui/aura/event_win.cc b/ui/aura/event_win.cc new file mode 100644 index 0000000..6bb6a78 --- /dev/null +++ b/ui/aura/event_win.cc @@ -0,0 +1,222 @@ +// Copyright (c) 2011 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/event.h" + +#include "base/logging.h" +#include "ui/base/keycodes/keyboard_code_conversion_win.h" + +namespace aura { + +namespace { + +bool IsClientMouseEvent(const NativeEvent& native_event) { + return native_event.message == WM_MOUSELEAVE || + native_event.message == WM_MOUSEHOVER || + (native_event.message >= WM_MOUSEFIRST && + native_event.message <= WM_MOUSELAST); +} + +bool IsNonClientMouseEvent(const NativeEvent& native_event) { + return native_event.message == WM_NCMOUSELEAVE || + native_event.message == WM_NCMOUSEHOVER || + (native_event.message >= WM_NCMOUSEMOVE && + native_event.message <= WM_NCXBUTTONDBLCLK); +} + +// Returns a mask corresponding to the set of modifier keys that are currently +// pressed. Windows key messages don't come with control key state as parameters +// as with mouse messages, so we need to explicitly ask for these states. +int GetKeyStateFlags() { + int flags = 0; + flags |= (GetKeyState(VK_MENU) & 0x80)? ui::EF_ALT_DOWN : 0; + flags |= (GetKeyState(VK_SHIFT) & 0x80)? ui::EF_SHIFT_DOWN : 0; + flags |= (GetKeyState(VK_CONTROL) & 0x80)? ui::EF_CONTROL_DOWN : 0; + return flags; +} + +bool IsButtonDown(NativeEvent native_event) { + return (native_event.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | + MK_XBUTTON1 | MK_XBUTTON2)) != 0; +} + +// Convert windows message identifiers to Event types. +ui::EventType EventTypeFromNative(NativeEvent native_event) { + switch (native_event.message) { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_CHAR: + return ui::ET_KEY_PRESSED; + case WM_KEYUP: + case WM_SYSKEYUP: + return ui::ET_KEY_RELEASED; + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCXBUTTONDBLCLK: + case WM_NCXBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_XBUTTONDBLCLK: + case WM_XBUTTONDOWN: + return ui::ET_MOUSE_PRESSED; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONUP: + case WM_NCRBUTTONUP: + case WM_NCXBUTTONUP: + case WM_RBUTTONUP: + case WM_XBUTTONUP: + return ui::ET_MOUSE_RELEASED; + case WM_MOUSEMOVE: + return IsButtonDown(native_event) ? ui::ET_MOUSE_DRAGGED : + ui::ET_MOUSE_MOVED; + case WM_NCMOUSEMOVE: + return ui::ET_MOUSE_MOVED; + case WM_MOUSEWHEEL: + return ui::ET_MOUSEWHEEL; + case WM_MOUSELEAVE: + case WM_NCMOUSELEAVE: + return ui::ET_MOUSE_EXITED; + default: + NOTREACHED(); + } + return ui::ET_UNKNOWN; +} + +// Get views::Event flags from a native Windows message +int EventFlagsFromNative(NativeEvent native_event) { + int flags = 0; + + // TODO(msw): ORing the pressed/released button into the flags is _wrong_. + // It makes it impossible to tell which button was modified when multiple + // buttons are/were held down. We need to instead put the modified button into + // a separate member on the MouseEvent, then audit all consumers of + // MouseEvents to fix them to use the resulting values correctly. + switch (native_event.message) { + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + native_event.wParam |= MK_LBUTTON; + break; + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + native_event.wParam |= MK_MBUTTON; + break; + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + native_event.wParam |= MK_RBUTTON; + break; + case WM_NCXBUTTONDBLCLK: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONUP: + case WM_XBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + native_event.wParam |= MK_XBUTTON1; + break; + } + + // Check if the event occurred in the non-client area. + if (IsNonClientMouseEvent(native_event)) + flags |= ui::EF_IS_NON_CLIENT; + + // Check for double click events. + switch (native_event.message) { + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDBLCLK: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: + flags |= ui::EF_IS_DOUBLE_CLICK; + break; + } + + // For non-client mouse message, the WPARAM value represents the hit test + // result, instead of the key state. + switch (native_event.message) { + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + flags |= ui::EF_LEFT_BUTTON_DOWN; + break; + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + flags |= ui::EF_MIDDLE_BUTTON_DOWN; + break; + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + flags |= ui::EF_RIGHT_BUTTON_DOWN; + break; + default: { + UINT win_flags = GET_KEYSTATE_WPARAM(native_event.wParam); + flags |= (win_flags & MK_CONTROL) ? ui::EF_CONTROL_DOWN : 0; + flags |= (win_flags & MK_SHIFT) ? ui::EF_SHIFT_DOWN : 0; + flags |= (GetKeyState(VK_MENU) < 0) ? ui::EF_ALT_DOWN : 0; + flags |= (win_flags & MK_LBUTTON) ? ui::EF_LEFT_BUTTON_DOWN : 0; + flags |= (win_flags & MK_MBUTTON) ? ui::EF_MIDDLE_BUTTON_DOWN : 0; + flags |= (win_flags & MK_RBUTTON) ? ui::EF_RIGHT_BUTTON_DOWN : 0; + break; + } + } + + return flags; +} + +} // namespace + +void Event::Init() { + ZeroMemory(&native_event_, sizeof(native_event_)); +} + +void Event::InitWithNativeEvent(NativeEvent native_event) { + native_event_ = native_event; +} + +LocatedEvent::LocatedEvent(NativeEvent native_event) + : Event(native_event, EventTypeFromNative(native_event), + EventFlagsFromNative(native_event)), + location_(native_event.pt.x, native_event.pt.y) { +} + +MouseEvent::MouseEvent(NativeEvent native_event) + : LocatedEvent(native_event) { + if (IsNonClientMouseEvent(native_event)) { + // Non-client message. The position is contained in a POINTS structure in + // LPARAM, and is in screen coordinates so we have to convert to client. + POINT native_point = location_.ToPOINT(); + ScreenToClient(native_event.hwnd, &native_point); + location_ = gfx::Point(native_point); + } +} + +KeyEvent::KeyEvent(NativeEvent native_event) + : Event(native_event, + EventTypeFromNative(native_event), + GetKeyStateFlags()), + key_code_(ui::KeyboardCodeForWindowsKeyCode(native_event.wParam)) { +} + +} // namespace aura diff --git a/ui/aura/event_x.cc b/ui/aura/event_x.cc new file mode 100644 index 0000000..323d6a5 --- /dev/null +++ b/ui/aura/event_x.cc @@ -0,0 +1,193 @@ +// Copyright (c) 2011 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/event.h" + +#include <X11/Xlib.h> +#include <X11/extensions/XInput2.h> + +#include "base/logging.h" +#include "ui/base/keycodes/keyboard_code_conversion_x.h" + +namespace aura { + +namespace { + +int GetEventFlagsFromXState(unsigned int state) { + int flags = 0; + if (state & ControlMask) + flags |= ui::EF_CONTROL_DOWN; + if (state & ShiftMask) + flags |= ui::EF_SHIFT_DOWN; + if (state & Mod1Mask) + flags |= ui::EF_ALT_DOWN; + if (state & LockMask) + flags |= ui::EF_CAPS_LOCK_DOWN; + if (state & Button1Mask) + flags |= ui::EF_LEFT_BUTTON_DOWN; + if (state & Button2Mask) + flags |= ui::EF_MIDDLE_BUTTON_DOWN; + if (state & Button3Mask) + flags |= ui::EF_RIGHT_BUTTON_DOWN; + + return flags; +} + +// Get the event flag for the button in XButtonEvent. During a ButtonPress +// event, |state| in XButtonEvent does not include the button that has just been +// pressed. Instead |state| contains flags for the buttons (if any) that had +// already been pressed before the current button, and |button| stores the most +// current pressed button. So, if you press down left mouse button, and while +// pressing it down, press down the right mouse button, then for the latter +// event, |state| would have Button1Mask set but not Button3Mask, and |button| +// would be 3. +int GetEventFlagsForButton(int button) { + switch (button) { + case 1: + return ui::EF_LEFT_BUTTON_DOWN; + case 2: + return ui::EF_MIDDLE_BUTTON_DOWN; + case 3: + return ui::EF_RIGHT_BUTTON_DOWN; + } + + DLOG(WARNING) << "Unexpected button (" << button << ") received."; + return 0; +} + +int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { + int buttonflags = 0; + + for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { + if (XIMaskIsSet(xievent->buttons.mask, i)) { + buttonflags |= GetEventFlagsForButton(i); + } + } + + return buttonflags; +} + +ui::EventType EventTypeFromNative(NativeEvent native_event) { + switch (native_event->type) { + case KeyPress: + return ui::ET_KEY_PRESSED; + case KeyRelease: + return ui::ET_KEY_RELEASED; + case ButtonPress: + if (native_event->xbutton.button == 4 || + native_event->xbutton.button == 5) + return ui::ET_MOUSEWHEEL; + return ui::ET_MOUSE_PRESSED; + case ButtonRelease: + if (native_event->xbutton.button == 4 || + native_event->xbutton.button == 5) + return ui::ET_MOUSEWHEEL; + return ui::ET_MOUSE_RELEASED; + case MotionNotify: + if (native_event->xmotion.state & + (Button1Mask | Button2Mask | Button3Mask)) + return ui::ET_MOUSE_DRAGGED; + return ui::ET_MOUSE_MOVED; + case GenericEvent: { + XIDeviceEvent* xievent = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + // TODO(sad): Determine if sourceid is a touch device. + switch (xievent->evtype) { + case XI_ButtonPress: + return (xievent->detail == 4 || xievent->detail == 5) ? + ui::ET_MOUSEWHEEL : ui::ET_MOUSE_PRESSED; + case XI_ButtonRelease: + return (xievent->detail == 4 || xievent->detail == 5) ? + ui::ET_MOUSEWHEEL : ui::ET_MOUSE_RELEASED; + case XI_Motion: + return GetButtonMaskForX2Event(xievent) ? ui::ET_MOUSE_DRAGGED : + ui::ET_MOUSE_MOVED; + } + } + default: + NOTREACHED(); + break; + } + return ui::ET_UNKNOWN; +} + +gfx::Point GetEventLocation(XEvent* xev) { + switch (xev->type) { + case ButtonPress: + case ButtonRelease: + return gfx::Point(xev->xbutton.x, xev->xbutton.y); + + case MotionNotify: + return gfx::Point(xev->xmotion.x, xev->xmotion.y); + + case GenericEvent: { + XIDeviceEvent* xievent = + static_cast<XIDeviceEvent*>(xev->xcookie.data); + return gfx::Point(static_cast<int>(xievent->event_x), + static_cast<int>(xievent->event_y)); + } + } + + return gfx::Point(); +} + +int GetLocatedEventFlags(XEvent* xev) { + switch (xev->type) { + case ButtonPress: + case ButtonRelease: + return GetEventFlagsFromXState(xev->xbutton.state) | + GetEventFlagsForButton(xev->xbutton.button); + + case MotionNotify: + return GetEventFlagsFromXState(xev->xmotion.state); + + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data); + bool touch = false; // TODO(sad): Determine if xievent->sourceid is a + // touch device. + switch (xievent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + return GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective) | + (touch ? 0 : GetEventFlagsForButton(xievent->detail)); + + case XI_Motion: + return GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective); + } + } + } + + return 0; +} + +} // namespace + +void Event::Init() { + memset(&native_event_, 0, sizeof(native_event_)); +} + +void Event::InitWithNativeEvent(NativeEvent native_event) { + native_event_ = native_event; +} + +LocatedEvent::LocatedEvent(NativeEvent native_event) + : Event(native_event, EventTypeFromNative(native_event), + GetLocatedEventFlags(native_event)), + location_(GetEventLocation(native_event)) { +} + +MouseEvent::MouseEvent(NativeEvent native_event) + : LocatedEvent(native_event) { +} + +KeyEvent::KeyEvent(NativeEvent native_event) + : Event(native_event, + EventTypeFromNative(native_event), + GetEventFlagsFromXState(native_event->xbutton.state)), + key_code_(ui::KeyboardCodeFromXKeyEvent(native_event)) { +} + +} // namespace aura diff --git a/ui/aura/focus_manager.cc b/ui/aura/focus_manager.cc new file mode 100644 index 0000000..9652f1c --- /dev/null +++ b/ui/aura/focus_manager.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2011 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/focus_manager.h" + +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" + +namespace aura { +namespace internal { + +FocusManager::FocusManager(Window* owner) + : owner_(owner), + focused_window_(NULL) { +} + +FocusManager::~FocusManager() { +} + +void FocusManager::SetFocusedWindow(Window* focused_window) { + if (focused_window == focused_window_) + return; + if (focused_window_) + focused_window_->delegate()->OnBlur(); + focused_window_ = focused_window; + if (focused_window_) + focused_window_->delegate()->OnFocus(); +} + +} // namespace internal +} // namespace aura diff --git a/ui/aura/focus_manager.h b/ui/aura/focus_manager.h new file mode 100644 index 0000000..f6249b6 --- /dev/null +++ b/ui/aura/focus_manager.h @@ -0,0 +1,37 @@ +// Copyright (c) 2011 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_FOCUS_MANAGER_H_ +#define UI_AURA_FOCUS_MANAGER_H_ +#pragma once + +#include "base/basictypes.h" + +namespace aura { +class Window; + +namespace internal { + +// The FocusManager, when attached to a Window, tracks changes to keyboard input +// focus within that Window's hierarchy. +class FocusManager { + public: + explicit FocusManager(Window* owner); + ~FocusManager(); + + void SetFocusedWindow(Window* window); + + Window* focused_window() { return focused_window_; } + + private: + Window* owner_; + Window* focused_window_; + + DISALLOW_COPY_AND_ASSIGN(FocusManager); +}; + +} // namespace internal +} // namespace aura + +#endif // UI_AURA_FOCUS_MANAGER_H_ diff --git a/ui/aura/hit_test.h b/ui/aura/hit_test.h new file mode 100644 index 0000000..4ea50e8 --- /dev/null +++ b/ui/aura/hit_test.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 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_HIT_TEST_H_ +#define UI_AURA_HIT_TEST_H_ +#pragma once + +// Defines the same symbolic names used by the WM_NCHITTEST Notification under +// win32 (the integer values are not guaranteed to be equivalent). We do this +// because we have a whole bunch of code that deals with window resizing and +// such that requires these values. +enum HitTestCompat { + HTBORDER = 1, + HTBOTTOM, + HTBOTTOMLEFT, + HTBOTTOMRIGHT, + HTCAPTION, + HTCLIENT, + HTCLOSE, + HTERROR, + HTGROWBOX, + HTHELP, + HTHSCROLL, + HTLEFT, + HTMENU, + HTMAXBUTTON, + HTMINBUTTON, + HTNOWHERE, + HTREDUCE, + HTRIGHT, + HTSIZE, + HTSYSMENU, + HTTOP, + HTTOPLEFT, + HTTOPRIGHT, + HTTRANSPARENT, + HTVSCROLL, + HTZOOM +}; + +#endif // UI_AURA_HIT_TEST_H_ diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc new file mode 100644 index 0000000..1f39440 --- /dev/null +++ b/ui/aura/root_window.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2011 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/root_window.h" + +#include "base/logging.h" +#include "ui/aura/event.h" +#include "ui/aura/focus_manager.h" +#include "ui/aura/window_delegate.h" +#include "ui/base/events.h" + +namespace aura { +namespace internal { + +RootWindow::RootWindow() + : Window(NULL), + mouse_pressed_handler_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(focus_manager_(new FocusManager(this))) { +} + +RootWindow::~RootWindow() { +} + +bool RootWindow::HandleMouseEvent(const MouseEvent& event) { + Window* target = mouse_pressed_handler_; + if (!target) + target = GetEventHandlerForPoint(event.location()); + if (event.type() == ui::ET_MOUSE_PRESSED && !mouse_pressed_handler_) + mouse_pressed_handler_ = target; + if (event.type() == ui::ET_MOUSE_RELEASED) + mouse_pressed_handler_ = NULL; + if (target->delegate()) { + MouseEvent translated_event(event, this, target); + return target->OnMouseEvent(&translated_event); + } + return false; +} + +bool RootWindow::HandleKeyEvent(const KeyEvent& event) { + Window* focused_window = GetFocusManager()->focused_window(); + if (focused_window) { + KeyEvent translated_event(event); + return GetFocusManager()->focused_window()->OnKeyEvent(&translated_event); + } + return false; +} + +bool RootWindow::IsTopLevelWindowContainer() const { + return true; +} + +FocusManager* RootWindow::GetFocusManager() { + return focus_manager_.get(); +} + +} // namespace internal +} // namespace aura diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h new file mode 100644 index 0000000..a985ab2 --- /dev/null +++ b/ui/aura/root_window.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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_ROOT_WINDOW_H_ +#define UI_AURA_ROOT_WINDOW_H_ +#pragma once + +#include "ui/aura/window.h" + +namespace aura { +namespace internal { + +class FocusManager; + +// A Window subclass that handles event targeting for certain types of +// MouseEvent. +class RootWindow : public Window { + public: + RootWindow(); + virtual ~RootWindow(); + + // Handles a mouse event. Returns true if handled. + bool HandleMouseEvent(const MouseEvent& event); + + // Handles a key event. Returns true if handled. + bool HandleKeyEvent(const KeyEvent& event); + + // Overridden from Window: + virtual bool IsTopLevelWindowContainer() const OVERRIDE; + virtual FocusManager* GetFocusManager() OVERRIDE; + + private: + Window* mouse_pressed_handler_; + scoped_ptr<FocusManager> focus_manager_; + + DISALLOW_COPY_AND_ASSIGN(RootWindow); +}; + +} // namespace internal +} // namespace aura + +#endif // UI_AURA_ROOT_WINDOW_H_ diff --git a/ui/aura/run_all_unittests.cc b/ui/aura/run_all_unittests.cc new file mode 100644 index 0000000..39d6771c --- /dev/null +++ b/ui/aura/run_all_unittests.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2011 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/test_suite.h" + +int main(int argc, char** argv) { + return AuraTestSuite(argc, argv).Run(); +} diff --git a/ui/aura/test_suite.cc b/ui/aura/test_suite.cc new file mode 100644 index 0000000..8d8c68c --- /dev/null +++ b/ui/aura/test_suite.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2011 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/test_suite.h" + +#include "base/file_path.h" +#include "base/path_service.h" +#include "build/build_config.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_paths.h" +#include "ui/gfx/gfx_paths.h" + +AuraTestSuite::AuraTestSuite(int argc, char** argv) + : TestSuite(argc, argv) {} + +void AuraTestSuite::Initialize() { + base::TestSuite::Initialize(); + + gfx::RegisterPathProvider(); + ui::RegisterPathProvider(); + + // Force unittests to run using en-US so if we test against string + // output, it'll pass regardless of the system language. + ui::ResourceBundle::InitSharedInstance("en-US"); +} + +void AuraTestSuite::Shutdown() { + ui::ResourceBundle::CleanupSharedInstance(); + + base::TestSuite::Shutdown(); +} diff --git a/ui/aura/test_suite.h b/ui/aura/test_suite.h new file mode 100644 index 0000000..37bb9c5 --- /dev/null +++ b/ui/aura/test_suite.h @@ -0,0 +1,22 @@ +// Copyright (c) 2011 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_TEST_SUITE_H_ +#define UI_AURA_TEST_SUITE_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/test/test_suite.h" + +class AuraTestSuite : public base::TestSuite { + public: + AuraTestSuite(int argc, char** argv); + + protected: + // base::TestSuite: + virtual void Initialize() OVERRIDE; + virtual void Shutdown() OVERRIDE; +}; + +#endif // UI_AURA_TEST_SUITE_H_ diff --git a/ui/aura/window.cc b/ui/aura/window.cc new file mode 100644 index 0000000..561d605 --- /dev/null +++ b/ui/aura/window.cc @@ -0,0 +1,175 @@ +// Copyright (c) 2011 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/window.h" + +#include <algorithm> + +#include "base/logging.h" +#include "ui/aura/desktop.h" +#include "ui/aura/event.h" +#include "ui/aura/window_delegate.h" +#include "ui/aura/window_manager.h" +#include "ui/gfx/canvas_skia.h" +#include "ui/gfx/compositor/compositor.h" +#include "ui/gfx/compositor/layer.h" + +namespace aura { + +Window::Window(WindowDelegate* delegate) + : delegate_(delegate), + visibility_(VISIBILITY_HIDDEN), + parent_(NULL), + id_(-1), + user_data_(NULL) { +} + +Window::~Window() { + // Let the delegate know we're in the processing of destroying. + if (delegate_) + delegate_->OnWindowDestroying(); + // Then destroy the children. + while (!children_.empty()) { + Window* child = children_[0]; + delete child; + // Deleting the child so remove it from out children_ list. + DCHECK(std::find(children_.begin(), children_.end(), child) == + children_.end()); + } + // And let the delegate do any post cleanup. + if (delegate_) + delegate_->OnWindowDestroyed(); + if (parent_) + parent_->RemoveChild(this); +} + +void Window::Init() { + layer_.reset(new ui::Layer(Desktop::GetInstance()->compositor())); + layer_->set_delegate(this); +} + +void Window::SetVisibility(Visibility visibility) { + if (visibility_ == visibility) + return; + + visibility_ = visibility; + layer_->set_visible(visibility_ != VISIBILITY_HIDDEN); + if (layer_->visible()) + SchedulePaint(); +} + +void Window::SetBounds(const gfx::Rect& bounds, int anim_ms) { + // TODO: support anim_ms + // TODO: funnel this through the Desktop. + bool was_move = bounds_.size() == bounds.size(); + bounds_ = bounds; + layer_->SetBounds(bounds); + if (was_move) + SchedulePaintInRect(gfx::Rect()); + else + SchedulePaint(); +} + +void Window::SchedulePaintInRect(const gfx::Rect& rect) { + layer_->SchedulePaint(rect); +} + +void Window::SetCanvas(const SkCanvas& canvas, const gfx::Point& origin) { + // TODO: figure out how this is going to work when animating the layer. In + // particular if we're animating the size then the underlying Texture is going + // to be unhappy if we try to set a texture on a size bigger than the size of + // the texture. + layer_->SetCanvas(canvas, origin); +} + +void Window::SetParent(Window* parent) { + if (parent) + parent->AddChild(this); + else + Desktop::GetInstance()->window()->AddChild(this); +} + +bool Window::IsTopLevelWindowContainer() const { + return false; +} + +void Window::MoveChildToFront(Window* child) { + DCHECK_EQ(child->parent(), this); + const Windows::iterator i(std::find(children_.begin(), children_.end(), + child)); + DCHECK(i != children_.end()); + children_.erase(i); + + // TODO(beng): this obviously has to handle different window types. + children_.insert(children_.begin() + children_.size(), child); + SchedulePaintInRect(gfx::Rect()); +} + +void Window::AddChild(Window* child) { + DCHECK(std::find(children_.begin(), children_.end(), child) == + children_.end()); + child->parent_ = this; + layer_->Add(child->layer_.get()); + children_.push_back(child); +} + +void Window::RemoveChild(Window* child) { + Windows::iterator i = std::find(children_.begin(), children_.end(), child); + DCHECK(i != children_.end()); + child->parent_ = NULL; + layer_->Remove(child->layer_.get()); + children_.erase(i); +} + +// static +void Window::ConvertPointToWindow(Window* source, + Window* target, + gfx::Point* point) { + ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); +} + +bool Window::OnMouseEvent(MouseEvent* event) { + if (!window_manager_.get()) + window_manager_.reset(new WindowManager(this)); + return window_manager_->OnMouseEvent(event) || delegate_->OnMouseEvent(event); +} + +bool Window::OnKeyEvent(KeyEvent* event) { + return delegate_->OnKeyEvent(event); +} + +bool Window::HitTest(const gfx::Point& point) { + gfx::Rect local_bounds(gfx::Point(), bounds().size()); + // TODO(beng): hittest masks. + return local_bounds.Contains(point); +} + +Window* Window::GetEventHandlerForPoint(const gfx::Point& point) { + Windows::const_reverse_iterator i = children_.rbegin(); + for (; i != children_.rend(); ++i) { + Window* child = *i; + if (child->visibility() == Window::VISIBILITY_HIDDEN) + continue; + gfx::Point point_in_child_coords(point); + Window::ConvertPointToWindow(this, child, &point_in_child_coords); + if (child->HitTest(point_in_child_coords)) + return child->GetEventHandlerForPoint(point_in_child_coords); + } + return this; +} + +internal::FocusManager* Window::GetFocusManager() { + return parent_ ? parent_->GetFocusManager() : NULL; +} + +void Window::SchedulePaint() { + SchedulePaintInRect(gfx::Rect(0, 0, bounds_.width(), bounds_.height())); +} + +void Window::OnPaintLayer(gfx::Canvas* canvas) { + if (delegate_) + delegate_->OnPaint(canvas); +} + +} // namespace aura diff --git a/ui/aura/window.h b/ui/aura/window.h new file mode 100644 index 0000000..de4189f --- /dev/null +++ b/ui/aura/window.h @@ -0,0 +1,166 @@ +// Copyright (c) 2011 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_WINDOW_H_ +#define UI_AURA_WINDOW_H_ +#pragma once + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/aura_export.h" +#include "ui/gfx/compositor/layer_delegate.h" +#include "ui/gfx/rect.h" + +class SkCanvas; + +namespace ui { +class Compositor; +class Layer; +} + +namespace aura { + +class Desktop; +class KeyEvent; +class MouseEvent; +class WindowDelegate; +class WindowManager; + +namespace internal { +class FocusManager; +} + +// Aura window implementation. Interesting events are sent to the +// WindowDelegate. +// TODO(beng): resolve ownership. +class AURA_EXPORT Window : public ui::LayerDelegate { + public: + enum Visibility { + // Don't display the window onscreen and don't let it receive mouse + // events. This is the default. + VISIBILITY_HIDDEN = 1, + + // Display the window and let it receive mouse events. + VISIBILITY_SHOWN = 2, + + // Display the window but prevent it from receiving mouse events. + VISIBILITY_SHOWN_NO_INPUT = 3, + }; + + explicit Window(WindowDelegate* delegate); + ~Window(); + + void Init(); + + int id() const { return id_; } + void set_id(int id) { id_ = id; } + + ui::Layer* layer() { return layer_.get(); } + const ui::Layer* layer() const { return layer_.get(); } + + // Changes the visibility of the window. + void SetVisibility(Visibility visibility); + Visibility visibility() const { return visibility_; } + + // Changes the bounds of the window. + void SetBounds(const gfx::Rect& bounds, int anim_ms); + const gfx::Rect& bounds() const { return bounds_; } + + // Marks the a portion of window as needing to be painted. + void SchedulePaintInRect(const gfx::Rect& rect); + + // Sets the contents of the window. + void SetCanvas(const SkCanvas& canvas, const gfx::Point& origin); + + // Sets the parent window of the window. If NULL, the window is parented to + // the desktop's window. + void SetParent(Window* parent); + Window* parent() { return parent_; } + + // Returns true if this Window is the container for toplevel windows. + virtual bool IsTopLevelWindowContainer() const; + + // Move the specified child of this Window to the front of the z-order. + // TODO(beng): this is (obviously) feeble. + void MoveChildToFront(Window* child); + + // Tree operations. + // TODO(beng): Child windows are currently not owned by the hierarchy. We + // should change this. + void AddChild(Window* child); + void RemoveChild(Window* child); + + static void ConvertPointToWindow(Window* source, + Window* target, + gfx::Point* point); + + // Handles a mouse event. Returns true if handled. + bool OnMouseEvent(MouseEvent* event); + + // Handles a key event. Returns true if handled. + bool OnKeyEvent(KeyEvent* event); + + WindowDelegate* delegate() { return delegate_; } + + // Returns true if the mouse pointer at the specified |point| can trigger an + // event for this Window. + // TODO(beng): + // A Window can supply a hit-test mask to cause some portions of itself to not + // trigger events, causing the events to fall through to the Window behind. + bool HitTest(const gfx::Point& point); + + // Returns the Window that most closely encloses |point| for the purposes of + // event targeting. + Window* GetEventHandlerForPoint(const gfx::Point& point); + + // Returns the FocusManager for the Window, which may be attached to a parent + // Window. Can return NULL if the Window has no FocusManager. + virtual internal::FocusManager* GetFocusManager(); + + // The Window does not own this object. + void set_user_data(void* user_data) { user_data_ = user_data; } + void* user_data() const { return user_data_; } + + private: + typedef std::vector<Window*> Windows; + + // If SchedulePaint has been invoked on the Window the delegate is notified. + void UpdateLayerCanvas(); + + // Schedules a paint for the Window's entire bounds. + void SchedulePaint(); + + // Overridden from ui::LayerDelegate: + virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE; + + WindowDelegate* delegate_; + + Visibility visibility_; + + scoped_ptr<ui::Layer> layer_; + + // Bounds of the window in the desktop's coordinate system. + gfx::Rect bounds_; + + // The Window's parent. + // TODO(beng): Implement NULL-ness for toplevels. + Window* parent_; + + // Child windows. Topmost is last. + Windows children_; + + int id_; + + scoped_ptr<WindowManager> window_manager_; + + void* user_data_; + + DISALLOW_COPY_AND_ASSIGN(Window); +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_H_ diff --git a/ui/aura/window_delegate.h b/ui/aura/window_delegate.h new file mode 100644 index 0000000..b7b02e0 --- /dev/null +++ b/ui/aura/window_delegate.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011 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_WINDOW_DELEGATE_H_ +#define UI_AURA_WINDOW_DELEGATE_H_ +#pragma once + +namespace gfx { +class Canvas; +class Point; +} + +namespace aura { + +class KeyEvent; +class MouseEvent; + +// Delegate interface for aura::Window. +class WindowDelegate { + public: + // Sent to the Window's delegate when the Window gains or loses focus. + virtual void OnFocus() = 0; + virtual void OnBlur() = 0; + + virtual bool OnKeyEvent(KeyEvent* event) = 0; + + // Returns the non-client component (see hit_test.h) containing |point|, in + // window coordinates. + virtual int GetNonClientComponent(const gfx::Point& point) const = 0; + + virtual bool OnMouseEvent(MouseEvent* event) = 0; + + // Asks the delegate to paint window contents into the supplied canvas. + virtual void OnPaint(gfx::Canvas* canvas) = 0; + + // Called from Window's destructor before OnWindowDestroyed and before the + // children have been destroyed. + virtual void OnWindowDestroying() = 0; + + // Called when the Window has been destroyed (i.e. from its destructor). This + // is called after OnWindowDestroying and after the children have been + // deleted. + // The delegate can use this as an opportunity to delete itself if necessary. + virtual void OnWindowDestroyed() = 0; + + protected: + virtual ~WindowDelegate() {} +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_DELEGATE_H_ diff --git a/ui/aura/window_manager.cc b/ui/aura/window_manager.cc new file mode 100644 index 0000000..3f5905c --- /dev/null +++ b/ui/aura/window_manager.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 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/window_manager.h" + +#include "ui/aura/event.h" +#include "ui/aura/focus_manager.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" + +#if !defined(OS_WIN) +#include "ui/aura/hit_test.h" +#endif + +namespace aura { + +WindowManager::WindowManager(Window* owner) + : owner_(owner), + window_component_(HTNOWHERE) { +} + +WindowManager::~WindowManager() { +} + +bool WindowManager::OnMouseEvent(MouseEvent* event) { + switch (event->type()) { + case ui::ET_MOUSE_PRESSED: + // TODO(beng): some windows (e.g. disabled ones, tooltips, etc) may not be + // focusable. + owner_->GetFocusManager()->SetFocusedWindow(owner_); + window_component_ = + owner_->delegate()->GetNonClientComponent(event->location()); + MoveWindowToFront(); + mouse_down_offset_ = event->location(); + window_location_ = owner_->bounds().origin(); + break; + case ui::ET_MOUSE_DRAGGED: + if (window_component_ == HTCAPTION) { + gfx::Point new_origin(event->location()); + new_origin.Offset(-mouse_down_offset_.x(), -mouse_down_offset_.y()); + new_origin.Offset(owner_->bounds().x(), owner_->bounds().y()); + owner_->SetBounds(gfx::Rect(new_origin, owner_->bounds().size()), 0); + return true; + } + break; + case ui::ET_MOUSE_RELEASED: + window_component_ = HTNOWHERE; + break; + default: + break; + } + return false; +} + +void WindowManager::MoveWindowToFront() { + Window* parent = owner_->parent(); + Window* child = owner_; + while (parent) { + parent->MoveChildToFront(child); + parent = parent->parent(); + child = child->parent(); + } +} + +} // namespace aura diff --git a/ui/aura/window_manager.h b/ui/aura/window_manager.h new file mode 100644 index 0000000..af7563d --- /dev/null +++ b/ui/aura/window_manager.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 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_WINDOW_MANAGER_H_ +#define UI_AURA_WINDOW_MANAGER_H_ +#pragma once + +#include "base/logging.h" +#include "ui/gfx/point.h" + +namespace aura { + +class Window; +class MouseEvent; + +// An object that filters events sent to an owner window, potentially performing +// adjustments to the window's position, size and z-index. +// +// TODO(beng): Make this into an interface so we can have specializations for +// different types of Window and product. +class WindowManager { + public: + explicit WindowManager(Window* owner); + ~WindowManager(); + + // Try to handle |event| (before the owner's delegate gets a chance to). + // Returns true if the event was handled by the WindowManager and should not + // be forwarded to the owner's delegate. + bool OnMouseEvent(MouseEvent* event); + + private: + // Moves the owner window and all of its parents to the front of their + // respective z-orders. + void MoveWindowToFront(); + + Window* owner_; + gfx::Point mouse_down_offset_; + gfx::Point window_location_; + int window_component_; + + DISALLOW_COPY_AND_ASSIGN(WindowManager); +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_MANAGER_H_ diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc new file mode 100644 index 0000000..9e836c0 --- /dev/null +++ b/ui/aura/window_unittest.cc @@ -0,0 +1,281 @@ +// Copyright (c) 2011 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 "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/desktop.h" +#include "ui/aura/event.h" +#include "ui/aura/focus_manager.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window_delegate.h" +#include "ui/gfx/canvas_skia.h" +#include "ui/base/keycodes/keyboard_codes.h" + +#if !defined(OS_WIN) +#include "aura/hit_test.h" +#endif + +namespace aura { +namespace internal { + +namespace { + +// WindowDelegate implementation with all methods stubbed out. +class WindowDelegateImpl : public WindowDelegate { + public: + WindowDelegateImpl() {} + virtual ~WindowDelegateImpl() {} + + // Overriden from WindowDelegate: + virtual void OnFocus() OVERRIDE {} + virtual void OnBlur() OVERRIDE {} + virtual bool OnKeyEvent(KeyEvent* event) OVERRIDE { + return false; + } + virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE { + return HTCLIENT; + } + virtual bool OnMouseEvent(MouseEvent* event) OVERRIDE { return false; } + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {} + virtual void OnWindowDestroying() OVERRIDE {} + virtual void OnWindowDestroyed() OVERRIDE {} + + private: + DISALLOW_COPY_AND_ASSIGN(WindowDelegateImpl); +}; + +// Used for verifying destruction methods are invoked. +class DestroyTrackingDelegateImpl : public WindowDelegateImpl { + public: + DestroyTrackingDelegateImpl() + : destroying_count_(0), + destroyed_count_(0), + in_destroying_(false) {} + + void clear_destroying_count() { destroying_count_ = 0; } + int destroying_count() const { return destroying_count_; } + + void clear_destroyed_count() { destroyed_count_ = 0; } + int destroyed_count() const { return destroyed_count_; } + + bool in_destroying() const { return in_destroying_; } + + virtual void OnWindowDestroying() OVERRIDE { + EXPECT_FALSE(in_destroying_); + in_destroying_ = true; + destroying_count_++; + } + + virtual void OnWindowDestroyed() OVERRIDE { + EXPECT_TRUE(in_destroying_); + in_destroying_ = false; + destroyed_count_++; + } + + private: + bool in_destroying_; + int destroying_count_; + int destroyed_count_; + + DISALLOW_COPY_AND_ASSIGN(DestroyTrackingDelegateImpl); +}; + +// Used to verify that when OnWindowDestroying is invoked the parent is also +// is in the process of being destroyed. +class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl { + public: + explicit ChildWindowDelegateImpl( + DestroyTrackingDelegateImpl* parent_delegate) + : parent_delegate_(parent_delegate) { + } + + virtual void OnWindowDestroying() OVERRIDE { + EXPECT_TRUE(parent_delegate_->in_destroying()); + DestroyTrackingDelegateImpl::OnWindowDestroying(); + } + + private: + DestroyTrackingDelegateImpl* parent_delegate_; + + DISALLOW_COPY_AND_ASSIGN(ChildWindowDelegateImpl); +}; + +// A simple WindowDelegate implementation for these tests. It owns itself +// (deletes itself when the Window it is attached to is destroyed). +class TestWindowDelegate : public WindowDelegateImpl { + public: + TestWindowDelegate(SkColor color) + : color_(color), + last_key_code_(ui::VKEY_UNKNOWN) { + } + virtual ~TestWindowDelegate() {} + + ui::KeyboardCode last_key_code() const { return last_key_code_; } + + // Overridden from WindowDelegateImpl: + virtual bool OnKeyEvent(KeyEvent* event) OVERRIDE { + last_key_code_ = event->key_code(); + return true; + } + virtual void OnWindowDestroyed() OVERRIDE { + delete this; + } + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + canvas->AsCanvasSkia()->drawColor(color_, SkXfermode::kSrc_Mode); + } + + private: + SkColor color_; + ui::KeyboardCode last_key_code_; + + DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate); +}; + +class WindowTest : public testing::Test { + public: + WindowTest() : main_message_loop(MessageLoop::TYPE_UI) { + aura::Desktop::GetInstance()->Show(); + aura::Desktop::GetInstance()->SetSize(gfx::Size(500, 500)); + } + virtual ~WindowTest() {} + + // Overridden from testing::Test: + virtual void SetUp() OVERRIDE { + } + + virtual void TearDown() OVERRIDE { + } + + Window* CreateTestWindow(SkColor color, + int id, + const gfx::Rect& bounds, + Window* parent) { + return CreateTestWindowWithDelegate(new TestWindowDelegate(color), + id, bounds, parent); + } + + Window* CreateTestWindowWithDelegate(WindowDelegate* delegate, + int id, + const gfx::Rect& bounds, + Window* parent) { + Window* window = new Window(delegate); + window->set_id(id); + window->Init(); + window->SetBounds(bounds, 0); + window->SetVisibility(Window::VISIBILITY_SHOWN); + window->SetParent(parent); + return window; + } + + void RunPendingMessages() { + MessageLoop message_loop(MessageLoop::TYPE_UI); + MessageLoopForUI::current()->Run(NULL); + } + + private: + MessageLoop main_message_loop; + + DISALLOW_COPY_AND_ASSIGN(WindowTest); +}; + +} // namespace + +TEST_F(WindowTest, HitTest) { + Window w1(new TestWindowDelegate(SK_ColorWHITE)); + w1.set_id(1); + w1.Init(); + w1.SetBounds(gfx::Rect(10, 10, 50, 50), 0); + w1.SetVisibility(Window::VISIBILITY_SHOWN); + w1.SetParent(NULL); + + // Points are in the Window's coordinates. + EXPECT_TRUE(w1.HitTest(gfx::Point(1, 1))); + EXPECT_FALSE(w1.HitTest(gfx::Point(-1, -1))); + + // TODO(beng): clip Window to parent. +} + +TEST_F(WindowTest, GetEventHandlerForPoint) { + scoped_ptr<Window> w1( + CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500), NULL)); + scoped_ptr<Window> w11( + CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(5, 5, 100, 100), w1.get())); + scoped_ptr<Window> w111( + CreateTestWindow(SK_ColorCYAN, 111, gfx::Rect(5, 5, 75, 75), w11.get())); + scoped_ptr<Window> w1111( + CreateTestWindow(SK_ColorRED, 1111, gfx::Rect(5, 5, 50, 50), w111.get())); + scoped_ptr<Window> w12( + CreateTestWindow(SK_ColorMAGENTA, 12, gfx::Rect(10, 420, 25, 25), + w1.get())); + scoped_ptr<Window> w121( + CreateTestWindow(SK_ColorYELLOW, 121, gfx::Rect(5, 5, 5, 5), w12.get())); + scoped_ptr<Window> w13( + CreateTestWindow(SK_ColorGRAY, 13, gfx::Rect(5, 470, 50, 50), w1.get())); + + Window* desktop = Desktop::GetInstance()->window(); + EXPECT_EQ(desktop, desktop->GetEventHandlerForPoint(gfx::Point(5, 5))); + EXPECT_EQ(w1.get(), desktop->GetEventHandlerForPoint(gfx::Point(11, 11))); + EXPECT_EQ(w11.get(), desktop->GetEventHandlerForPoint(gfx::Point(16, 16))); + EXPECT_EQ(w111.get(), desktop->GetEventHandlerForPoint(gfx::Point(21, 21))); + EXPECT_EQ(w1111.get(), desktop->GetEventHandlerForPoint(gfx::Point(26, 26))); + EXPECT_EQ(w12.get(), desktop->GetEventHandlerForPoint(gfx::Point(21, 431))); + EXPECT_EQ(w121.get(), desktop->GetEventHandlerForPoint(gfx::Point(26, 436))); + EXPECT_EQ(w13.get(), desktop->GetEventHandlerForPoint(gfx::Point(26, 481))); +} + +TEST_F(WindowTest, Focus) { + scoped_ptr<Window> w1( + CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500), NULL)); + scoped_ptr<Window> w11( + CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(5, 5, 100, 100), w1.get())); + scoped_ptr<Window> w111( + CreateTestWindow(SK_ColorCYAN, 111, gfx::Rect(5, 5, 75, 75), w11.get())); + scoped_ptr<Window> w1111( + CreateTestWindow(SK_ColorRED, 1111, gfx::Rect(5, 5, 50, 50), w111.get())); + scoped_ptr<Window> w12( + CreateTestWindow(SK_ColorMAGENTA, 12, gfx::Rect(10, 420, 25, 25), + w1.get())); + TestWindowDelegate* w121delegate = new TestWindowDelegate(SK_ColorYELLOW); + scoped_ptr<Window> w121( + CreateTestWindowWithDelegate(w121delegate, 121, gfx::Rect(5, 5, 5, 5), + w12.get())); + scoped_ptr<Window> w13( + CreateTestWindow(SK_ColorGRAY, 13, gfx::Rect(5, 470, 50, 50), w1.get())); + + // Click on a sub-window (w121) to focus it. + Desktop* desktop = Desktop::GetInstance(); + gfx::Point click_point = w121->bounds().CenterPoint(); + Window::ConvertPointToWindow(w121->parent(), desktop->window(), &click_point); + desktop->OnMouseEvent( + MouseEvent(ui::ET_MOUSE_PRESSED, click_point, ui::EF_LEFT_BUTTON_DOWN)); + internal::FocusManager* focus_manager = w121->GetFocusManager(); + EXPECT_EQ(w121.get(), focus_manager->focused_window()); + + // The key press should be sent to the focused sub-window. + desktop->OnKeyEvent(KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_E, 0)); + EXPECT_EQ(ui::VKEY_E, w121delegate->last_key_code()); +} + +// Various destruction assertions. +TEST_F(WindowTest, DestroyTest) { + DestroyTrackingDelegateImpl parent_delegate; + ChildWindowDelegateImpl child_delegate(&parent_delegate); + { + scoped_ptr<Window> parent( + CreateTestWindowWithDelegate(&parent_delegate, 0, gfx::Rect(), NULL)); + Window* child = CreateTestWindowWithDelegate(&child_delegate, 0, + gfx::Rect(), parent.get()); + } + // Both the parent and child should have been destroyed. + EXPECT_EQ(1, parent_delegate.destroying_count()); + EXPECT_EQ(1, parent_delegate.destroyed_count()); + EXPECT_EQ(1, child_delegate.destroying_count()); + EXPECT_EQ(1, child_delegate.destroyed_count()); +} + +} // namespace internal +} // namespace aura + |