summaryrefslogtreecommitdiffstats
path: root/ui/aura
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-14 21:14:01 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-14 21:14:01 +0000
commitf94f0f14dd3c9c49c6da8bdf3d7de19f4a6fb6b7 (patch)
tree17f77aa9323a3e1de24b6603e385301eab13d8c3 /ui/aura
parente49d616f0151b407d6b9296167facdc0655811c5 (diff)
downloadchromium_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/DEPS6
-rw-r--r--ui/aura/OWNERS2
-rw-r--r--ui/aura/aura.gyp98
-rw-r--r--ui/aura/aura_export.h29
-rw-r--r--ui/aura/demo/demo_main.cc109
-rw-r--r--ui/aura/desktop.cc85
-rw-r--r--ui/aura/desktop.h80
-rw-r--r--ui/aura/desktop_host.h47
-rw-r--r--ui/aura/desktop_host_linux.cc122
-rw-r--r--ui/aura/desktop_host_win.cc96
-rw-r--r--ui/aura/desktop_host_win.h60
-rw-r--r--ui/aura/event.cc66
-rw-r--r--ui/aura/event.h111
-rw-r--r--ui/aura/event_win.cc222
-rw-r--r--ui/aura/event_x.cc193
-rw-r--r--ui/aura/focus_manager.cc32
-rw-r--r--ui/aura/focus_manager.h37
-rw-r--r--ui/aura/hit_test.h42
-rw-r--r--ui/aura/root_window.cc58
-rw-r--r--ui/aura/root_window.h43
-rw-r--r--ui/aura/run_all_unittests.cc9
-rw-r--r--ui/aura/test_suite.cc32
-rw-r--r--ui/aura/test_suite.h22
-rw-r--r--ui/aura/window.cc175
-rw-r--r--ui/aura/window.h166
-rw-r--r--ui/aura/window_delegate.h53
-rw-r--r--ui/aura/window_manager.cc66
-rw-r--r--ui/aura/window_manager.h47
-rw-r--r--ui/aura/window_unittest.cc281
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
+